Repository: rust-analyzer/rust-analyzer
Pull request #11538 (2022-02-23 15:03:56)

feat: Make private editable completions configurable, disable by default
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/10253
Fixes https://github.com/rust-analyzer/rust-analyzer/issues/9885

This does disable these completions by default, as it seems that people find this behaviour surprising(due to other IDEs usually not doing this).


Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 54f35cf0a6..f41e7ee4c4 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2440,7 +2440,7 @@ impl Impl {
 
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct Type {
-    krate: CrateId, // FIXME this is probably redundant with the TraitEnvironment
+    krate: CrateId,
     env: Arc<TraitEnvironment>,
     ty: Ty,
 }
@@ -2507,10 +2507,6 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
-    pub fn is_slice(&self) -> bool {
-        matches!(self.ty.kind(Interner), TyKind::Slice(..))
-    }
-
     pub fn is_usize(&self) -> bool {
         matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
     }
@@ -2533,9 +2529,12 @@ impl Type {
     /// Checks that particular type `ty` implements `std::future::Future`.
     /// This function is used in `.await` syntax completion.
     pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
-        let std_future_trait = db
-            .lang_item(self.krate, SmolStr::new_inline("future_trait"))
-            .and_then(|it| it.as_trait());
+        // No special case for the type of async block, since Chalk can figure it out.
+
+        let krate = self.krate;
+
+        let std_future_trait =
+            db.lang_item(krate, SmolStr::new_inline("future_trait")).and_then(|it| it.as_trait());
         let std_future_trait = match std_future_trait {
             Some(it) => it,
             None => return false,
@@ -2543,7 +2542,13 @@ impl Type {
 
         let canonical_ty =
             Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
-        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
+        method_resolution::implements_trait(
+            &canonical_ty,
+            db,
+            self.env.clone(),
+            krate,
+            std_future_trait,
+        )
     }
 
     /// Checks that particular type `ty` implements `std::ops::FnOnce`.
@@ -2551,7 +2556,9 @@ impl Type {
     /// This function can be used to check if a particular type is callable, since FnOnce is a
     /// supertrait of Fn and FnMut, so all callable types implements at least FnOnce.
     pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
-        let fnonce_trait = match FnTrait::FnOnce.get_id(db, self.krate) {
+        let krate = self.krate;
+
+        let fnonce_trait = match FnTrait::FnOnce.get_id(db, krate) {
             Some(it) => it,
             None => return false,
         };
@@ -2562,6 +2569,7 @@ impl Type {
             &canonical_ty,
             db,
             self.env.clone(),
+            krate,
             fnonce_trait,
         )
     }
@@ -2732,8 +2740,9 @@ impl Type {
     pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Ty> + 'a {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
-        let environment = self.env.clone();
-        autoderef(db, environment, canonical).map(|canonical| canonical.value)
+        let environment = self.env.env.clone();
+        let ty = InEnvironment { goal: canonical, environment };
+        autoderef(db, Some(self.krate), ty).map(|canonical| canonical.value)
     }
 
     // This would be nicer if it just returned an iterator, but that runs into
@@ -2788,26 +2797,24 @@ impl Type {
     pub fn iterate_method_candidates<T>(
         &self,
         db: &dyn HirDatabase,
-        scope: &SemanticsScope,
-        // FIXME this can be retrieved from `scope`, except autoimport uses this
-        // to specify a different set, so the method needs to be split
+        krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
         name: Option<&Name>,
-        mut callback: impl FnMut(Function) -> Option<T>,
+        mut callback: impl FnMut(Type, Function) -> Option<T>,
     ) -> Option<T> {
         let _p = profile::span("iterate_method_candidates");
         let mut slot = None;
 
         self.iterate_method_candidates_dyn(
             db,
-            scope,
+            krate,
             traits_in_scope,
             with_local_impls,
             name,
-            &mut |assoc_item_id| {
+            &mut |ty, assoc_item_id| {
                 if let AssocItemId::FunctionId(func) = assoc_item_id {
-                    if let Some(res) = callback(func.into()) {
+                    if let Some(res) = callback(self.derived(ty.clone()), func.into()) {
                         slot = Some(res);
                         return ControlFlow::Break(());
                     }
@@ -2821,55 +2828,50 @@ impl Type {
     fn iterate_method_candidates_dyn(
         &self,
         db: &dyn HirDatabase,
-        scope: &SemanticsScope,
+        krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
         name: Option<&Name>,
-        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
+        callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
     ) {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
-        let krate = match scope.krate() {
-            Some(k) => k,
-            None => return,
-        };
-        let environment = scope.resolver().generic_def().map_or_else(
-            || Arc::new(TraitEnvironment::empty(krate.id)),
-            |d| db.trait_environment(d),
-        );
+        let env = self.env.clone();
+        let krate = krate.id;
 
         method_resolution::iterate_method_candidates_dyn(
             &canonical,
             db,
-            environment,
+            env,
+            krate,
             traits_in_scope,
             with_local_impls.and_then(|b| b.id.containing_block()).into(),
             name,
             method_resolution::LookupMode::MethodCall,
-            &mut |_adj, id| callback(id),
+            &mut |ty, id| callback(&ty.value, id),
         );
     }
 
     pub fn iterate_path_candidates<T>(
         &self,
         db: &dyn HirDatabase,
-        scope: &SemanticsScope,
+        krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
         name: Option<&Name>,
-        mut callback: impl FnMut(AssocItem) -> Option<T>,
+        mut callback: impl FnMut(Type, AssocItem) -> Option<T>,
     ) -> Option<T> {
         let _p = profile::span("iterate_path_candidates");
         let mut slot = None;
         self.iterate_path_candidates_dyn(
             db,
-            scope,
+            krate,
             traits_in_scope,
             with_local_impls,
             name,
-            &mut |assoc_item_id| {
-                if let Some(res) = callback(assoc_item_id.into()) {
+            &mut |ty, assoc_item_id| {
+                if let Some(res) = callback(self.derived(ty.clone()), assoc_item_id.into()) {
                     slot = Some(res);
                     return ControlFlow::Break(());
                 }
@@ -2882,31 +2884,27 @@ impl Type {
     fn iterate_path_candidates_dyn(
         &self,
         db: &dyn HirDatabase,
-        scope: &SemanticsScope,
+        krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
         with_local_impls: Option<Module>,
         name: Option<&Name>,
-        callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
+        callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
     ) {
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
-        let krate = match scope.krate() {
-            Some(k) => k,
-            None => return,
-        };
-        let environment = scope.resolver().generic_def().map_or_else(
-            || Arc::new(TraitEnvironment::empty(krate.id)),
-            |d| db.trait_environment(d),
-        );
+        let env = self.env.clone();
+        let krate = krate.id;
 
-        method_resolution::iterate_path_candidates(
+        method_resolution::iterate_method_candidates_dyn(
             &canonical,
             db,
-            environment,
+            env,
+            krate,
             traits_in_scope,
             with_local_impls.and_then(|b| b.id.containing_block()).into(),
             name,
-            &mut |id| callback(id),
+            method_resolution::LookupMode::Path,
+            &mut |ty, id| callback(&ty.value, id),
         );
     }
 
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2e0dbf82b7..20c360e302 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -1230,10 +1230,6 @@ impl<'a> SemanticsScope<'a> {
         Some(Crate { id: self.resolver.krate()? })
     }
 
-    pub(crate) fn resolver(&self) -> &Resolver {
-        &self.resolver
-    }
-
     /// Note: `FxHashSet<TraitId>` should be treated as an opaque type, passed into `Type
     pub fn visible_traits(&self) -> FxHashSet<TraitId> {
         let resolver = &self.resolver;
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 9176c90ae9..41e4bf8e8b 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1701,9 +1701,8 @@ impl ModCollector<'_, '_> {
                 {
                     Ok((file_id, is_mod_rs, mod_dir)) => {
                         let item_tree = db.file_item_tree(file_id.into());
-                        let krate = self.def_collector.def_map.krate;
                         let is_enabled = item_tree
-                            .top_level_attrs(db, krate)
+                            .top_level_attrs(db, self.def_collector.def_map.krate)
                             .cfg()
                             .map_or(true, |cfg| self.is_cfg_enabled(&cfg));
                         if is_enabled {
@@ -1714,7 +1713,7 @@ impl ModCollector<'_, '_> {
                                 &self.item_tree[module.visibility],
                             );
                             ModCollector {
-                                def_collector: self.def_collector,
+                                def_collector: &mut *self.def_collector,
                                 macro_depth: self.macro_depth,
                                 module_id,
                                 tree_id: TreeId::new(file_id.into(), None),
@@ -1724,7 +1723,7 @@ impl ModCollector<'_, '_> {
                             .collect_in_top_module(item_tree.top_level_items());
                             let is_macro_use = is_macro_use
                                 || item_tree
-                                    .top_level_attrs(db, krate)
+                                    .top_level_attrs(db, self.def_collector.def_map.krate)
                                     .by_key("macro_use")
                                     .exists();
                             if is_macro_use {
@@ -1749,11 +1748,12 @@ impl ModCollector<'_, '_> {
         definition: Option<(FileId, bool)>,
         visibility: &crate::visibility::RawVisibility,
     ) -> LocalModuleId {
-        let def_map = &mut self.def_collector.def_map;
-        let vis = def_map
+        let vis = self
+            .def_collector
+            .def_map
             .resolve_visibility(self.def_collector.db, self.module_id, visibility)
             .unwrap_or(Visibility::Public);
-        let modules = &mut def_map.modules;
+        let modules = &mut self.def_collector.def_map.modules;
         let origin = match definition {
             None => ModuleOrigin::Inline { definition: declaration },
             Some((definition, is_mod_rs)) => {
@@ -1768,10 +1768,10 @@ impl ModCollector<'_, '_> {
         }
         modules[self.module_id].children.insert(name.clone(), res);
 
-        let module = def_map.module_id(res);
+        let module = self.def_collector.def_map.module_id(res);
         let def = ModuleDefId::from(module);
 
-        def_map.modules[self.module_id].scope.declare(def);
+        self.def_collector.def_map.modules[self.module_id].scope.declare(def);
         self.def_collector.update(
             self.module_id,
             &[(Some(name), PerNs::from_def(def, vis, false))],
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index f76034a3e2..80009010c5 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -1,6 +1,6 @@
 //! Defines hir-level representation of visibility (e.g. `pub` and `pub(crate)`).
 
-use std::{iter, sync::Arc};
+use std::sync::Arc;
 
 use hir_expand::{hygiene::Hygiene, InFile};
 use la_arena::ArenaMap;
@@ -25,7 +25,7 @@ pub enum RawVisibility {
 }
 
 impl RawVisibility {
-    pub(crate) const fn private() -> RawVisibility {
+    pub(crate) fn private() -> RawVisibility {
         RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
     }
 
@@ -113,7 +113,10 @@ impl Visibility {
     }
 
     pub(crate) fn is_visible_from_other_crate(self) -> bool {
-        matches!(self, Visibility::Public)
+        match self {
+            Visibility::Module(_) => false,
+            Visibility::Public => true,
+        }
     }
 
     pub(crate) fn is_visible_from_def_map(
@@ -142,7 +145,10 @@ impl Visibility {
                 arc = to_module.def_map(db);
                 &arc
             };
-        let is_block_root = matches!(to_module.block, Some(_) if to_module_def_map[to_module.local_id].parent.is_none());
+        let is_block_root = match to_module.block {
+            Some(_) => to_module_def_map[to_module.local_id].parent.is_none(),
+            None => false,
+        };
         if is_block_root {
             to_module = to_module_def_map.containing_module(to_module.local_id).unwrap();
         }
@@ -155,7 +161,9 @@ impl Visibility {
                 return true;
             }
             match def_map[from_module].parent {
-                Some(parent) => from_module = parent,
+                Some(parent) => {
+                    from_module = parent;
+                }
                 None => {
                     match def_map.parent() {
                         Some(module) => {
@@ -163,8 +171,10 @@ impl Visibility {
                             def_map = &*parent_arc;
                             from_module = module.local_id;
                         }
-                        // Reached the root module, nothing left to check.
-                        None => return false,
+                        None => {
+                            // Reached the root module, nothing left to check.
+                            return false;
+                        }
                     }
                 }
             }
@@ -184,12 +194,12 @@ impl Visibility {
                     return None;
                 }
 
-                let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| {
-                    let parent_id = def_map[m].parent?;
+                let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| {
+                    let parent_id = def_map[*m].parent?;
                     Some(parent_id)
                 });
-                let mut b_ancestors = iter::successors(Some(mod_b.local_id), |&m| {
-                    let parent_id = def_map[m].parent?;
+                let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| {
+                    let parent_id = def_map[*m].parent?;
                     Some(parent_id)
                 });
 
diff --git a/crates/hir_expand/src/builtin_fn_macro.rs b/crates/hir_expand/src/builtin_fn_macro.rs
index 17f0caca7a..5876be81b4 100644
--- a/crates/hir_expand/src/builtin_fn_macro.rs
+++ b/crates/hir_expand/src/builtin_fn_macro.rs
@@ -114,7 +114,6 @@ register_builtin! {
     (cfg, Cfg) => cfg_expand,
     (core_panic, CorePanic) => panic_expand,
     (std_panic, StdPanic) => panic_expand,
-    (unreachable, Unreachable) => unreachable_expand,
     (log_syntax, LogSyntax) => log_syntax_expand,
     (trace_macros, TraceMacros) => trace_macros_expand,
 
@@ -122,7 +121,6 @@ register_builtin! {
     (compile_error, CompileError) => compile_error_expand,
     (concat, Concat) => concat_expand,
     (concat_idents, ConcatIdents) => concat_idents_expand,
-    (concat_bytes, ConcatBytes) => concat_bytes_expand,
     (include, Include) => include_expand,
     (include_bytes, IncludeBytes) => include_bytes_expand,
     (include_str, IncludeStr) => include_str_expand,
@@ -355,37 +353,12 @@ fn panic_expand(
     ExpandResult::ok(call)
 }
 
-fn unreachable_expand(
-    db: &dyn AstDatabase,
-    id: MacroCallId,
-    tt: &tt::Subtree,
-) -> ExpandResult<tt::Subtree> {
-    let loc: MacroCallLoc = db.lookup_intern_macro_call(id);
-    // Expand to a macro call `$crate::panic::unreachable_{edition}`
-    let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
-    let mut call = if db.crate_graph()[loc.krate].edition == Edition::Edition2021 {
-        quote!(#krate::panic::unreachable_2021!)
-    } else {
-        quote!(#krate::panic::unreachable_2015!)
-    };
-
-    // Pass the original arguments
-    call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
-    ExpandResult::ok(call)
-}
-
 fn unquote_str(lit: &tt::Literal) -> Option<String> {
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::String::cast(lit)?;
     token.value().map(|it| it.into_owned())
 }
 
-fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
-    let lit = ast::make::tokens::literal(&lit.to_string());
-    let token = ast::ByteString::cast(lit)?;
-    token.value().map(|it| it.into_owned())
-}
-
 fn compile_error_expand(
     _db: &dyn AstDatabase,
     _id: MacroCallId,
@@ -449,74 +422,6 @@ fn concat_expand(
     ExpandResult { value: ExpandedEager::new(quote!(#text)), err }
 }
 
-fn concat_bytes_expand(
-    _db: &dyn AstDatabase,
-    _arg_id: MacroCallId,
-    tt: &tt::Subtree,
-) -> ExpandResult<ExpandedEager> {
-    let mut bytes = Vec::new();
-    let mut err = None;
-    for (i, t) in tt.token_trees.iter().enumerate() {
-        match t {
-            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
-                let token = ast::make::tokens::literal(&lit.to_string());
-                match token.kind() {
-                    syntax::SyntaxKind::BYTE => bytes.push(token.text().to_string()),
-                    syntax::SyntaxKind::BYTE_STRING => {
-                        let components = unquote_byte_string(lit).unwrap_or_else(|| Vec::new());
-                        components.into_iter().for_each(|x| bytes.push(x.to_string()));
-                    }
-                    _ => {
-                        err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
-                        break;
-                    }
-                }
-            }
-            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
-            tt::TokenTree::Subtree(tree)
-                if tree.delimiter_kind() == Some(tt::DelimiterKind::Bracket) =>
-            {
-                if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) {
-                    err.get_or_insert(e);
-                    break;
-                }
-            }
-            _ => {
-                err.get_or_insert(mbe::ExpandError::UnexpectedToken.into());
-                break;
-            }
-        }
-    }
-    let ident = tt::Ident { text: bytes.join(", ").into(), id: tt::TokenId::unspecified() };
-    ExpandResult { value: ExpandedEager::new(quote!([#ident])), err }
-}
-
-fn concat_bytes_expand_subtree(
-    tree: &tt::Subtree,
-    bytes: &mut Vec<String>,
-) -> Result<(), ExpandError> {
-    for (ti, tt) in tree.token_trees.iter().enumerate() {
-        match tt {
-            tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
-                let lit = ast::make::tokens::literal(&lit.to_string());
-                match lit.kind() {
-                    syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => {
-                        bytes.push(lit.text().to_string())
-                    }
-                    _ => {
-                        return Err(mbe::ExpandError::UnexpectedToken.into());
-                    }
-                }
-            }
-            tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if ti % 2 == 1 && punct.char == ',' => (),
-            _ => {
-                return Err(mbe::ExpandError::UnexpectedToken.into());
-            }
-        }
-    }
-    Ok(())
-}
-
 fn concat_idents_expand(
     _db: &dyn AstDatabase,
     _arg_id: MacroCallId,
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index f62c3ca0a0..c36bd09e2b 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -233,7 +233,6 @@ pub mod known {
         column,
         compile_error,
         concat_idents,
-        concat_bytes,
         concat,
         const_format_args,
         core_panic,
@@ -253,7 +252,6 @@ pub mod known {
         std_panic,
         stringify,
         trace_macros,
-        unreachable,
         // Builtin derives
         Copy,
         Clone,
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index dffb36b5de..6266554ecf 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -3,16 +3,20 @@
 //! reference to a type with the field `bar`. This is an approximation of the
 //! logic in rustc (which lives in librustc_typeck/check/autoderef.rs).
 
-use std::sync::Arc;
+use std::iter::successors;
 
-use chalk_ir::cast::Cast;
+use base_db::CrateId;
+use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
+use hir_def::lang_item::LangItemTarget;
 use hir_expand::name::name;
 use limit::Limit;
 use syntax::SmolStr;
+use tracing::{info, warn};
 
 use crate::{
-    db::HirDatabase, infer::unify::InferenceTable, Canonical, Goal, Interner, ProjectionTyExt,
-    TraitEnvironment, Ty, TyBuilder, TyKind,
+    db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
+    ConstrainedSubst, DebruijnIndex, Environment, Guidance, InEnvironment, Interner,
+    ProjectionTyExt, Solution, Substitution, Ty, TyBuilder, TyKind,
 };
 
 static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
@@ -22,34 +26,40 @@ pub(crate) enum AutoderefKind {
     Overloaded,
 }
 
-pub(crate) struct Autoderef<'a, 'db> {
-    pub(crate) table: &'a mut InferenceTable<'db>,
-    ty: Ty,
+pub(crate) struct Autoderef<'db> {
+    db: &'db dyn HirDatabase,
+    ty: Canonical<Ty>,
     at_start: bool,
+    krate: Option<CrateId>,
+    environment: Environment,
     steps: Vec<(AutoderefKind, Ty)>,
 }
 
-impl<'a, 'db> Autoderef<'a, 'db> {
-    pub(crate) fn new(table: &'a mut InferenceTable<'db>, ty: Ty) -> Self {
-        let ty = table.resolve_ty_shallow(&ty);
-        Autoderef { table, ty, at_start: true, steps: Vec::new() }
+impl<'db> Autoderef<'db> {
+    pub(crate) fn new(
+        db: &'db dyn HirDatabase,
+        krate: Option<CrateId>,
+        ty: InEnvironment<Canonical<Ty>>,
+    ) -> Self {
+        let InEnvironment { goal: ty, environment } = ty;
+        Autoderef { db, ty, at_start: true, environment, krate, steps: Vec::new() }
     }
 
     pub(crate) fn step_count(&self) -> usize {
         self.steps.len()
     }
 
-    pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
+    pub(crate) fn steps(&self) -> &[(AutoderefKind, chalk_ir::Ty<Interner>)] {
         &self.steps
     }
 
     pub(crate) fn final_ty(&self) -> Ty {
-        self.ty.clone()
+        self.ty.value.clone()
     }
 }
 
-impl Iterator for Autoderef<'_, '_> {
-    type Item = (Ty, usize);
+impl Iterator for Autoderef<'_> {
+    type Item = (Canonical<Ty>, usize);
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.at_start {
@@ -61,42 +71,54 @@ impl Iterator for Autoderef<'_, '_> {
             return None;
         }
 
-        let (kind, new_ty) = autoderef_step(self.table, self.ty.clone())?;
+        let (kind, new_ty) = if let Some(derefed) = builtin_deref(&self.ty.value) {
+            (
+                AutoderefKind::Builtin,
+                Canonical { value: derefed.clone(), binders: self.ty.binders.clone() },
+            )
+        } else {
+            (
+                AutoderefKind::Overloaded,
+                deref_by_trait(
+                    self.db,
+                    self.krate?,
+                    InEnvironment { goal: &self.ty, environment: self.environment.clone() },
+                )?,
+            )
+        };
 
-        self.steps.push((kind, self.ty.clone()));
+        self.steps.push((kind, self.ty.value.clone()));
         self.ty = new_ty;
 
         Some((self.ty.clone(), self.step_count()))
     }
 }
 
-pub(crate) fn autoderef_step(table: &mut InferenceTable, ty: Ty) -> Option<(AutoderefKind, Ty)> {
-    if let Some(derefed) = builtin_deref(&ty) {
-        Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
-    } else {
-        Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
-    }
-}
-
 // FIXME: replace uses of this with Autoderef above
 pub fn autoderef<'a>(
     db: &'a dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
-    ty: Canonical<Ty>,
+    krate: Option<CrateId>,
+    ty: InEnvironment<Canonical<Ty>>,
 ) -> impl Iterator<Item = Canonical<Ty>> + 'a {
-    let mut table = InferenceTable::new(db, env);
-    let ty = table.instantiate_canonical(ty);
-    let mut autoderef = Autoderef::new(&mut table, ty);
-    let mut v = Vec::new();
-    while let Some((ty, _steps)) = autoderef.next() {
-        v.push(autoderef.table.canonicalize(ty).value);
-    }
-    v.into_iter()
+    let InEnvironment { goal: ty, environment } = ty;
+    successors(Some(ty), move |ty| {
+        deref(db, krate?, InEnvironment { goal: ty, environment: environment.clone() })
+    })
+    .take(AUTODEREF_RECURSION_LIMIT.inner())
 }
 
-pub(crate) fn deref(table: &mut InferenceTable, ty: Ty) -> Option<Ty> {
+pub(crate) fn deref(
+    db: &dyn HirDatabase,
+    krate: CrateId,
+    ty: InEnvironment<&Canonical<Ty>>,
+) -> Option<Canonical<Ty>> {
     let _p = profile::span("deref");
-    autoderef_step(table, ty).map(|(_, ty)| ty)
+    match builtin_deref(&ty.goal.value) {
+        Some(derefed) => {
+            Some(Canonical { value: derefed.clone(), binders: ty.goal.binders.clone() })
+        }
+        None => deref_by_trait(db, krate, ty),
+    }
 }
 
 fn builtin_deref(ty: &Ty) -> Option<&Ty> {
@@ -107,12 +129,16 @@ fn builtin_deref(ty: &Ty) -> Option<&Ty> {
     }
 }
 
-fn deref_by_trait(table: &mut InferenceTable, ty: Ty) -> Option<Ty> {
-    let db = table.db;
+fn deref_by_trait(
+    db: &dyn HirDatabase,
+    krate: CrateId,
+    ty: InEnvironment<&Canonical<Ty>>,
+) -> Option<Canonical<Ty>> {
     let _p = profile::span("deref_by_trait");
-    let deref_trait = db
-        .lang_item(table.trait_env.krate, SmolStr::new_inline("deref"))
-        .and_then(|l| l.as_trait())?;
+    let deref_trait = match db.lang_item(krate, SmolStr::new_inline("deref"))? {
+        LangItemTarget::TraitId(it) => it,
+        _ => return None,
+    };
     let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
 
     let projection = {
@@ -122,16 +148,114 @@ fn deref_by_trait(table: &mut InferenceTable, ty: Ty) -> Option<Ty> {
             // namely Deref's Self type
             return None;
         }
-        b.push(ty).build()
+        b.push(ty.goal.value.clone()).build()
     };
 
+    // FIXME make the Canonical / bound var handling nicer
+
     // Check that the type implements Deref at all
     let trait_ref = projection.trait_ref(db);
-    let implements_goal: Goal = trait_ref.cast(Interner);
-    table.try_obligation(implements_goal.clone())?;
+    let implements_goal = Canonical {
+        binders: ty.goal.binders.clone(),
+        value: InEnvironment {
+            goal: trait_ref.cast(Interner),
+            environment: ty.environment.clone(),
+        },
+    };
+    if db.trait_solve(krate, implements_goal).is_none() {
+        return None;
+    }
 
-    table.register_obligation(implements_goal);
+    // Now do the assoc type projection
+    let alias_eq = AliasEq {
+        alias: AliasTy::Projection(projection),
+        ty: TyKind::BoundVar(BoundVar::new(
+            DebruijnIndex::INNERMOST,
+            ty.goal.binders.len(Interner),
+        ))
+        .intern(Interner),
+    };
+
+    let in_env = InEnvironment { goal: alias_eq.cast(Interner), environment: ty.environment };
+
+    let canonical = Canonical {
+        value: in_env,
+        binders: CanonicalVarKinds::from_iter(
+            Interner,
+            ty.goal.binders.iter(Interner).cloned().chain(Some(chalk_ir::WithKind::new(
+                VariableKind::Ty(chalk_ir::TyVariableKind::General),
+                chalk_ir::UniverseIndex::ROOT,
+            ))),
+        ),
+    };
+
+    let solution = db.trait_solve(krate, canonical)?;
+
+    match &solution {
+        Solution::Unique(Canonical { value: ConstrainedSubst { subst, .. }, binders })
+        | Solution::Ambig(Guidance::Definite(Canonical { value: subst, binders })) => {
+            // FIXME: vars may contain solutions for any inference variables
+            // that happened to be inside ty. To correctly handle these, we
+            // would have to pass the solution up to the inference context, but
+            // that requires a larger refactoring (especially if the deref
+            // happens during method resolution). So for the moment, we just
+            // check that we're not in the situation where we would actually
+            // need to handle the values of the additional variables, i.e.
+            // they're just being 'passed through'. In the 'standard' case where
+            // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
+            // the case.
+
+            // FIXME: if the trait solver decides to truncate the type, these
+            // assumptions will be broken. We would need to properly introduce
+            // new variables in that case
+
+            for i in 1..binders.len(Interner) {
+                if subst.at(Interner, i - 1).assert_ty_ref(Interner).kind(Interner)
+                    != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
+                {
+                    warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
+                    return None;
+                }
+            }
+            // FIXME: we remove lifetime variables here since they can confuse
+            // the method resolution code later
+            Some(fixup_lifetime_variables(Canonical {
+                value: subst.at(Interner, subst.len(Interner) - 1).assert_ty_ref(Interner).clone(),
+                binders: binders.clone(),
+            }))
+        }
+        Solution::Ambig(_) => {
+            info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
+            None
+        }
+    }
+}
 
-    let result = table.normalize_projection_ty(projection);
-    Some(table.resolve_ty_shallow(&result))
+fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
+    c: Canonical<T>,
+) -> Canonical<T> {
+    // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
+    let mut i = 0;
+    let subst = Substitution::from_iter(
+        Interner,
+        c.binders.iter(Interner).map(|vk| match vk.kind {
+            VariableKind::Ty(_) => {
+                let index = i;
+                i += 1;
+                BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(Interner).cast(Interner)
+            }
+            VariableKind::Lifetime => static_lifetime().cast(Interner),
+            VariableKind::Const(_) => unimplemented!(),
+        }),
+    );
+    let binders = CanonicalVarKinds::from_iter(
+        Interner,
+        c.binders.iter(Interner).filter(|vk| match vk.kind {
+            VariableKind::Ty(_) => true,
+            VariableKind::Lifetime => false,
+            VariableKind::Const(_) => true,
+        }),
+    );
+    let value = subst.apply(c.value, Interner);
+    Canonical { binders, value }
 }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 2020834fbc..0e75ddeabc 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -1189,18 +1189,7 @@ impl HirDisplay for Path {
                     write!(f, "super")?;
                 }
             }
-            (_, PathKind::DollarCrate(id)) => {
-                // Resolve `$crate` to the crate's display name.
-                // FIXME: should use the dependency name instead if available, but that depends on
-                // the crate invoking `HirDisplay`
-                let crate_graph = f.db.crate_graph();
-                let name = crate_graph[*id]
-                    .display_name
-                    .as_ref()
-                    .map(|name| name.canonical_name())
-                    .unwrap_or("$crate");
-                write!(f, "{name}")?
-            }
+            (_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
         }
 
         for (seg_idx, segment) in self.segments().iter().enumerate() {
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index c84604d69b..173380654e 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -46,7 +46,7 @@ use crate::{
 pub use unify::could_unify;
 pub(crate) use unify::unify;
 
-pub(crate) mod unify;
+mod unify;
 mod path;
 mod expr;
 mod pat;
@@ -228,7 +228,7 @@ pub enum Adjust {
 /// The target type is `U` in both cases, with the region and mutability
 /// being those shared by both the receiver and the returned reference.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct OverloadedDeref(pub Mutability);
+pub struct OverloadedDeref(Mutability);
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum AutoBorrow {
@@ -455,6 +455,10 @@ impl<'a> InferenceContext<'a> {
         self.result.method_resolutions.insert(expr, (func, subst));
     }
 
+    fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) {
+        self.result.field_resolutions.insert(expr, field);
+    }
+
     fn write_variant_resolution(&mut self, id: ExprOrPatId, variant: VariantId) {
         self.result.variant_resolutions.insert(id, variant);
     }
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index c24772f29b..bddb79c501 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -259,19 +259,27 @@ impl<'a> InferenceContext<'a> {
         // details of coercion errors though, so I think it's useful to leave
         // the structure like it is.
 
-        let snapshot = self.table.snapshot();
-
-        let mut autoderef = Autoderef::new(&mut self.table, from_ty.clone());
+        let canonicalized = self.canonicalize(from_ty.clone());
+        let mut autoderef = Autoderef::new(
+            self.db,
+            self.resolver.krate(),
+            InEnvironment {
+                goal: canonicalized.value.clone(),
+                environment: self.trait_env.env.clone(),
+            },
+        );
         let mut first_error = None;
         let mut found = None;
 
-        while let Some((referent_ty, autoderefs)) = autoderef.next() {
+        for (referent_ty, autoderefs) in autoderef.by_ref() {
             if autoderefs == 0 {
                 // Don't let this pass, otherwise it would cause
                 // &T to autoref to &&T.
                 continue;
             }
 
+            let referent_ty = canonicalized.decanonicalize_ty(&mut self.table, referent_ty);
+
             // At this point, we have deref'd `a` to `referent_ty`.  So
             // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
             // In the autoderef loop for `&'a mut Vec<T>`, we would get
@@ -296,7 +304,7 @@ impl<'a> InferenceContext<'a> {
             // from `&mut T` to `&U`.
             let lt = static_lifetime(); // FIXME: handle lifetimes correctly, see rustc
             let derefd_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(Interner);
-            match autoderef.table.try_unify(&derefd_from_ty, to_ty) {
+            match self.table.try_unify(&derefd_from_ty, to_ty) {
                 Ok(result) => {
                     found = Some(result.map(|()| derefd_from_ty));
                     break;
@@ -317,7 +325,6 @@ impl<'a> InferenceContext<'a> {
         let InferOk { value: ty, goals } = match found {
             Some(d) => d,
             None => {
-                self.table.rollback_to(snapshot);
                 let err = first_error.expect("coerce_borrowed_pointer had no error");
                 return Err(err);
             }
@@ -338,13 +345,29 @@ impl<'a> InferenceContext<'a> {
             return success(vec![], ty, goals);
         }
 
-        let mut adjustments = auto_deref_adjust_steps(&autoderef);
+        let mut adjustments = self.auto_deref_adjust_steps(&autoderef);
         adjustments
             .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(to_mt)), target: ty.clone() });
 
         success(adjustments, ty, goals)
     }
 
+    pub(super) fn auto_deref_adjust_steps(&self, autoderef: &Autoderef<'_>) -> Vec<Adjustment> {
+        let steps = autoderef.steps();
+        let targets =
+            steps.iter().skip(1).map(|(_, ty)| ty.clone()).chain(iter::once(autoderef.final_ty()));
+        steps
+            .iter()
+            .map(|(kind, _source)| match kind {
+                // We do not know what kind of deref we require at this point yet
+                AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
+                AutoderefKind::Builtin => None,
+            })
+            .zip(targets)
+            .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
+            .collect()
+    }
+
     /// Attempts to coerce from the type of a Rust function item into a function pointer.
     fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> CoerceResult {
         match to_ty.kind(Interner) {
@@ -597,19 +620,3 @@ fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError
         (Mutability::Not, Mutability::Mut) => Err(TypeError),
     }
 }
-
-pub(super) fn auto_deref_adjust_steps(autoderef: &Autoderef<'_, '_>) -> Vec<Adjustment> {
-    let steps = autoderef.steps();
-    let targets =
-        steps.iter().skip(1).map(|(_, ty)| ty.clone()).chain(iter::once(autoderef.final_ty()));
-    steps
-        .iter()
-        .map(|(kind, _source)| match kind {
-            // We do not know what kind of deref we require at this point yet
-            AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
-            AutoderefKind::Builtin => None,
-        })
-        .zip(targets)
-        .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
-        .collect()
-}
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index c305af2e91..13f64d6825 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -1,7 +1,6 @@
 //! Type inference for expressions.
 
 use std::{
-    collections::hash_map::Entry,
     iter::{repeat, repeat_with},
     mem,
     sync::Arc,
@@ -27,14 +26,15 @@ use crate::{
     method_resolution,
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
+    traits::FnTrait,
     utils::{generics, Generics},
-    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar,
-    Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+    AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
+    ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 };
 
 use super::{
-    coerce::auto_deref_adjust_steps, find_breakable, BindingMode, BreakableContext, Diverges,
-    Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch,
+    find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext,
+    InferenceDiagnostic, TypeMismatch,
 };
 
 impl<'a> InferenceContext<'a> {
@@ -77,6 +77,51 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
+    fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
+        let krate = self.resolver.krate()?;
+        let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
+        let output_assoc_type =
+            self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
+
+        let mut arg_tys = vec![];
+        let arg_ty = TyBuilder::tuple(num_args)
+            .fill(repeat_with(|| {
+                let arg = self.table.new_type_var();
+                arg_tys.push(arg.clone());
+                arg
+            }))
+            .build();
+
+        let projection = {
+            let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
+            if b.remaining() != 2 {
+                return None;
+            }
+            b.push(ty.clone()).push(arg_ty).build()
+        };
+
+        let trait_env = self.trait_env.env.clone();
+        let obligation = InEnvironment {
+            goal: projection.trait_ref(self.db).cast(Interner),
+            environment: trait_env,
+        };
+        let canonical = self.canonicalize(obligation.clone());
+        if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
+            self.push_obligation(obligation.goal);
+            let return_ty = self.table.normalize_projection_ty(projection);
+            Some((arg_tys, return_ty))
+        } else {
+            None
+        }
+    }
+
+    pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
+        match ty.callable_sig(self.db) {
+            Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())),
+            None => self.callable_sig_from_fn_trait(ty, num_args),
+        }
+    }
+
     fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
         self.db.unwind_if_cancelled();
 
@@ -274,19 +319,22 @@ impl<'a> InferenceContext<'a> {
             }
             Expr::Call { callee, args } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());
-                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone());
-                let mut res = None;
-                // manual loop to be able to access `derefs.table`
-                while let Some((callee_deref_ty, _)) = derefs.next() {
-                    res = derefs.table.callable_sig(&callee_deref_ty, args.len());
-                    if res.is_some() {
-                        break;
-                    }
-                }
+                let canonicalized = self.canonicalize(callee_ty.clone());
+                let mut derefs = Autoderef::new(
+                    self.db,
+                    self.resolver.krate(),
+                    InEnvironment {
+                        goal: canonicalized.value.clone(),
+                        environment: self.table.trait_env.env.clone(),
+                    },
+                );
+                let res = derefs.by_ref().find_map(|(callee_deref_ty, _)| {
+                    let ty = &canonicalized.decanonicalize_ty(&mut self.table, callee_deref_ty);
+                    self.callable_sig(ty, args.len())
+                });
                 let (param_tys, ret_ty): (Vec<Ty>, Ty) = match res {
                     Some(res) => {
-                        let adjustments = auto_deref_adjust_steps(&derefs);
-                        self.write_expr_adj(*callee, adjustments);
+                        self.write_expr_adj(*callee, self.auto_deref_adjust_steps(&derefs));
                         res
                     }
                     None => (Vec::new(), self.err_ty()),
@@ -441,67 +489,78 @@ impl<'a> InferenceContext<'a> {
             }
             Expr::Field { expr, name } => {
                 let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
-
-                let mut autoderef = Autoderef::new(&mut self.table, receiver_ty);
+                let canonicalized = self.canonicalize(receiver_ty);
+
+                let mut autoderef = Autoderef::new(
+                    self.db,
+                    self.resolver.krate(),
+                    InEnvironment {
+                        goal: canonicalized.value.clone(),
+                        environment: self.trait_env.env.clone(),
+                    },
+                );
                 let ty = autoderef.by_ref().find_map(|(derefed_ty, _)| {
-                    let (field_id, parameters) = match derefed_ty.kind(Interner) {
-                        TyKind::Tuple(_, substs) => {
-                            return name.as_tuple_index().and_then(|idx| {
-                                substs
-                                    .as_slice(Interner)
-                                    .get(idx)
-                                    .map(|a| a.assert_ty_ref(Interner))
-                                    .cloned()
-                            });
-                        }
+                    let module = self.resolver.module();
+                    let db = self.db;
+                    let is_visible = |field_id: &FieldId| {
+                        module
+                            .map(|mod_id| {
+                                db.field_visibilities(field_id.parent)[field_id.local_id]
+                                    .is_visible_from(db.upcast(), mod_id)
+                            })
+                            .unwrap_or(true)
+                    };
+                    match canonicalized
+                        .decanonicalize_ty(&mut self.table, derefed_ty)
+                        .kind(Interner)
+                    {
+                        TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
+                            substs
+                                .as_slice(Interner)
+                                .get(idx)
+                                .map(|a| a.assert_ty_ref(Interner))
+                                .cloned()
+                        }),
                         TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
                             let local_id = self.db.struct_data(*s).variant_data.field(name)?;
                             let field = FieldId { parent: (*s).into(), local_id };
-                            (field, parameters.clone())
+                            if is_visible(&field) {
+                                self.write_field_resolution(tgt_expr, field);
+                                Some(
+                                    self.db.field_types((*s).into())[field.local_id]
+                                        .clone()
+                                        .substitute(Interner, &parameters),
+                                )
+                            } else {
+                                None
+                            }
                         }
                         TyKind::Adt(AdtId(hir_def::AdtId::UnionId(u)), parameters) => {
                             let local_id = self.db.union_data(*u).variant_data.field(name)?;
                             let field = FieldId { parent: (*u).into(), local_id };
-                            (field, parameters.clone())
-                        }
-                        _ => return None,
-                    };
-                    let module = self.resolver.module();
-                    let is_visible = module
-                        .map(|mod_id| {
-                            self.db.field_visibilities(field_id.parent)[field_id.local_id]
-                                .is_visible_from(self.db.upcast(), mod_id)
-                        })
-                        .unwrap_or(true);
-                    if !is_visible {
-                        // Write down the first field resolution even if it is not visible
-                        // This aids IDE features for private fields like goto def and in
-                        // case of autoderef finding an applicable field, this will be
-                        // overwritten in a following cycle
-                        if let Entry::Vacant(entry) = self.result.field_resolutions.entry(tgt_expr)
-                        {
-                            entry.insert(field_id);
+                            if is_visible(&field) {
+                                self.write_field_resolution(tgt_expr, field);
+                                Some(
+                                    self.db.field_types((*u).into())[field.local_id]
+                                        .clone()
+                                        .substitute(Interner, &parameters),
+                                )
+                            } else {
+                                None
+                            }
                         }
-                        return None;
+                        _ => None,
                     }
-                    // can't have `write_field_resolution` here because `self.table` is borrowed :(
-                    self.result.field_resolutions.insert(tgt_expr, field_id);
-                    let ty = self.db.field_types(field_id.parent)[field_id.local_id]
-                        .clone()
-                        .substitute(Interner, &parameters);
-                    Some(ty)
                 });
                 let ty = match ty {
                     Some(ty) => {
-                        let adjustments = auto_deref_adjust_steps(&autoderef);
-                        self.write_expr_adj(*expr, adjustments);
-                        let ty = self.insert_type_vars(ty);
-                        let ty = self.normalize_associated_types_in(ty);
+                        self.write_expr_adj(*expr, self.auto_deref_adjust_steps(&autoderef));
                         ty
                     }
-                    _ => self.err_ty(),
+                    None => self.err_ty(),
                 };
-                ty
+                let ty = self.insert_type_vars(ty);
+                self.normalize_associated_types_in(ty)
             }
             Expr::Await { expr } => {
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
@@ -559,9 +618,25 @@ impl<'a> InferenceContext<'a> {
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
                 let inner_ty = self.resolve_ty_shallow(&inner_ty);
                 match op {
-                    UnaryOp::Deref => {
-                        autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
-                    }
+                    UnaryOp::Deref => match self.resolver.krate() {
+                        Some(krate) => {
+                            let canonicalized = self.canonicalize(inner_ty);
+                            match autoderef::deref(
+                                self.db,
+                                krate,
+                                InEnvironment {
+                                    goal: &canonicalized.value,
+                                    environment: self.trait_env.env.clone(),
+                                },
+                            ) {
+                                Some(derefed_ty) => {
+                                    canonicalized.decanonicalize_ty(&mut self.table, derefed_ty)
+                                }
+                                None => self.err_ty(),
+                            }
+                        }
+                        None => self.err_ty(),
+                    },
                     UnaryOp::Neg => {
                         match inner_ty.kind(Interner) {
                             // Fast path for builtins
@@ -647,19 +722,20 @@ impl<'a> InferenceContext<'a> {
                 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
                 let index_ty = self.infer_expr(*index, &Expectation::none());
 
-                if let Some(index_trait) = self.resolve_ops_index() {
-                    let canonicalized = self.canonicalize(base_ty.clone());
-                    let receiver_adjustments = method_resolution::resolve_indexing_op(
+                if let (Some(index_trait), Some(krate)) =
+                    (self.resolve_ops_index(), self.resolver.krate())
+                {
+                    let canonicalized = self.canonicalize(base_ty);
+                    let self_ty = method_resolution::resolve_indexing_op(
                         self.db,
+                        &canonicalized.value,
                         self.trait_env.clone(),
-                        canonicalized.value,
+                        krate,
                         index_trait,
                     );
-                    let (self_ty, adj) = receiver_adjustments
-                        .map_or((self.err_ty(), Vec::new()), |adj| {
-                            adj.apply(&mut self.table, base_ty)
-                        });
-                    self.write_expr_adj(*base, adj);
+                    let self_ty = self_ty.map_or(self.err_ty(), |t| {
+                        canonicalized.decanonicalize_ty(&mut self.table, t)
+                    });
                     self.resolve_associated_type_with_params(
                         self_ty,
                         self.resolve_ops_index_output(),
@@ -906,20 +982,22 @@ impl<'a> InferenceContext<'a> {
 
         let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
 
-        let resolved = method_resolution::lookup_method(
-            &canonicalized_receiver.value,
-            self.db,
-            self.trait_env.clone(),
-            &traits_in_scope,
-            self.resolver.module().into(),
-            method_name,
-        );
+        let resolved = self.resolver.krate().and_then(|krate| {
+            method_resolution::lookup_method(
+                &canonicalized_receiver.value,
+                self.db,
+                self.trait_env.clone(),
+                krate,
+                &traits_in_scope,
+                self.resolver.module().into(),
+                method_name,
+            )
+        });
         let (receiver_ty, method_ty, substs) = match resolved {
-            Some((adjust, func)) => {
-                let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
+            Some((ty, func)) => {
+                let ty = canonicalized_receiver.decanonicalize_ty(&mut self.table, ty);
                 let generics = generics(self.db.upcast(), func.into());
-                let substs = self.substs_for_method_call(generics, generic_args);
-                self.write_expr_adj(receiver, adjustments);
+                let substs = self.substs_for_method_call(generics, generic_args, &ty);
                 self.write_method_resolution(tgt_expr, func, substs.clone());
                 (ty, self.db.value_ty(func.into()), substs)
             }
@@ -1032,15 +1110,20 @@ impl<'a> InferenceContext<'a> {
         &mut self,
         def_generics: Generics,
         generic_args: Option<&GenericArgs>,
+        receiver_ty: &Ty,
     ) -> Substitution {
         let (parent_params, self_params, type_params, impl_trait_params) =
             def_generics.provenance_split();
         assert_eq!(self_params, 0); // method shouldn't have another Self param
         let total_len = parent_params + type_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
-        // Parent arguments are unknown
-        for _ in def_generics.iter_parent() {
-            substs.push(self.table.new_type_var());
+        // Parent arguments are unknown, except for the receiver type
+        for (_id, param) in def_generics.iter_parent() {
+            if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
+                substs.push(receiver_ty.clone());
+            } else {
+                substs.push(self.table.new_type_var());
+            }
         }
         // handle provided type arguments
         if let Some(generic_args) = generic_args {
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 0d6c8f12d2..b63ef2ffdc 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -218,12 +218,14 @@ impl<'a> InferenceContext<'a> {
         }
 
         let canonical_ty = self.canonicalize(ty.clone());
+        let krate = self.resolver.krate()?;
         let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
 
         method_resolution::iterate_method_candidates(
             &canonical_ty.value,
             self.db,
             self.table.trait_env.clone(),
+            krate,
             &traits_in_scope,
             self.resolver.module().into(),
             Some(name),
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 21b48b9d80..bb7cdb677e 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -1,6 +1,6 @@
 //! Unification and canonicalization logic.
 
-use std::{fmt, iter, mem, sync::Arc};
+use std::{fmt, mem, sync::Arc};
 
 use chalk_ir::{
     cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
@@ -8,14 +8,12 @@ use chalk_ir::{
 };
 use chalk_solve::infer::ParameterEnaVariableExt;
 use ena::unify::UnifyKey;
-use hir_expand::name;
 
 use super::{InferOk, InferResult, InferenceContext, TypeError};
 use crate::{
-    db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar,
-    Canonical, Const, DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar,
-    Interner, Lifetime, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution,
-    TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
+    db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, Const,
+    DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime,
+    ProjectionTy, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
 };
 
 impl<'a> InferenceContext<'a> {
@@ -26,20 +24,32 @@ impl<'a> InferenceContext<'a> {
     where
         T::Result: HasInterner<Interner = Interner>,
     {
+        // try to resolve obligations before canonicalizing, since this might
+        // result in new knowledge about variables
+        self.resolve_obligations_as_possible();
         self.table.canonicalize(t)
     }
 }
 
 #[derive(Debug, Clone)]
-pub(crate) struct Canonicalized<T>
+pub(super) struct Canonicalized<T>
 where
     T: HasInterner<Interner = Interner>,
 {
-    pub(crate) value: Canonical<T>,
+    pub(super) value: Canonical<T>,
     free_vars: Vec<GenericArg>,
 }
 
 impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
+    /// this method is wrong and shouldn't exist
+    pub(super) fn decanonicalize_ty(&self, table: &mut InferenceTable, ty: Canonical<Ty>) -> Ty {
+        let mut vars = self.free_vars.clone();
+        while ty.binders.len(Interner) > vars.len() {
+            vars.push(table.new_type_var().cast(Interner));
+        }
+        chalk_ir::Substitute::apply(&vars, ty.value, Interner)
+    }
+
     pub(super) fn apply_solution(
         &self,
         ctx: &mut InferenceTable,
@@ -193,16 +203,13 @@ impl<'a> InferenceTable<'a> {
         .intern(Interner)
     }
 
-    pub(crate) fn canonicalize<T: Fold<Interner> + HasInterner<Interner = Interner>>(
+    pub(super) fn canonicalize<T: Fold<Interner> + HasInterner<Interner = Interner>>(
         &mut self,
         t: T,
     ) -> Canonicalized<T::Result>
     where
         T::Result: HasInterner<Interner = Interner>,
     {
-        // try to resolve obligations before canonicalizing, since this might
-        // result in new knowledge about variables
-        self.resolve_obligations_as_possible();
         let result = self.var_unification_table.canonicalize(Interner, t);
         let free_vars = result
             .free_vars
@@ -218,7 +225,7 @@ impl<'a> InferenceTable<'a> {
     /// type annotation (e.g. from a let type annotation, field type or function
     /// call). `make_ty` handles this already, but e.g. for field types we need
     /// to do it as well.
-    pub(crate) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
+    pub(super) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
         fold_tys(
             ty,
             |ty, _| match ty.kind(Interner) {
@@ -231,7 +238,7 @@ impl<'a> InferenceTable<'a> {
         )
     }
 
-    pub(crate) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
+    pub(super) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
         let var = self.new_type_var();
         let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
         let obligation = alias_eq.cast(Interner);
@@ -292,13 +299,6 @@ impl<'a> InferenceTable<'a> {
         self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
     }
 
-    pub(crate) fn instantiate_canonical<T>(&mut self, canonical: Canonical<T>) -> T::Result
-    where
-        T: HasInterner<Interner = Interner> + Fold<Interner> + std::fmt::Debug,
-    {
-        self.var_unification_table.instantiate_canonical(Interner, canonical)
-    }
-
     fn resolve_with_fallback_inner<T>(
         &mut self,
         var_stack: &mut Vec<InferenceVar>,
@@ -351,7 +351,6 @@ impl<'a> InferenceTable<'a> {
     /// If `ty` is a type variable with known type, returns that type;
     /// otherwise, return ty.
     pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
-        self.resolve_obligations_as_possible();
         self.var_unification_table.normalize_ty_shallow(Interner, ty).unwrap_or_else(|| ty.clone())
     }
 
@@ -364,16 +363,6 @@ impl<'a> InferenceTable<'a> {
         self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
     }
 
-    /// Checks an obligation without registering it. Useful mostly to check
-    /// whether a trait *might* be implemented before deciding to 'lock in' the
-    /// choice (during e.g. method resolution or deref).
-    pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
-        let in_env = InEnvironment::new(&self.trait_env.env, goal);
-        let canonicalized = self.canonicalize(in_env);
-        let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value);
-        solution
-    }
-
     pub(crate) fn register_obligation(&mut self, goal: Goal) {
         let in_env = InEnvironment::new(&self.trait_env.env, goal);
         self.register_obligation_in_env(in_env)
@@ -533,51 +522,6 @@ impl<'a> InferenceTable<'a> {
             }
         }
     }
-
-    pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
-        match ty.callable_sig(self.db) {
-            Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())),
-            None => self.callable_sig_from_fn_trait(ty, num_args),
-        }
-    }
-
-    fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
-        let krate = self.trait_env.krate;
-        let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
-        let output_assoc_type =
-            self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
-
-        let mut arg_tys = vec![];
-        let arg_ty = TyBuilder::tuple(num_args)
-            .fill(iter::repeat_with(|| {
-                let arg = self.new_type_var();
-                arg_tys.push(arg.clone());
-                arg
-            }))
-            .build();
-
-        let projection = {
-            let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
-            if b.remaining() != 2 {
-                return None;
-            }
-            b.push(ty.clone()).push(arg_ty).build()
-        };
-
-        let trait_env = self.trait_env.env.clone();
-        let obligation = InEnvironment {
-            goal: projection.trait_ref(self.db).cast(Interner),
-            environment: trait_env,
-        };
-        let canonical = self.canonicalize(obligation.clone());
-        if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
-            self.register_obligation(obligation.goal);
-            let return_ty = self.normalize_projection_ty(projection);
-            Some((arg_tys, return_ty))
-        } else {
-            None
-        }
-    }
 }
 
 impl<'a> fmt::Debug for InferenceTable<'a> {
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 44ece57a8e..c91b6f2e82 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -17,11 +17,10 @@ use rustc_hash::{FxHashMap, FxHashSet};
 use stdx::never;
 
 use crate::{
-    autoderef::{self, AutoderefKind},
+    autoderef,
     consteval::{self, ConstExt},
     db::HirDatabase,
     from_foreign_def_id,
-    infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
     primitive::{self, FloatTy, IntTy, UintTy},
     static_lifetime,
     utils::all_super_traits,
@@ -430,25 +429,28 @@ pub fn def_crates(
     Some(res)
 }
 
-/// Look up the method with the given name.
+/// Look up the method with the given name, returning the actual autoderefed
+/// receiver type (but without autoref applied yet).
 pub(crate) fn lookup_method(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: &Name,
-) -> Option<(ReceiverAdjustments, FunctionId)> {
+) -> Option<(Canonical<Ty>, FunctionId)> {
     iterate_method_candidates(
         ty,
         db,
         env,
+        krate,
         traits_in_scope,
         visible_from_module,
         Some(name),
         LookupMode::MethodCall,
-        |adjustments, f| match f {
-            AssocItemId::FunctionId(f) => Some((adjustments, f)),
+        |ty, f| match f {
+            AssocItemId::FunctionId(f) => Some((ty.clone(), f)),
             _ => None,
         },
     )
@@ -494,89 +496,33 @@ impl From<Option<BlockId>> for VisibleFromModule {
     }
 }
 
-#[derive(Debug, Clone, Default)]
-pub struct ReceiverAdjustments {
-    autoref: Option<Mutability>,
-    autoderefs: usize,
-    unsize_array: bool,
-}
-
-impl ReceiverAdjustments {
-    pub(crate) fn apply(&self, table: &mut InferenceTable, ty: Ty) -> (Ty, Vec<Adjustment>) {
-        let mut ty = ty;
-        let mut adjust = Vec::new();
-        for _ in 0..self.autoderefs {
-            match autoderef::autoderef_step(table, ty.clone()) {
-                None => {
-                    never!("autoderef not possible for {:?}", ty);
-                    ty = TyKind::Error.intern(Interner);
-                    break;
-                }
-                Some((kind, new_ty)) => {
-                    ty = new_ty.clone();
-                    adjust.push(Adjustment {
-                        kind: Adjust::Deref(match kind {
-                            // FIXME should we know the mutability here?
-                            AutoderefKind::Overloaded => Some(OverloadedDeref(Mutability::Not)),
-                            AutoderefKind::Builtin => None,
-                        }),
-                        target: new_ty,
-                    });
-                }
-            }
-        }
-        if self.unsize_array {
-            ty = match ty.kind(Interner) {
-                TyKind::Array(inner, _) => TyKind::Slice(inner.clone()).intern(Interner),
-                _ => {
-                    never!("unsize_array with non-array {:?}", ty);
-                    ty
-                }
-            };
-            // FIXME this is kind of wrong since the unsize needs to happen to a pointer/reference
-            adjust.push(Adjustment {
-                kind: Adjust::Pointer(PointerCast::Unsize),
-                target: ty.clone(),
-            });
-        }
-        if let Some(m) = self.autoref {
-            ty = TyKind::Ref(m, static_lifetime(), ty).intern(Interner);
-            adjust
-                .push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(m)), target: ty.clone() });
-        }
-        (ty, adjust)
-    }
-
-    fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments {
-        Self { autoref: Some(m), ..*self }
-    }
-}
-
 // This would be nicer if it just returned an iterator, but that runs into
 // lifetime problems, because we need to borrow temp `CrateImplDefs`.
 // FIXME add a context type here?
-pub(crate) fn iterate_method_candidates<T>(
+pub fn iterate_method_candidates<T>(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
     mode: LookupMode,
-    mut callback: impl FnMut(ReceiverAdjustments, AssocItemId) -> Option<T>,
+    mut callback: impl FnMut(&Canonical<Ty>, AssocItemId) -> Option<T>,
 ) -> Option<T> {
     let mut slot = None;
     iterate_method_candidates_dyn(
         ty,
         db,
         env,
+        krate,
         traits_in_scope,
         visible_from_module,
         name,
         mode,
-        &mut |adj, item| {
+        &mut |ty, item| {
             assert!(slot.is_none());
-            if let Some(it) = callback(adj, item) {
+            if let Some(it) = callback(ty, item) {
                 slot = Some(it);
                 return ControlFlow::Break(());
             }
@@ -586,45 +532,28 @@ pub(crate) fn iterate_method_candidates<T>(
     slot
 }
 
-pub fn iterate_path_candidates(
-    ty: &Canonical<Ty>,
-    db: &dyn HirDatabase,
-    env: Arc<TraitEnvironment>,
-    traits_in_scope: &FxHashSet<TraitId>,
-    visible_from_module: VisibleFromModule,
-    name: Option<&Name>,
-    callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
-) -> ControlFlow<()> {
-    iterate_method_candidates_dyn(
-        ty,
-        db,
-        env,
-        traits_in_scope,
-        visible_from_module,
-        name,
-        LookupMode::Path,
-        // the adjustments are not relevant for path lookup
-        &mut |_, id| callback(id),
-    )
-}
-
 pub fn iterate_method_candidates_dyn(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
     mode: LookupMode,
-    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+    callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
     match mode {
         LookupMode::MethodCall => {
-            // For method calls, rust first does any number of autoderef, and
-            // then one autoref (i.e. when the method takes &self or &mut self).
-            // Note that when we've got a receiver like &S, even if the method
-            // we find in the end takes &self, we still do the autoderef step
-            // (just as rustc does an autoderef and then autoref again).
+            // For method calls, rust first does any number of autoderef, and then one
+            // autoref (i.e. when the method takes &self or &mut self). We just ignore
+            // the autoref currently -- when we find a method matching the given name,
+            // we assume it fits.
+
+            // Also note that when we've got a receiver like &S, even if the method we
+            // find in the end takes &self, we still do the autoderef step (just as
+            // rustc does an autoderef and then autoref again).
+            let ty = InEnvironment { goal: ty.clone(), environment: env.env.clone() };
 
             // We have to be careful about the order we're looking at candidates
             // in here. Consider the case where we're resolving `x.clone()`
@@ -639,31 +568,29 @@ pub fn iterate_method_candidates_dyn(
             // the methods by autoderef order of *receiver types*, not *self
             // types*.
 
-            let mut table = InferenceTable::new(db, env.clone());
-            let ty = table.instantiate_canonical(ty.clone());
-            let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
-            let deref_chains = stdx::slice_tails(&deref_chain);
+            let deref_chain = autoderef_method_receiver(db, krate, ty);
+            let mut deref_chains = stdx::slice_tails(&deref_chain);
 
-            let result = deref_chains.zip(adj).try_for_each(|(deref_chain, adj)| {
+            deref_chains.try_for_each(|deref_chain| {
                 iterate_method_candidates_with_autoref(
                     deref_chain,
-                    adj,
                     db,
                     env.clone(),
+                    krate,
                     traits_in_scope,
                     visible_from_module,
                     name,
                     callback,
                 )
-            });
-            result
+            })
         }
         LookupMode::Path => {
             // No autoderef for path lookups
             iterate_method_candidates_for_self_ty(
                 ty,
                 db,
-                env.clone(),
+                env,
+                krate,
                 traits_in_scope,
                 visible_from_module,
                 name,
@@ -675,27 +602,27 @@ pub fn iterate_method_candidates_dyn(
 
 fn iterate_method_candidates_with_autoref(
     deref_chain: &[Canonical<Ty>],
-    first_adjustment: ReceiverAdjustments,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
-    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+    mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
     let (receiver_ty, rest) = match deref_chain.split_first() {
-        Some((rec, rest)) => (rec, rest),
+        Some((rec, rest)) => (rec.clone(), rest),
         None => {
             never!("received empty deref-chain");
             return ControlFlow::Break(());
         }
     };
     iterate_method_candidates_by_receiver(
-        receiver_ty,
-        first_adjustment.clone(),
+        &receiver_ty,
         &rest,
         db,
         env.clone(),
+        krate,
         traits_in_scope,
         visible_from_module,
         name,
@@ -703,17 +630,17 @@ fn iterate_method_candidates_with_autoref(
     )?;
 
     let refed = Canonical {
+        binders: receiver_ty.binders.clone(),
         value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
             .intern(Interner),
-        binders: receiver_ty.binders.clone(),
     };
 
     iterate_method_candidates_by_receiver(
         &refed,
-        first_adjustment.with_autoref(Mutability::Not),
         deref_chain,
         db,
         env.clone(),
+        krate,
         traits_in_scope,
         visible_from_module,
         name,
@@ -721,17 +648,16 @@ fn iterate_method_candidates_with_autoref(
     )?;
 
     let ref_muted = Canonical {
-        value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
-            .intern(Interner),
-        binders: receiver_ty.binders.clone(),
+        binders: receiver_ty.binders,
+        value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value).intern(Interner),
     };
 
     iterate_method_candidates_by_receiver(
         &ref_muted,
-        first_adjustment.with_autoref(Mutability::Mut),
         deref_chain,
         db,
-        env.clone(),
+        env,
+        krate,
         traits_in_scope,
         visible_from_module,
         name,
@@ -741,14 +667,14 @@ fn iterate_method_candidates_with_autoref(
 
 fn iterate_method_candidates_by_receiver(
     receiver_ty: &Canonical<Ty>,
-    receiver_adjustments: ReceiverAdjustments,
     rest_of_deref_chain: &[Canonical<Ty>],
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
-    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+    mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
     // We're looking for methods with *receiver* type receiver_ty. These could
     // be found in any of the derefs of receiver_ty, so we have to go through
@@ -760,7 +686,7 @@ fn iterate_method_candidates_by_receiver(
             env.clone(),
             name,
             Some(receiver_ty),
-            Some(receiver_adjustments.clone()),
+            krate,
             visible_from_module,
             &mut callback,
         )?
@@ -771,10 +697,10 @@ fn iterate_method_candidates_by_receiver(
             self_ty,
             db,
             env.clone(),
+            krate,
             traits_in_scope,
             name,
             Some(receiver_ty),
-            Some(receiver_adjustments.clone()),
             &mut callback,
         )?
     }
@@ -786,10 +712,11 @@ fn iterate_method_candidates_for_self_ty(
     self_ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     visible_from_module: VisibleFromModule,
     name: Option<&Name>,
-    mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+    mut callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
     iterate_inherent_methods(
         self_ty,
@@ -797,24 +724,24 @@ fn iterate_method_candidates_for_self_ty(
         env.clone(),
         name,
         None,
-        None,
+        krate,
         visible_from_module,
         &mut callback,
     )?;
-    iterate_trait_method_candidates(self_ty, db, env, traits_in_scope, name, None, None, callback)
+    iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
 }
 
 fn iterate_trait_method_candidates(
     self_ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     traits_in_scope: &FxHashSet<TraitId>,
     name: Option<&Name>,
     receiver_ty: Option<&Canonical<Ty>>,
-    receiver_adjustments: Option<ReceiverAdjustments>,
-    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+    callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let self_is_array = matches!(self_ty.value.kind(Interner), chalk_ir::TyKind::Array(..));
+    let receiver_is_array = matches!(self_ty.value.kind(Interner), chalk_ir::TyKind::Array(..));
     // if ty is `dyn Trait`, the trait doesn't need to be in scope
     let inherent_trait =
         self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
@@ -836,10 +763,10 @@ fn iterate_trait_method_candidates(
         // 2021.
         // This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
         // arrays.
-        if data.skip_array_during_method_dispatch && self_is_array {
+        if data.skip_array_during_method_dispatch && receiver_is_array {
             // FIXME: this should really be using the edition of the method name's span, in case it
             // comes from a macro
-            if db.crate_graph()[env.krate].edition < Edition::Edition2021 {
+            if db.crate_graph()[krate].edition < Edition::Edition2021 {
                 continue;
             }
         }
@@ -855,13 +782,14 @@ fn iterate_trait_method_candidates(
                 continue;
             }
             if !known_implemented {
-                let goal = generic_implements_goal(db, env.clone(), t, self_ty);
-                if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
+                let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
+                if db.trait_solve(krate, goal.cast(Interner)).is_none() {
                     continue 'traits;
                 }
             }
             known_implemented = true;
-            callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+            // FIXME: we shouldn't be ignoring the binders here
+            callback(self_ty, item)?
         }
     }
     ControlFlow::Continue(())
@@ -896,11 +824,11 @@ fn iterate_inherent_methods(
     env: Arc<TraitEnvironment>,
     name: Option<&Name>,
     receiver_ty: Option<&Canonical<Ty>>,
-    receiver_adjustments: Option<ReceiverAdjustments>,
+    krate: CrateId,
     visible_from_module: VisibleFromModule,
-    callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+    callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let def_crates = match def_crates(db, &self_ty.value, env.krate) {
+    let def_crates = match def_crates(db, &self_ty.value, krate) {
         Some(k) => k,
         None => return ControlFlow::Continue(()),
     };
@@ -920,7 +848,6 @@ fn iterate_inherent_methods(
                 env.clone(),
                 name,
                 receiver_ty,
-                receiver_adjustments.clone(),
                 module,
                 callback,
             )?;
@@ -929,17 +856,7 @@ fn iterate_inherent_methods(
 
     for krate in def_crates {
         let impls = db.inherent_impls_in_crate(krate);
-        impls_for_self_ty(
-            &impls,
-            self_ty,
-            db,
-            env.clone(),
-            name,
-            receiver_ty,
-            receiver_adjustments.clone(),
-            module,
-            callback,
-        )?;
+        impls_for_self_ty(&impls, self_ty, db, env.clone(), name, receiver_ty, module, callback)?;
     }
     return ControlFlow::Continue(());
 
@@ -950,9 +867,8 @@ fn iterate_inherent_methods(
         env: Arc<TraitEnvironment>,
         name: Option<&Name>,
         receiver_ty: Option<&Canonical<Ty>>,
-        receiver_adjustments: Option<ReceiverAdjustments>,
         visible_from_module: Option<ModuleId>,
-        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
+        callback: &mut dyn FnMut(&Canonical<Ty>, AssocItemId) -> ControlFlow<()>,
     ) -> ControlFlow<()> {
         let impls_for_self_ty = filter_inherent_impls_for_self_ty(impls, &self_ty.value);
         for &impl_def in impls_for_self_ty {
@@ -973,32 +889,33 @@ fn iterate_inherent_methods(
                 // already happens in `is_valid_candidate` above; if not, we
                 // check it here
                 if receiver_ty.is_none()
-                    && inherent_impl_substs(db, env.clone(), impl_def, &self_ty).is_none()
+                    && inherent_impl_substs(db, env.clone(), impl_def, self_ty).is_none()
                 {
                     cov_mark::hit!(impl_self_type_match_without_receiver);
                     continue;
                 }
-                callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
+                let receiver_ty = receiver_ty.unwrap_or(self_ty);
+                callback(receiver_ty, item)?;
             }
         }
         ControlFlow::Continue(())
     }
 }
 
-/// Returns the receiver type for the index trait call.
+/// Returns the self type for the index trait call.
 pub fn resolve_indexing_op(
     db: &dyn HirDatabase,
+    ty: &Canonical<Ty>,
     env: Arc<TraitEnvironment>,
-    ty: Canonical<Ty>,
+    krate: CrateId,
     index_trait: TraitId,
-) -> Option<ReceiverAdjustments> {
-    let mut table = InferenceTable::new(db, env.clone());
-    let ty = table.instantiate_canonical(ty);
-    let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
-    for (ty, adj) in deref_chain.into_iter().zip(adj) {
-        let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
-        if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
-            return Some(adj);
+) -> Option<Canonical<Ty>> {
+    let ty = InEnvironment { goal: ty.clone(), environment: env.env.clone() };
+    let deref_chain = autoderef_method_receiver(db, krate, ty);
+    for ty in deref_chain {
+        let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
+        if db.trait_solve(krate, goal.cast(Interner)).is_some() {
+            return Some(ty);
         }
     }
     None
@@ -1150,10 +1067,11 @@ pub fn implements_trait(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     trait_: TraitId,
 ) -> bool {
-    let goal = generic_implements_goal(db, env.clone(), trait_, &ty);
-    let solution = db.trait_solve(env.krate, goal.cast(Interner));
+    let goal = generic_implements_goal(db, env, trait_, ty.clone());
+    let solution = db.trait_solve(krate, goal.cast(Interner));
 
     solution.is_some()
 }
@@ -1162,10 +1080,11 @@ pub fn implements_trait_unique(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
+    krate: CrateId,
     trait_: TraitId,
 ) -> bool {
-    let goal = generic_implements_goal(db, env.clone(), trait_, &ty);
-    let solution = db.trait_solve(env.krate, goal.cast(Interner));
+    let goal = generic_implements_goal(db, env, trait_, ty.clone());
+    let solution = db.trait_solve(krate, goal.cast(Interner));
 
     matches!(solution, Some(crate::Solution::Unique(_)))
 }
@@ -1176,11 +1095,11 @@ fn generic_implements_goal(
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
     trait_: TraitId,
-    self_ty: &Canonical<Ty>,
+    self_ty: Canonical<Ty>,
 ) -> Canonical<InEnvironment<super::DomainGoal>> {
     let mut kinds = self_ty.binders.interned().to_vec();
     let trait_ref = TyBuilder::trait_ref(db, trait_)
-        .push(self_ty.value.clone())
+        .push(self_ty.value)
         .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
         .build();
     kinds.extend(
@@ -1198,27 +1117,17 @@ fn generic_implements_goal(
 }
 
 fn autoderef_method_receiver(
-    table: &mut InferenceTable,
-    ty: Ty,
-) -> (Vec<Canonical<Ty>>, Vec<ReceiverAdjustments>) {
-    let (mut deref_chain, mut adjustments): (Vec<_>, Vec<_>) = (Vec::new(), Vec::new());
-    let mut autoderef = autoderef::Autoderef::new(table, ty);
-    while let Some((ty, derefs)) = autoderef.next() {
-        deref_chain.push(autoderef.table.canonicalize(ty).value);
-        adjustments.push(ReceiverAdjustments {
-            autoref: None,
-            autoderefs: derefs,
-            unsize_array: false,
-        });
-    }
+    db: &dyn HirDatabase,
+    krate: CrateId,
+    ty: InEnvironment<Canonical<Ty>>,
+) -> Vec<Canonical<Ty>> {
+    let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
     // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
-    if let (Some((TyKind::Array(parameters, _), binders)), Some(adj)) = (
-        deref_chain.last().map(|ty| (ty.value.kind(Interner), ty.binders.clone())),
-        adjustments.last().cloned(),
-    ) {
+    if let Some(TyKind::Array(parameters, _)) = deref_chain.last().map(|ty| ty.value.kind(Interner))
+    {
+        let kinds = deref_chain.last().unwrap().binders.clone();
         let unsized_ty = TyKind::Slice(parameters.clone()).intern(Interner);
-        deref_chain.push(Canonical { value: unsized_ty, binders });
-        adjustments.push(ReceiverAdjustments { unsize_array: true, ..adj });
+        deref_chain.push(Canonical { value: unsized_ty, binders: kinds })
     }
-    (deref_chain, adjustments)
+    deref_chain
 }
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index b139edbee9..bd280ba774 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -40,7 +40,8 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct TraitEnvironment {
     pub krate: CrateId,
-    // FIXME make this a BTreeMap
+    // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord,
+    // but for now it's too annoying...
     pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
     pub env: chalk_ir::Environment<Interner>,
 }
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index f886ff7837..b6d9e4021d 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -2,9 +2,7 @@ use hir::Semantics;
 use ide_db::{
     base_db::{FileId, FilePosition},
     defs::{Definition, IdentClass},
-    helpers::{
-        for_each_break_and_continue_expr, for_each_tail_expr, node_ext::walk_expr, pick_best_token,
-    },
+    helpers::{for_each_break_expr, for_each_tail_expr, node_ext::walk_expr, pick_best_token},
     search::{FileReference, ReferenceCategory, SearchScope},
     RootDatabase,
 };
@@ -12,7 +10,7 @@ use rustc_hash::FxHashSet;
 use syntax::{
     ast::{self, HasLoopBody},
     match_ast, AstNode,
-    SyntaxKind::{self, IDENT, INT_NUMBER},
+    SyntaxKind::{IDENT, INT_NUMBER},
     SyntaxNode, SyntaxToken, TextRange, T,
 };
 
@@ -68,9 +66,7 @@ pub(crate) fn highlight_related(
         T![for] if config.break_points && token.parent().and_then(ast::ForExpr::cast).is_some() => {
             highlight_break_points(token)
         }
-        T![break] | T![loop] | T![while] | T![continue] if config.break_points => {
-            highlight_break_points(token)
-        }
+        T![break] | T![loop] | T![while] if config.break_points => highlight_break_points(token),
         _ if config.references => highlight_references(sema, &syntax, token, file_id),
         _ => None,
     }
@@ -191,7 +187,6 @@ fn highlight_exit_points(
 
 fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
     fn hl(
-        cursor_token_kind: SyntaxKind,
         token: Option<SyntaxToken>,
         label: Option<ast::Label>,
         body: Option<ast::StmtList>,
@@ -202,23 +197,11 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
             label.as_ref().map(|it| it.syntax().text_range()),
         );
         highlights.extend(range.map(|range| HighlightedRange { category: None, range }));
-        for_each_break_and_continue_expr(label, body, &mut |expr| {
-            let range: Option<TextRange> = match (cursor_token_kind, expr) {
-                (T![for] | T![while] | T![loop] | T![break], ast::Expr::BreakExpr(break_)) => {
-                    cover_range(
-                        break_.break_token().map(|it| it.text_range()),
-                        break_.lifetime().map(|it| it.syntax().text_range()),
-                    )
-                }
-                (
-                    T![for] | T![while] | T![loop] | T![continue],
-                    ast::Expr::ContinueExpr(continue_),
-                ) => cover_range(
-                    continue_.continue_token().map(|it| it.text_range()),
-                    continue_.lifetime().map(|it| it.syntax().text_range()),
-                ),
-                _ => None,
-            };
+        for_each_break_expr(label, body, &mut |break_| {
+            let range = cover_range(
+                break_.break_token().map(|it| it.text_range()),
+                break_.lifetime().map(|it| it.syntax().text_range()),
+            );
             highlights.extend(range.map(|range| HighlightedRange { category: None, range }));
         });
         Some(highlights)
@@ -227,7 +210,6 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
     let lbl = match_ast! {
         match parent {
             ast::BreakExpr(b) => b.lifetime(),
-            ast::ContinueExpr(c) => c.lifetime(),
             ast::LoopExpr(l) => l.label().and_then(|it| it.lifetime()),
             ast::ForExpr(f) => f.label().and_then(|it| it.lifetime()),
             ast::WhileExpr(w) => w.label().and_then(|it| it.lifetime()),
@@ -242,29 +224,19 @@ fn highlight_break_points(token: SyntaxToken) -> Option<Vec<HighlightedRange>> {
         }
         None => true,
     };
-    let token_kind = token.kind();
     for anc in token.ancestors().flat_map(ast::Expr::cast) {
         return match anc {
-            ast::Expr::LoopExpr(l) if label_matches(l.label()) => hl(
-                token_kind,
-                l.loop_token(),
-                l.label(),
-                l.loop_body().and_then(|it| it.stmt_list()),
-            ),
-            ast::Expr::ForExpr(f) if label_matches(f.label()) => hl(
-                token_kind,
-                f.for_token(),
-                f.label(),
-                f.loop_body().and_then(|it| it.stmt_list()),
-            ),
-            ast::Expr::WhileExpr(w) if label_matches(w.label()) => hl(
-                token_kind,
-                w.while_token(),
-                w.label(),
-                w.loop_body().and_then(|it| it.stmt_list()),
-            ),
+            ast::Expr::LoopExpr(l) if label_matches(l.label()) => {
+                hl(l.loop_token(), l.label(), l.loop_body().and_then(|it| it.stmt_list()))
+            }
+            ast::Expr::ForExpr(f) if label_matches(f.label()) => {
+                hl(f.for_token(), f.label(), f.loop_body().and_then(|it| it.stmt_list()))
+            }
+            ast::Expr::WhileExpr(w) if label_matches(w.label()) => {
+                hl(w.while_token(), w.label(), w.loop_body().and_then(|it| it.stmt_list()))
+            }
             ast::Expr::BlockExpr(e) if e.label().is_some() && label_matches(e.label()) => {
-                hl(token_kind, None, e.label(), e.stmt_list())
+                hl(None, e.label(), e.stmt_list())
             }
             _ => continue,
         };
@@ -832,115 +804,6 @@ fn foo() {
         );
     }
 
-    #[test]
-    fn test_hl_break_for_but_not_continue() {
-        check(
-            r#"
-fn foo() {
-    'outer: for _ in () {
- // ^^^^^^^^^^^
-        break;
-     // ^^^^^
-        continue;
-        'inner: for _ in () {
-            break;
-            continue;
-            'innermost: for _ in () {
-                continue 'outer;
-                break 'outer;
-             // ^^^^^^^^^^^^
-                continue 'inner;
-                break 'inner;
-            }
-            break$0 'outer;
-         // ^^^^^^^^^^^^
-            continue 'outer;
-            break;
-            continue;
-        }
-        break;
-     // ^^^^^
-        continue;
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_hl_continue_for_but_not_break() {
-        check(
-            r#"
-fn foo() {
-    'outer: for _ in () {
- // ^^^^^^^^^^^
-        break;
-        continue;
-     // ^^^^^^^^
-        'inner: for _ in () {
-            break;
-            continue;
-            'innermost: for _ in () {
-                continue 'outer;
-             // ^^^^^^^^^^^^^^^
-                break 'outer;
-                continue 'inner;
-                break 'inner;
-            }
-            break 'outer;
-            continue$0 'outer;
-         // ^^^^^^^^^^^^^^^
-            break;
-            continue;
-        }
-        break;
-        continue;
-     // ^^^^^^^^
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn test_hl_break_and_continue() {
-        check(
-            r#"
-fn foo() {
-    'outer: fo$0r _ in () {
- // ^^^^^^^^^^^
-        break;
-     // ^^^^^
-        continue;
-     // ^^^^^^^^
-        'inner: for _ in () {
-            break;
-            continue;
-            'innermost: for _ in () {
-                continue 'outer;
-             // ^^^^^^^^^^^^^^^
-                break 'outer;
-             // ^^^^^^^^^^^^
-                continue 'inner;
-                break 'inner;
-            }
-            break 'outer;
-         // ^^^^^^^^^^^^
-            continue 'outer;
-         // ^^^^^^^^^^^^^^^
-            break;
-            continue;
-        }
-        break;
-     // ^^^^^
-        continue;
-     // ^^^^^^^^
-    }
-}
-"#,
-        );
-    }
-
     #[test]
     fn test_hl_break_while() {
         check(
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 ec8fbb4974..eeed0386ad 100644
--- a/crates/ide_assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
@@ -1,11 +1,11 @@
 use std::iter::{self, Peekable};
 
 use either::Either;
-use hir::{Adt, Crate, HasAttrs, HasSource, ModuleDef, Semantics};
+use hir::{Adt, HasSource, ModuleDef, Semantics};
 use ide_db::helpers::{mod_path_to_ast, FamousDefs};
 use ide_db::RootDatabase;
 use itertools::Itertools;
-use syntax::ast::{self, make, AstNode, HasName, MatchArmList, MatchExpr, Pat};
+use syntax::ast::{self, make, AstNode, HasName, MatchArm, MatchArmList, MatchExpr, Pat};
 
 use crate::{
     utils::{self, render_snippet, Cursor},
@@ -52,45 +52,36 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
 
     let expr = match_expr.expr()?;
 
-    let mut has_catch_all_arm = false;
+    let mut arms: Vec<MatchArm> = match_arm_list.arms().collect();
+    if let [arm] = arms.as_slice() {
+        if let Some(Pat::WildcardPat(..)) = arm.pat() {
+            arms.clear();
+        }
+    }
 
-    let top_lvl_pats: Vec<_> = match_arm_list
-        .arms()
-        .filter_map(|arm| Some((arm.pat()?, arm.guard().is_some())))
-        .flat_map(|(pat, has_guard)| {
-            match pat {
-                // Special case OrPat as separate top-level pats
-                Pat::OrPat(or_pat) => Either::Left(or_pat.pats()),
-                _ => Either::Right(iter::once(pat)),
-            }
-            .map(move |pat| (pat, has_guard))
-        })
-        .map(|(pat, has_guard)| {
-            has_catch_all_arm |= !has_guard && matches!(pat, Pat::WildcardPat(_));
-            pat
+    let top_lvl_pats: Vec<_> = arms
+        .iter()
+        .filter_map(ast::MatchArm::pat)
+        .flat_map(|pat| match pat {
+            // Special case OrPat as separate top-level pats
+            Pat::OrPat(or_pat) => Either::Left(or_pat.pats()),
+            _ => Either::Right(iter::once(pat)),
         })
         // Exclude top level wildcards so that they are expanded by this assist, retains status quo in #8129.
         .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
         .collect();
 
     let module = ctx.sema.scope(expr.syntax()).module()?;
-    let (mut missing_pats, is_non_exhaustive): (
-        Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
-        bool,
-    ) = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
-        let is_non_exhaustive = enum_def.is_non_exhaustive(ctx.db());
 
+    let mut missing_pats: Peekable<Box<dyn Iterator<Item = ast::Pat>>> = if let Some(enum_def) =
+        resolve_enum_def(&ctx.sema, &expr)
+    {
         let variants = enum_def.variants(ctx.db());
 
         let missing_pats = variants
             .into_iter()
-            .filter_map(|variant| {
-                Some((
-                    build_pat(ctx.db(), module, variant)?,
-                    variant.should_be_hidden(ctx.db(), module.krate()),
-                ))
-            })
-            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
+            .filter_map(|variant| build_pat(ctx.db(), module, variant))
+            .filter(|variant_pat| is_variant_missing(&top_lvl_pats, variant_pat));
 
         let option_enum =
             FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option().map(lift_enum);
@@ -101,11 +92,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
         } else {
             Box::new(missing_pats)
         };
-        (missing_pats.peekable(), is_non_exhaustive)
+        missing_pats.peekable()
     } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
-        let is_non_exhaustive =
-            enum_defs.iter().any(|enum_def| enum_def.is_non_exhaustive(ctx.db()));
-
         let mut n_arms = 1;
         let variants_of_enums: Vec<Vec<ExtendedVariant>> = enum_defs
             .into_iter()
@@ -129,23 +117,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
             .multi_cartesian_product()
             .inspect(|_| cov_mark::hit!(add_missing_match_arms_lazy_computation))
             .map(|variants| {
-                let is_hidden = variants
-                    .iter()
-                    .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
                 let patterns =
                     variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
-
-                (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
+                ast::Pat::from(make::tuple_pat(patterns))
             })
-            .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
-        ((Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable(), is_non_exhaustive)
+            .filter(|variant_pat| is_variant_missing(&top_lvl_pats, variant_pat));
+        (Box::new(missing_pats) as Box<dyn Iterator<Item = _>>).peekable()
     } else {
         return None;
     };
 
-    let mut needs_catch_all_arm = is_non_exhaustive && !has_catch_all_arm;
-
-    if !needs_catch_all_arm && missing_pats.peek().is_none() {
+    if missing_pats.peek().is_none() {
         return None;
     }
 
@@ -156,10 +138,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
         |builder| {
             let new_match_arm_list = match_arm_list.clone_for_update();
             let missing_arms = missing_pats
-                .map(|(pat, hidden)| {
-                    (make::match_arm(iter::once(pat), None, make::ext::expr_todo()), hidden)
-                })
-                .map(|(it, hidden)| (it.clone_for_update(), hidden));
+                .map(|pat| make::match_arm(iter::once(pat), None, make::ext::expr_todo()))
+                .map(|it| it.clone_for_update());
 
             let catch_all_arm = new_match_arm_list
                 .arms()
@@ -179,22 +159,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
                 }
             }
             let mut first_new_arm = None;
-            for (arm, hidden) in missing_arms {
-                if hidden {
-                    needs_catch_all_arm = !has_catch_all_arm;
-                } else {
-                    first_new_arm.get_or_insert_with(|| arm.clone());
-                    new_match_arm_list.add_arm(arm);
-                }
-            }
-            if needs_catch_all_arm && !has_catch_all_arm {
-                cov_mark::hit!(added_wildcard_pattern);
-                let arm = make::match_arm(
-                    iter::once(make::wildcard_pat().into()),
-                    None,
-                    make::ext::expr_todo(),
-                )
-                .clone_for_update();
+            for arm in missing_arms {
                 first_new_arm.get_or_insert_with(|| arm.clone());
                 new_match_arm_list.add_arm(arm);
             }
@@ -285,29 +250,11 @@ enum ExtendedVariant {
     Variant(hir::Variant),
 }
 
-impl ExtendedVariant {
-    fn should_be_hidden(self, db: &RootDatabase, krate: Crate) -> bool {
-        match self {
-            ExtendedVariant::Variant(var) => {
-                var.attrs(db).has_doc_hidden() && var.module(db).krate() != krate
-            }
-            _ => false,
-        }
-    }
-}
-
 fn lift_enum(e: hir::Enum) -> ExtendedEnum {
     ExtendedEnum::Enum(e)
 }
 
 impl ExtendedEnum {
-    fn is_non_exhaustive(self, db: &RootDatabase) -> bool {
-        match self {
-            ExtendedEnum::Enum(e) => e.attrs(db).by_key("non_exhaustive").exists(),
-            _ => false,
-        }
-    }
-
     fn variants(self, db: &RootDatabase) -> Vec<ExtendedVariant> {
         match self {
             ExtendedEnum::Enum(e) => {
@@ -1333,352 +1280,6 @@ fn foo(t: bool) {
         $0true => todo!(),
         false => todo!(),
     }
-}"#,
-        );
-    }
-
-    #[test]
-    fn does_not_fill_hidden_variants() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-    }
-}
-//- /e.rs crate:e
-pub enum E { A, #[doc(hidden)] B, }
-"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        $0e::E::A => todo!(),
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn does_not_fill_hidden_variants_tuple() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: (bool, ::e::E)) {
-    match $0t {
-    }
-}
-//- /e.rs crate:e
-pub enum E { A, #[doc(hidden)] B, }
-"#,
-            r#"
-fn foo(t: (bool, ::e::E)) {
-    match t {
-        $0(true, e::E::A) => todo!(),
-        (false, e::E::A) => todo!(),
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn fills_wildcard_with_only_hidden_variants() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-    }
-}
-//- /e.rs crate:e
-pub enum E { #[doc(hidden)] A, }
-"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        ${0:_} => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn does_not_fill_wildcard_when_hidden_variants_are_explicit() {
-        check_assist_not_applicable(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-        e::E::A => todo!(),
-    }
-}
-//- /e.rs crate:e
-pub enum E { #[doc(hidden)] A, }
-"#,
-        );
-    }
-
-    // FIXME: I don't think the assist should be applicable in this case
-    #[test]
-    fn does_not_fill_wildcard_with_wildcard() {
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-        _ => todo!(),
-    }
-}
-//- /e.rs crate:e
-pub enum E { #[doc(hidden)] A, }
-"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn fills_wildcard_on_non_exhaustive_with_explicit_matches() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-        e::E::A => todo!(),
-    }
-}
-//- /e.rs crate:e
-#[non_exhaustive]
-pub enum E { A, }
-"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        e::E::A => todo!(),
-        ${0:_} => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn fills_wildcard_on_non_exhaustive_without_matches() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-    }
-}
-//- /e.rs crate:e
-#[non_exhaustive]
-pub enum E { A, }
-"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        $0e::E::A => todo!(),
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn fills_wildcard_on_non_exhaustive_with_doc_hidden() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-    }
-}
-//- /e.rs crate:e
-#[non_exhaustive]
-pub enum E { A, #[doc(hidden)] B }"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        $0e::E::A => todo!(),
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn fills_wildcard_on_non_exhaustive_with_doc_hidden_with_explicit_arms() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-        e::E::A => todo!(),
-    }
-}
-//- /e.rs crate:e
-#[non_exhaustive]
-pub enum E { A, #[doc(hidden)] B }"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        e::E::A => todo!(),
-        ${0:_} => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn fill_wildcard_with_partial_wildcard() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E, b: bool) {
-    match $0t {
-        _ if b => todo!(),
-    }
-}
-//- /e.rs crate:e
-pub enum E { #[doc(hidden)] A, }"#,
-            r#"
-fn foo(t: ::e::E, b: bool) {
-    match t {
-        _ if b => todo!(),
-        ${0:_} => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn does_not_fill_wildcard_with_partial_wildcard_and_wildcard() {
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E, b: bool) {
-    match $0t {
-        _ if b => todo!(),
-        _ => todo!(),
-    }
-}
-//- /e.rs crate:e
-pub enum E { #[doc(hidden)] A, }"#,
-            r#"
-fn foo(t: ::e::E, b: bool) {
-    match t {
-        _ if b => todo!(),
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn non_exhaustive_doc_hidden_tuple_fills_wildcard() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-//- /main.rs crate:main deps:e
-fn foo(t: ::e::E) {
-    match $0t {
-    }
-}
-//- /e.rs crate:e
-#[non_exhaustive]
-pub enum E { A, #[doc(hidden)] B, }"#,
-            r#"
-fn foo(t: ::e::E) {
-    match t {
-        $0e::E::A => todo!(),
-        _ => todo!(),
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn ignores_doc_hidden_for_crate_local_enums() {
-        check_assist(
-            add_missing_match_arms,
-            r#"
-enum E { A, #[doc(hidden)] B, }
-
-fn foo(t: E) {
-    match $0t {
-    }
-}"#,
-            r#"
-enum E { A, #[doc(hidden)] B, }
-
-fn foo(t: E) {
-    match t {
-        $0E::A => todo!(),
-        E::B => todo!(),
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn ignores_doc_hidden_for_crate_local_enums_but_not_non_exhaustive() {
-        cov_mark::check!(added_wildcard_pattern);
-        check_assist(
-            add_missing_match_arms,
-            r#"
-#[non_exhaustive]
-enum E { A, #[doc(hidden)] B, }
-
-fn foo(t: E) {
-    match $0t {
-    }
-}"#,
-            r#"
-#[non_exhaustive]
-enum E { A, #[doc(hidden)] B, }
-
-fn foo(t: E) {
-    match t {
-        $0E::A => todo!(),
-        E::B => todo!(),
-        _ => todo!(),
-    }
 }"#,
         );
     }
diff --git a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
index 4a4ad984db..0d2daa8dc3 100644
--- a/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
+++ b/crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs
@@ -154,11 +154,11 @@ fn is_ref_and_impls_iter_method(
     let has_wanted_method = ty
         .iterate_method_candidates(
             sema.db,
-            &scope,
+            krate,
             &traits_in_scope,
             None,
             Some(&wanted_method),
-            |func| {
+            |_, func| {
                 if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) {
                     return Some(());
                 }
diff --git a/crates/ide_assists/src/handlers/destructure_tuple_binding.rs b/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
index ac17e3f057..5f361f01dc 100644
--- a/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
+++ b/crates/ide_assists/src/handlers/destructure_tuple_binding.rs
@@ -371,7 +371,7 @@ fn handle_ref_field_usage(ctx: &AssistContext, field_expr: &FieldExpr) -> RefDat
             fn is_auto_ref(ctx: &AssistContext, call_expr: &MethodCallExpr) -> bool {
                 fn impl_(ctx: &AssistContext, call_expr: &MethodCallExpr) -> Option<bool> {
                     let rec = call_expr.receiver()?;
-                    let rec_ty = ctx.sema.type_of_expr(&rec)?.original();
+                    let rec_ty = ctx.sema.type_of_expr(&rec)?.adjusted();
                     // input must be actual value
                     if rec_ty.is_reference() {
                         return Some(false);
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
index db0cfbe2ec..cb3fbed219 100644
--- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -90,9 +90,10 @@ fn get_impl_method(
     let impl_def: hir::Impl = ctx.sema.to_def(impl_)?;
 
     let scope = ctx.sema.scope(impl_.syntax());
+    let krate = impl_def.module(db).krate();
     let ty = impl_def.self_ty(db);
     let traits_in_scope = scope.visible_traits();
-    ty.iterate_method_candidates(db, &scope, &traits_in_scope, None, Some(fn_name), |func| {
+    ty.iterate_method_candidates(db, krate, &traits_in_scope, None, Some(fn_name), |_, func| {
         Some(func)
     })
 }
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 981e25b55c..3bb3f883cd 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -74,28 +74,30 @@ fn complete_methods(
     receiver: &hir::Type,
     mut f: impl FnMut(hir::Function),
 ) {
-    let mut seen_methods = FxHashSet::default();
-    let mut traits_in_scope = ctx.scope.visible_traits();
-
-    // Remove drop from the environment as calling `Drop::drop` is not allowed
-    if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
-        cov_mark::hit!(dot_remove_drop_trait);
-        traits_in_scope.remove(&drop_trait.into());
-    }
-
-    receiver.iterate_method_candidates(
-        ctx.db,
-        &ctx.scope,
-        &traits_in_scope,
-        ctx.module,
-        None,
-        |func| {
-            if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
-                f(func);
-            }
-            None::<()>
-        },
-    );
+    if let Some(krate) = ctx.krate {
+        let mut seen_methods = FxHashSet::default();
+        let mut traits_in_scope = ctx.scope.visible_traits();
+
+        // Remove drop from the environment as calling `Drop::drop` is not allowed
+        if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
+            cov_mark::hit!(dot_remove_drop_trait);
+            traits_in_scope.remove(&drop_trait.into());
+        }
+
+        receiver.iterate_method_candidates(
+            ctx.db,
+            krate,
+            &traits_in_scope,
+            ctx.module,
+            None,
+            |_ty, func| {
+                if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
+                    f(func);
+                }
+                None::<()>
+            },
+        );
+    }
 }
 
 #[cfg(test)]
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index c8a9cf21da..f1b4fa7205 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -134,37 +134,39 @@ fn pattern_path_completion(
                         .for_each(|variant| acc.add_enum_variant(ctx, variant, None));
                 }
                 res @ (hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_)) => {
-                    let ty = match res {
-                        hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
-                        hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
-                        _ => return,
-                    };
+                    if let Some(krate) = ctx.krate {
+                        let ty = match res {
+                            hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+                            hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+                            _ => return,
+                        };
 
-                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
-                        e.variants(ctx.db)
-                            .into_iter()
-                            .for_each(|variant| acc.add_enum_variant(ctx, variant, None));
-                    }
+                        if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                            e.variants(ctx.db)
+                                .into_iter()
+                                .for_each(|variant| acc.add_enum_variant(ctx, variant, None));
+                        }
 
-                    let traits_in_scope = ctx.scope.visible_traits();
-                    let mut seen = FxHashSet::default();
-                    ty.iterate_path_candidates(
-                        ctx.db,
-                        &ctx.scope,
-                        &traits_in_scope,
-                        ctx.module,
-                        None,
-                        |item| {
-                            // Note associated consts cannot be referenced in patterns
-                            if let AssocItem::TypeAlias(ta) = item {
-                                // We might iterate candidates of a trait multiple times here, so deduplicate them.
-                                if seen.insert(item) {
-                                    acc.add_type_alias(ctx, ta);
+                        let traits_in_scope = ctx.scope.visible_traits();
+                        let mut seen = FxHashSet::default();
+                        ty.iterate_path_candidates(
+                            ctx.db,
+                            krate,
+                            &traits_in_scope,
+                            ctx.module,
+                            None,
+                            |_ty, item| {
+                                // Note associated consts cannot be referenced in patterns
+                                if let AssocItem::TypeAlias(ta) = item {
+                                    // We might iterate candidates of a trait multiple times here, so deduplicate them.
+                                    if seen.insert(item) {
+                                        acc.add_type_alias(ctx, ta);
+                                    }
                                 }
-                            }
-                            None::<()>
-                        },
-                    );
+                                None::<()>
+                            },
+                        );
+                    }
                 }
                 _ => {}
             }
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index d63aacbadb..cf78f7c1ad 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -138,11 +138,11 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
                 let traits_in_scope = ctx.scope.visible_traits();
                 ty.iterate_path_candidates(
                     ctx.db,
-                    &ctx.scope,
+                    krate,
                     &traits_in_scope,
                     ctx.module,
                     None,
-                    |item| {
+                    |_ty, item| {
                         add_assoc_item(acc, ctx, item);
                         None::<()>
                     },
@@ -164,33 +164,35 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
             }
         }
         hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_) => {
-            let ty = match resolution {
-                hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
-                hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
-                _ => return,
-            };
+            if let Some(krate) = ctx.krate {
+                let ty = match resolution {
+                    hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
+                    hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
+                    _ => return,
+                };
 
-            if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
-                add_enum_variants(acc, ctx, e);
-            }
+                if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                    add_enum_variants(acc, ctx, e);
+                }
 
-            let traits_in_scope = ctx.scope.visible_traits();
-            let mut seen = FxHashSet::default();
-            ty.iterate_path_candidates(
-                ctx.db,
-                &ctx.scope,
-                &traits_in_scope,
-                ctx.module,
-                None,
-                |item| {
-                    // We might iterate candidates of a trait multiple times here, so deduplicate
-                    // them.
-                    if seen.insert(item) {
-                        add_assoc_item(acc, ctx, item);
-                    }
-                    None::<()>
-                },
-            );
+                let traits_in_scope = ctx.scope.visible_traits();
+                let mut seen = FxHashSet::default();
+                ty.iterate_path_candidates(
+                    ctx.db,
+                    krate,
+                    &traits_in_scope,
+                    ctx.module,
+                    None,
+                    |_ty, item| {
+                        // We might iterate candidates of a trait multiple times here, so deduplicate
+                        // them.
+                        if seen.insert(item) {
+                            add_assoc_item(acc, ctx, item);
+                        }
+                        None::<()>
+                    },
+                );
+            }
         }
         _ => {}
     }
diff --git a/crates/ide_completion/src/config.rs b/crates/ide_completion/src/config.rs
index 5e5c7efdfb..c4e91e7283 100644
--- a/crates/ide_completion/src/config.rs
+++ b/crates/ide_completion/src/config.rs
@@ -13,6 +13,7 @@ pub struct CompletionConfig {
     pub enable_postfix_completions: bool,
     pub enable_imports_on_the_fly: bool,
     pub enable_self_on_the_fly: bool,
+    pub enable_private_editable: bool,
     pub add_call_parenthesis: bool,
     pub add_call_argument_snippets: bool,
     pub snippet_cap: Option<SnippetCap>,
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index e986c28b14..c4e145ffcb 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -360,6 +360,9 @@ impl<'a> CompletionContext<'a> {
             None => return Visible::No,
         };
         if !vis.is_visible_from(self.db, module.into()) {
+            if !self.config.enable_private_editable {
+                return Visible::No;
+            }
             // If the definition location is editable, also show private items
             let root_file = defining_crate.root_file(self.db);
             let source_root_id = self.db.file_source_root(root_file);
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 08530f84fb..08104efcdc 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -206,23 +206,8 @@ impl NameClass {
 
         let parent = name.syntax().parent()?;
 
-        let definition = match_ast! {
-            match parent {
-                ast::Item(it) => classify_item(sema, it)?,
-                ast::IdentPat(it) => return classify_ident_pat(sema, it),
-                ast::Rename(it) => classify_rename(sema, it)?,
-                ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?),
-                ast::RecordField(it) => Definition::Field(sema.to_def(&it)?),
-                ast::Variant(it) => Definition::Variant(sema.to_def(&it)?),
-                ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
-                ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
-                _ => return None,
-            }
-        };
-        return Some(NameClass::Definition(definition));
-
-        fn classify_item(sema: &Semantics<RootDatabase>, item: ast::Item) -> Option<Definition> {
-            let definition = match item {
+        let def = if let Some(item) = ast::Item::cast(parent.clone()) {
+            match item {
                 ast::Item::MacroRules(it) => {
                     Definition::Macro(sema.to_def(&ast::Macro::MacroRules(it))?)
                 }
@@ -244,20 +229,14 @@ impl NameClass {
                 ast::Item::Struct(it) => Definition::Adt(hir::Adt::Struct(sema.to_def(&it)?)),
                 ast::Item::Union(it) => Definition::Adt(hir::Adt::Union(sema.to_def(&it)?)),
                 _ => return None,
-            };
-            Some(definition)
-        }
-
-        fn classify_ident_pat(
-            sema: &Semantics<RootDatabase>,
-            ident_pat: ast::IdentPat,
-        ) -> Option<NameClass> {
-            if let Some(def) = sema.resolve_bind_pat_to_const(&ident_pat) {
+            }
+        } else if let Some(it) = ast::IdentPat::cast(parent.clone()) {
+            if let Some(def) = sema.resolve_bind_pat_to_const(&it) {
                 return Some(NameClass::ConstReference(Definition::from(def)));
             }
 
-            let local = sema.to_def(&ident_pat)?;
-            let pat_parent = ident_pat.syntax().parent();
+            let local = sema.to_def(&it)?;
+            let pat_parent = it.syntax().parent();
             if let Some(record_pat_field) = pat_parent.and_then(ast::RecordPatField::cast) {
                 if record_pat_field.name_ref().is_none() {
                     if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
@@ -268,23 +247,57 @@ impl NameClass {
                     }
                 }
             }
-            Some(NameClass::Definition(Definition::Local(local)))
-        }
 
-        fn classify_rename(
-            sema: &Semantics<RootDatabase>,
-            rename: ast::Rename,
-        ) -> Option<Definition> {
-            if let Some(use_tree) = rename.syntax().parent().and_then(ast::UseTree::cast) {
+            Definition::Local(local)
+        } else if let Some(it) = ast::Rename::cast(parent.clone()) {
+            if let Some(use_tree) = it.syntax().parent().and_then(ast::UseTree::cast) {
                 let path = use_tree.path()?;
-                sema.resolve_path(&path).map(Definition::from)
+                let path_segment = path.segment()?;
+                let name_ref = path_segment.name_ref()?;
+                let name_ref = if name_ref.self_token().is_some() {
+                    use_tree
+                        .syntax()
+                        .parent()
+                        .as_ref()
+                        // Skip over UseTreeList
+                        .and_then(|it| {
+                            let use_tree = it.parent().and_then(ast::UseTree::cast)?;
+                            let path = use_tree.path()?;
+                            let path_segment = path.segment()?;
+                            path_segment.name_ref()
+                        })
+                        .unwrap_or(name_ref)
+                } else {
+                    name_ref
+                };
+                let name_ref_class = NameRefClass::classify(sema, &name_ref)?;
+
+                match name_ref_class {
+                    NameRefClass::Definition(def) => def,
+                    NameRefClass::FieldShorthand { local_ref: _, field_ref } => {
+                        Definition::Field(field_ref)
+                    }
+                }
             } else {
-                let extern_crate = rename.syntax().parent().and_then(ast::ExternCrate::cast)?;
+                let extern_crate = it.syntax().parent().and_then(ast::ExternCrate::cast)?;
                 let krate = sema.resolve_extern_crate(&extern_crate)?;
                 let root_module = krate.root_module(sema.db);
-                Some(Definition::Module(root_module))
+                Definition::Module(root_module)
             }
-        }
+        } else {
+            match_ast! {
+                match parent {
+                    ast::SelfParam(it) => Definition::Local(sema.to_def(&it)?),
+                    ast::RecordField(it) => Definition::Field(sema.to_def(&it)?),
+                    ast::Variant(it) => Definition::Variant(sema.to_def(&it)?),
+                    ast::TypeParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
+                    ast::ConstParam(it) => Definition::GenericParam(sema.to_def(&it)?.into()),
+                    _ => return None,
+                }
+            }
+        };
+
+        Some(NameClass::Definition(def))
     }
 
     pub fn classify_lifetime(
@@ -294,14 +307,19 @@ impl NameClass {
         let _p = profile::span("classify_lifetime").detail(|| lifetime.to_string());
         let parent = lifetime.syntax().parent()?;
 
-        if let Some(it) = ast::LifetimeParam::cast(parent.clone()) {
-            sema.to_def(&it).map(Into::into).map(Definition::GenericParam)
-        } else if let Some(it) = ast::Label::cast(parent.clone()) {
-            sema.to_def(&it).map(Definition::Label)
-        } else {
-            None
+        match_ast! {
+            match parent {
+                ast::LifetimeParam(it) => {
+                    let def = sema.to_def(&it)?;
+                    Some(NameClass::Definition(Definition::GenericParam(def.into())))
+                },
+                ast::Label(it) => {
+                    let def = sema.to_def(&it)?;
+                    Some(NameClass::Definition(Definition::Label(def)))
+                },
+                _ => None,
+            }
         }
-        .map(NameClass::Definition)
     }
 }
 
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index fcad172984..cbe4adf1b9 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -16,8 +16,7 @@ use hir::{ItemInNs, MacroDef, ModuleDef, Name, Semantics};
 use itertools::Itertools;
 use syntax::{
     ast::{self, make, HasLoopBody},
-    AstNode, AstToken, Preorder, RustLanguage, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent,
-    T,
+    AstNode, AstToken, SyntaxKind, SyntaxToken, TokenAtOffset, WalkEvent, T,
 };
 
 use crate::{defs::Definition, RootDatabase};
@@ -191,102 +190,46 @@ pub fn for_each_tail_expr(expr: &ast::Expr, cb: &mut dyn FnMut(&ast::Expr)) {
     }
 }
 
-pub fn for_each_break_and_continue_expr(
-    label: Option<ast::Label>,
-    body: Option<ast::StmtList>,
-    cb: &mut dyn FnMut(ast::Expr),
-) {
-    let label = label.and_then(|lbl| lbl.lifetime());
-    if let Some(b) = body {
-        let tree_depth_iterator = TreeWithDepthIterator::new(b);
-        for (expr, depth) in tree_depth_iterator {
-            match expr {
-                ast::Expr::BreakExpr(b)
-                    if (depth == 0 && b.lifetime().is_none())
-                        || eq_label_lt(&label, &b.lifetime()) =>
-                {
-                    cb(ast::Expr::BreakExpr(b));
-                }
-                ast::Expr::ContinueExpr(c)
-                    if (depth == 0 && c.lifetime().is_none())
-                        || eq_label_lt(&label, &c.lifetime()) =>
-                {
-                    cb(ast::Expr::ContinueExpr(c));
-                }
-                _ => (),
-            }
-        }
-    }
-}
-
-fn for_each_break_expr(
+/// Calls `cb` on each break expr inside of `body` that is applicable for the given label.
+pub fn for_each_break_expr(
     label: Option<ast::Label>,
     body: Option<ast::StmtList>,
     cb: &mut dyn FnMut(ast::BreakExpr),
 ) {
     let label = label.and_then(|lbl| lbl.lifetime());
+    let mut depth = 0;
     if let Some(b) = body {
-        let tree_depth_iterator = TreeWithDepthIterator::new(b);
-        for (expr, depth) in tree_depth_iterator {
-            match expr {
-                ast::Expr::BreakExpr(b)
-                    if (depth == 0 && b.lifetime().is_none())
-                        || eq_label_lt(&label, &b.lifetime()) =>
-                {
-                    cb(b);
-                }
-                _ => (),
-            }
-        }
-    }
-}
-
-fn eq_label_lt(lt1: &Option<ast::Lifetime>, lt2: &Option<ast::Lifetime>) -> bool {
-    lt1.as_ref().zip(lt2.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
-}
-
-struct TreeWithDepthIterator {
-    preorder: Preorder<RustLanguage>,
-    depth: u32,
-}
-
-impl TreeWithDepthIterator {
-    fn new(body: ast::StmtList) -> Self {
-        let preorder = body.syntax().preorder();
-        Self { preorder, depth: 0 }
-    }
-}
-
-impl<'a> Iterator for TreeWithDepthIterator {
-    type Item = (ast::Expr, u32);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        while let Some(event) = self.preorder.find_map(|ev| match ev {
-            WalkEvent::Enter(it) => ast::Expr::cast(it).map(WalkEvent::Enter),
-            WalkEvent::Leave(it) => ast::Expr::cast(it).map(WalkEvent::Leave),
-        }) {
-            match event {
-                WalkEvent::Enter(
-                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
-                ) => {
-                    self.depth += 1;
-                }
-                WalkEvent::Leave(
-                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_),
-                ) => {
-                    self.depth -= 1;
-                }
-                WalkEvent::Enter(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
-                    self.depth += 1;
-                }
-                WalkEvent::Leave(ast::Expr::BlockExpr(e)) if e.label().is_some() => {
-                    self.depth -= 1;
-                }
-                WalkEvent::Enter(expr) => return Some((expr, self.depth)),
-                _ => (),
+        let preorder = &mut b.syntax().preorder();
+        let ev_as_expr = |ev| match ev {
+            WalkEvent::Enter(it) => Some(WalkEvent::Enter(ast::Expr::cast(it)?)),
+            WalkEvent::Leave(it) => Some(WalkEvent::Leave(ast::Expr::cast(it)?)),
+        };
+        let eq_label = |lt: Option<ast::Lifetime>| {
+            lt.zip(label.as_ref()).map_or(false, |(lt, lbl)| lt.text() == lbl.text())
+        };
+        while let Some(node) = preorder.find_map(ev_as_expr) {
+            match node {
+                WalkEvent::Enter(expr) => match expr {
+                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
+                        depth += 1
+                    }
+                    ast::Expr::BlockExpr(e) if e.label().is_some() => depth += 1,
+                    ast::Expr::BreakExpr(b)
+                        if (depth == 0 && b.lifetime().is_none()) || eq_label(b.lifetime()) =>
+                    {
+                        cb(b);
+                    }
+                    _ => (),
+                },
+                WalkEvent::Leave(expr) => match expr {
+                    ast::Expr::LoopExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::ForExpr(_) => {
+                        depth -= 1
+                    }
+                    ast::Expr::BlockExpr(e) if e.label().is_some() => depth -= 1,
+                    _ => (),
+                },
             }
         }
-        None
     }
 }
 
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index d91627e0a9..319a217352 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -1,7 +1,7 @@
 //! Look up accessible paths for items.
 use hir::{
     AsAssocItem, AssocItem, AssocItemContainer, Crate, ItemInNs, MacroDef, ModPath, Module,
-    ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Type,
+    ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, Type,
 };
 use itertools::Itertools;
 use rustc_hash::FxHashSet;
@@ -239,6 +239,7 @@ impl ImportAssets {
         let _p = profile::span("import_assets::search_for");
 
         let scope_definitions = self.scope_definitions(sema);
+        let current_crate = self.module_with_candidate.krate();
         let mod_path = |item| {
             get_mod_path(
                 sema.db,
@@ -248,18 +249,15 @@ impl ImportAssets {
             )
         };
 
-        let krate = self.module_with_candidate.krate();
-        let scope = sema.scope(&self.candidate_node);
-
         match &self.import_candidate {
             ImportCandidate::Path(path_candidate) => {
-                path_applicable_imports(sema, krate, path_candidate, mod_path)
+                path_applicable_imports(sema, current_crate, path_candidate, mod_path)
             }
             ImportCandidate::TraitAssocItem(trait_candidate) => {
-                trait_applicable_items(sema, krate, &scope, trait_candidate, true, mod_path)
+                trait_applicable_items(sema, current_crate, trait_candidate, true, mod_path)
             }
             ImportCandidate::TraitMethod(trait_candidate) => {
-                trait_applicable_items(sema, krate, &scope, trait_candidate, false, mod_path)
+                trait_applicable_items(sema, current_crate, trait_candidate, false, mod_path)
             }
         }
         .into_iter()
@@ -449,7 +447,6 @@ fn module_with_segment_name(
 fn trait_applicable_items(
     sema: &Semantics<RootDatabase>,
     current_crate: Crate,
-    scope: &SemanticsScope,
     trait_candidate: &TraitImportCandidate,
     trait_assoc_item: bool,
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
@@ -487,11 +484,11 @@ fn trait_applicable_items(
     if trait_assoc_item {
         trait_candidate.receiver_ty.iterate_path_candidates(
             db,
-            scope,
+            current_crate,
             &trait_candidates,
             None,
             None,
-            |assoc| {
+            |_, assoc| {
                 if required_assoc_items.contains(&assoc) {
                     if let AssocItem::Function(f) = assoc {
                         if f.self_param(db).is_some() {
@@ -514,11 +511,11 @@ fn trait_applicable_items(
     } else {
         trait_candidate.receiver_ty.iterate_method_candidates(
             db,
-            scope,
+            current_crate,
             &trait_candidates,
             None,
             None,
-            |function| {
+            |_, function| {
                 let assoc = function.as_assoc_item(db)?;
                 if required_assoc_items.contains(&assoc) {
                     let located_trait = assoc.containing_trait(db)?;
diff --git a/crates/ide_ssr/src/resolving.rs b/crates/ide_ssr/src/resolving.rs
index e15cb874ef..844b19779a 100644
--- a/crates/ide_ssr/src/resolving.rs
+++ b/crates/ide_ssr/src/resolving.rs
@@ -222,11 +222,11 @@ impl<'db> ResolutionScope<'db> {
             let module = self.scope.module()?;
             adt.ty(self.scope.db).iterate_path_candidates(
                 self.scope.db,
-                &self.scope,
+                module.krate(),
                 &self.scope.visible_traits(),
                 Some(module),
                 None,
-                |assoc_item| {
+                |_ty, assoc_item| {
                     let item_name = assoc_item.name(self.scope.db)?;
                     if item_name.to_smol_str().as_str() == name.text() {
                         Some(hir::PathResolution::AssocItem(assoc_item))
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index f52e1e7512..55a542c3c1 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -10,11 +10,7 @@ use hir::{
     db::{AstDatabase, DefDatabase, HirDatabase},
     AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
 };
-use hir_def::{
-    body::{BodySourceMap, SyntheticSyntax},
-    expr::ExprId,
-    FunctionId,
-};
+use hir_def::{body::BodySourceMap, expr::ExprId, FunctionId};
 use hir_ty::{TyExt, TypeWalk};
 use ide::{Analysis, AnalysisHost, LineCol, RootDatabase};
 use ide_db::base_db::{
@@ -32,7 +28,7 @@ use syntax::{AstNode, SyntaxNode};
 use vfs::{AbsPathBuf, Vfs, VfsPath};
 
 use crate::cli::{
-    flags::{self, OutputFormat},
+    flags,
     load_cargo::{load_workspace, LoadCargoConfig},
     print_memory_usage,
     progress_report::ProgressReport,
@@ -195,7 +191,7 @@ impl flags::AnalysisStats {
     ) {
         let mut bar = match verbosity {
             Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
-            _ if self.parallel || self.output.is_some() => ProgressReport::hidden(),
+            _ if self.parallel => ProgressReport::hidden(),
             _ => ProgressReport::new(funcs.len() as u64),
         };
 
@@ -256,7 +252,7 @@ impl flags::AnalysisStats {
             for (expr_id, _) in body.exprs.iter() {
                 let ty = &inference_result[expr_id];
                 num_exprs += 1;
-                let unknown_or_partial = if ty.is_unknown() {
+                if ty.is_unknown() {
                     num_exprs_unknown += 1;
                     if verbosity.is_spammy() {
                         if let Some((path, start, end)) =
@@ -274,7 +270,6 @@ impl flags::AnalysisStats {
                             bar.println(format!("{}: Unknown type", name,));
                         }
                     }
-                    true
                 } else {
                     let mut is_partially_unknown = false;
                     ty.walk(&mut |ty| {
@@ -285,8 +280,7 @@ impl flags::AnalysisStats {
                     if is_partially_unknown {
                         num_exprs_partially_unknown += 1;
                     }
-                    is_partially_unknown
-                };
+                }
                 if self.only.is_some() && verbosity.is_spammy() {
                     // in super-verbose mode for just one function, we print every single expression
                     if let Some((_, start, end)) =
@@ -304,13 +298,6 @@ impl flags::AnalysisStats {
                         bar.println(format!("unknown location: {}", ty.display(db)));
                     }
                 }
-                if unknown_or_partial && self.output == Some(OutputFormat::Csv) {
-                    println!(
-                        r#"{},type,"{}""#,
-                        location_csv(db, &analysis, vfs, &sm, expr_id),
-                        ty.display(db)
-                    );
-                }
                 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
                     num_type_mismatches += 1;
                     if verbosity.is_verbose() {
@@ -336,14 +323,6 @@ impl flags::AnalysisStats {
                             ));
                         }
                     }
-                    if self.output == Some(OutputFormat::Csv) {
-                        println!(
-                            r#"{},mismatch,"{}","{}""#,
-                            location_csv(db, &analysis, vfs, &sm, expr_id),
-                            mismatch.expected.display(db),
-                            mismatch.actual.display(db)
-                        );
-                    }
                 }
             }
             if verbosity.is_spammy() {
@@ -379,28 +358,6 @@ impl flags::AnalysisStats {
     }
 }
 
-fn location_csv(
-    db: &RootDatabase,
-    analysis: &Analysis,
-    vfs: &Vfs,
-    sm: &BodySourceMap,
-    expr_id: ExprId,
-) -> String {
-    let src = match sm.expr_syntax(expr_id) {
-        Ok(s) => s,
-        Err(SyntheticSyntax) => return "synthetic,,".to_string(),
-    };
-    let root = db.parse_or_expand(src.file_id).unwrap();
-    let node = src.map(|e| e.to_node(&root).syntax().clone());
-    let original_range = node.as_ref().original_file_range(db);
-    let path = vfs.file_path(original_range.file_id);
-    let line_index = analysis.file_line_index(original_range.file_id).unwrap();
-    let text_range = original_range.range;
-    let (start, end) =
-        (line_index.line_col(text_range.start()), line_index.line_col(text_range.end()));
-    format!("{},{}:{},{}:{}", path, start.line + 1, start.col, end.line + 1, end.col)
-}
-
 fn expr_syntax_range(
     db: &RootDatabase,
     analysis: &Analysis,
diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs
index 19907ebddb..b759d912c9 100644
--- a/crates/rust-analyzer/src/cli/flags.rs
+++ b/crates/rust-analyzer/src/cli/flags.rs
@@ -1,6 +1,6 @@
 //! Grammar for the command-line arguments.
 #![allow(unreachable_pub)]
-use std::{path::PathBuf, str::FromStr};
+use std::path::PathBuf;
 
 use ide_ssr::{SsrPattern, SsrRule};
 
@@ -54,8 +54,6 @@ xflags::xflags! {
             /// Directory with Cargo.toml.
             required path: PathBuf
         {
-            optional --output format: OutputFormat
-
             /// Randomize order in which crates, modules, and items are processed.
             optional --randomize
             /// Run type inference in parallel.
@@ -162,7 +160,6 @@ pub struct Highlight {
 pub struct AnalysisStats {
     pub path: PathBuf,
 
-    pub output: Option<OutputFormat>,
     pub randomize: bool,
     pub parallel: bool,
     pub memory_usage: bool,
@@ -218,11 +215,6 @@ impl RustAnalyzer {
 }
 // generated end
 
-#[derive(Debug, PartialEq, Eq)]
-pub enum OutputFormat {
-    Csv,
-}
-
 impl RustAnalyzer {
     pub fn verbosity(&self) -> Verbosity {
         if self.quiet {
@@ -235,14 +227,3 @@ impl RustAnalyzer {
         }
     }
 }
-
-impl FromStr for OutputFormat {
-    type Err = String;
-
-    fn from_str(s: &str) -> Result<Self, Self::Err> {
-        match s {
-            "csv" => Ok(Self::Csv),
-            _ => Err(format!("unknown output format `{}`", s)),
-        }
-    }
-}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 76b7270797..af779ee000 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -161,13 +161,15 @@ config_data! {
             }
         }"#,
         /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
-        completion_postfix_enable: bool          = "true",
+        completion_postfix_enable: bool         = "true",
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = "true",
         /// Toggles the additional completions that automatically show method calls and field accesses
         /// with `self` prefixed to them when inside a method.
-        completion_autoself_enable: bool       = "true",
+        completion_autoself_enable: bool        = "true",
+        /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
+        completion_privateEditable_enable: bool = "false",
 
         /// Whether to show native rust-analyzer diagnostics.
         diagnostics_enable: bool                = "true",
@@ -875,6 +877,7 @@ impl Config {
             enable_imports_on_the_fly: self.data.completion_autoimport_enable
                 && completion_item_edit_resolve(&self.caps),
             enable_self_on_the_fly: self.data.completion_autoself_enable,
+            enable_private_editable: self.data.completion_privateEditable_enable,
             add_call_parenthesis: self.data.completion_addCallParenthesis,
             add_call_argument_snippets: self.data.completion_addCallArgumentSnippets,
             insert_use: self.insert_use_config(),
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index c745af3da6..a910a910bb 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -134,6 +134,7 @@ fn integrated_completion_benchmark() {
             enable_postfix_completions: true,
             enable_imports_on_the_fly: true,
             enable_self_on_the_fly: true,
+            enable_private_editable: true,
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: SnippetCap::new(true),
@@ -171,6 +172,7 @@ fn integrated_completion_benchmark() {
             enable_postfix_completions: true,
             enable_imports_on_the_fly: true,
             enable_self_on_the_fly: true,
+            enable_private_editable: true,
             add_call_parenthesis: true,
             add_call_argument_snippets: true,
             snippet_cap: SnippetCap::new(true),
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index e30f6cd79c..0f7855a053 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -52,15 +52,14 @@ pub use crate::{
     ptr::{AstPtr, SyntaxNodePtr},
     syntax_error::SyntaxError,
     syntax_node::{
-        PreorderWithTokens, RustLanguage, SyntaxElement, SyntaxElementChildren, SyntaxNode,
-        SyntaxNodeChildren, SyntaxToken, SyntaxTreeBuilder,
+        PreorderWithTokens, SyntaxElement, SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren,
+        SyntaxToken, SyntaxTreeBuilder,
     },
     token_text::TokenText,
 };
 pub use parser::{SyntaxKind, T};
 pub use rowan::{
-    api::Preorder, Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize,
-    TokenAtOffset, WalkEvent,
+    Direction, GreenNode, NodeOrToken, SyntaxText, TextRange, TextSize, TokenAtOffset, WalkEvent,
 };
 pub use smol_str::SmolStr;
 
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index b10b0d3552..7e6c8225b1 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -213,6 +213,11 @@ Note that your client must specify the `additionalTextEdits` LSP client capabili
 Toggles the additional completions that automatically show method calls and field accesses
 with `self` prefixed to them when inside a method.
 --
+[[rust-analyzer.completion.privateEditable.enable]]rust-analyzer.completion.privateEditable.enable (default: `false`)::
++
+--
+Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
+--
 [[rust-analyzer.diagnostics.enable]]rust-analyzer.diagnostics.enable (default: `true`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index 5b75b895d0..1252752a9a 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -643,6 +643,11 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.completion.privateEditable.enable": {
+                    "markdownDescription": "Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.diagnostics.enable": {
                     "markdownDescription": "Whether to show native rust-analyzer diagnostics.",
                     "default": true,
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 993c64ccea..69b3cb9c17 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -113,15 +113,9 @@ pub struct Bb {
 impl Xtask {
     pub const HELP: &'static str = Self::HELP_;
 
-    #[allow(dead_code)]
     pub fn from_env() -> xflags::Result<Self> {
         Self::from_env_()
     }
-
-    #[allow(dead_code)]
-    pub fn from_vec(args: Vec<std::ffi::OsString>) -> xflags::Result<Self> {
-        Self::from_vec_(args)
-    }
 }
 // generated end
 


Test patch:
diff --git a/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs
index 919dd6c07f..6e91301ecd 100644
--- a/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir_def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -313,24 +313,6 @@ fn main() { "foor0bar\nfalse"; }
     );
 }
 
-#[test]
-fn test_concat_bytes_expand() {
-    check(
-        r##"
-#[rustc_builtin_macro]
-macro_rules! concat_bytes {}
-
-fn main() { concat_bytes!(b'A', b"BC", [68, b'E', 70]); }
-"##,
-        expect![[r##"
-#[rustc_builtin_macro]
-macro_rules! concat_bytes {}
-
-fn main() { [b'A', 66, 67, 68, b'E', 70]; }
-"##]],
-    );
-}
-
 #[test]
 fn test_concat_with_captured_expr() {
     check(
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 7385da5662..29250dca00 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -100,7 +100,6 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
                         .trim_start_matches("adjustments: ")
                         .split(',')
                         .map(|it| it.trim().to_string())
-                        .filter(|it| !it.is_empty())
                         .collect(),
                 );
             } else {
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index c0dddb608e..dd3b86f050 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -242,45 +242,6 @@ fn test() {
     );
 }
 
-#[test]
-fn coerce_autoderef_implication_1() {
-    check_no_mismatches(
-        r"
-//- minicore: deref
-struct Foo<T>;
-impl core::ops::Deref for Foo<u32> { type Target = (); }
-
-fn takes_ref_foo<T>(x: &Foo<T>) {}
-fn test() {
-    let foo = Foo;
-      //^^^ type: Foo<{unknown}>
-    takes_ref_foo(&foo);
-
-    let foo = Foo;
-      //^^^ type: Foo<u32>
-    let _: &() = &foo;
-}",
-    );
-}
-
-#[test]
-fn coerce_autoderef_implication_2() {
-    check(
-        r"
-//- minicore: deref
-struct Foo<T>;
-impl core::ops::Deref for Foo<u32> { type Target = (); }
-
-fn takes_ref_foo<T>(x: &Foo<T>) {}
-fn test() {
-    let foo = Foo;
-      //^^^ type: Foo<{unknown}>
-    let _: &u32 = &Foo;
-                //^^^^ expected &u32, got &Foo<{unknown}>
-}",
-    );
-}
-
 #[test]
 fn closure_return_coerce() {
     check_no_mismatches(
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index c118ae24cf..9c0c00da3b 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1460,121 +1460,3 @@ fn main() {
     "#,
     );
 }
-
-#[test]
-fn deref_fun_1() {
-    check_types(
-        r#"
-//- minicore: deref
-
-struct A<T, U>(T, U);
-struct B<T>(T);
-struct C<T>(T);
-
-impl<T> core::ops::Deref for A<B<T>, u32> {
-    type Target = B<T>;
-    fn deref(&self) -> &B<T> { &self.0 }
-}
-impl core::ops::Deref for B<isize> {
-    type Target = C<isize>;
-    fn deref(&self) -> &C<isize> { loop {} }
-}
-
-impl<T: Copy> C<T> {
-    fn thing(&self) -> T { self.0 }
-}
-
-fn make<T>() -> T { loop {} }
-
-fn test() {
-    let a1 = A(make(), make());
-    let _: usize = (*a1).0;
-    a1;
-  //^^ A<B<usize>, u32>
-
-    let a2 = A(make(), make());
-    a2.thing();
-  //^^^^^^^^^^ isize
-    a2;
-  //^^ A<B<isize>, u32>
-}
-"#,
-    );
-}
-
-#[test]
-fn deref_fun_2() {
-    check_types(
-        r#"
-//- minicore: deref
-
-struct A<T, U>(T, U);
-struct B<T>(T);
-struct C<T>(T);
-
-impl<T> core::ops::Deref for A<B<T>, u32> {
-    type Target = B<T>;
-    fn deref(&self) -> &B<T> { &self.0 }
-}
-impl core::ops::Deref for B<isize> {
-    type Target = C<isize>;
-    fn deref(&self) -> &C<isize> { loop {} }
-}
-
-impl<T> core::ops::Deref for A<C<T>, i32> {
-    type Target = C<T>;
-    fn deref(&self) -> &C<T> { &self.0 }
-}
-
-impl<T: Copy> C<T> {
-    fn thing(&self) -> T { self.0 }
-}
-
-fn make<T>() -> T { loop {} }
-
-fn test() {
-    let a1 = A(make(), 1u32);
-    a1.thing();
-    a1;
-  //^^ A<B<isize>, u32>
-
-    let a2 = A(make(), 1i32);
-    let _: &str = a2.thing();
-    a2;
-  //^^ A<C<&str>, i32>
-}
-"#,
-    );
-}
-
-#[test]
-fn receiver_adjustment_autoref() {
-    check(
-        r#"
-struct Foo;
-impl Foo {
-    fn foo(&self) {}
-}
-fn test() {
-    Foo.foo();
-  //^^^ adjustments: Borrow(Ref(Not))
-    (&Foo).foo();
-  // ^^^^ adjustments: ,
-}
-"#,
-    );
-}
-
-#[test]
-fn receiver_adjustment_unsize_array() {
-    // FIXME not quite correct
-    check(
-        r#"
-//- minicore: slice
-fn test() {
-    let a = [1, 2, 3];
-    a.len();
-} //^ adjustments: Pointer(Unsize), Borrow(Ref(Not))
-"#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 04d8b91e35..c2669646e2 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -540,52 +540,6 @@ fn test() {
     );
 }
 
-#[test]
-fn infer_ops_index_field() {
-    check_types(
-        r#"
-//- minicore: index
-struct Bar;
-struct Foo {
-    field: u32;
-}
-
-impl core::ops::Index<u32> for Bar {
-    type Output = Foo;
-}
-
-fn test() {
-    let a = Bar;
-    let b = a[1u32].field;
-    b;
-} //^ u32
-"#,
-    );
-}
-
-#[test]
-fn infer_ops_index_field_autoderef() {
-    check_types(
-        r#"
-//- minicore: index
-struct Bar;
-struct Foo {
-    field: u32;
-}
-
-impl core::ops::Index<u32> for Bar {
-    type Output = Foo;
-}
-
-fn test() {
-    let a = Bar;
-    let b = (&a[1u32]).field;
-    b;
-} //^ u32
-"#,
-    );
-}
-
 #[test]
 fn infer_ops_index_int() {
     check_types(
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df0ca941c9..a232ebd4fb 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -4583,33 +4583,3 @@ pub struct Foo;
         "##]],
     );
 }
-
-#[test]
-fn hover_dollar_crate() {
-    // $crate should be resolved to the right crate name.
-
-    check(
-        r#"
-//- /main.rs crate:main deps:dep
-dep::m!(KONST$0);
-//- /dep.rs crate:dep
-#[macro_export]
-macro_rules! m {
-    ( $name:ident ) => { const $name: $crate::Type = $crate::Type; };
-}
-
-pub struct Type;
-"#,
-        expect![[r#"
-            *KONST*
-
-            ```rust
-            main
-            ```
-
-            ```rust
-            const KONST: dep::Type = $crate::Type
-            ```
-        "#]],
-    );
-}
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index f063a9638c..45c7c58dc0 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -64,6 +64,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     enable_postfix_completions: true,
     enable_imports_on_the_fly: true,
     enable_self_on_the_fly: true,
+    enable_private_editable: true,
     add_call_parenthesis: true,
     add_call_argument_snippets: true,
     snippet_cap: SnippetCap::new(true),