Repository: rust-analyzer/rust-analyzer
Pull request #11877 (2022-04-02 06:12:35)

fix: splitting path of a glob import wrongly adds `self`
Close  #11703 

`ast::UseTree::split_prefix` handles globs now.
Removed an extra branch for globs in `ide_db::imports::merge_imports::recursive_merge` (superseeded by split_prefix).


Patch:
diff --git a/README.md b/README.md
index 9732b05801..e2f3ad232a 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,12 @@
 rust-analyzer is a modular compiler frontend for the Rust language.
 It is a part of a larger rls-2.0 effort to create excellent IDE support for Rust.
 
+Work on rust-analyzer is sponsored by
+
+[<img src="https://user-images.githubusercontent.com/1711539/58105231-cf306900-7bee-11e9-83d8-9f1102e59d29.png" alt="Ferrous Systems" width="300">](https://ferrous-systems.com/)
+- [Mozilla](https://www.mozilla.org/en-US/)
+- [Embark Studios](https://embark-studios.com/)
+
 ## Quick Start
 
 https://rust-analyzer.github.io/manual.html#installation
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index daa0e3f699..d1e2d74a98 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -10,7 +10,7 @@ use tt::Subtree;
 use vfs::{file_set::FileSet, VfsPath};
 
 use crate::{
-    input::{CrateName, CrateOrigin, LangCrateOrigin},
+    input::{CrateName, CrateOrigin},
     Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition,
     FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, SourceDatabaseExt,
     SourceRoot, SourceRootId,
@@ -196,7 +196,7 @@ impl ChangeFixture {
                 Env::default(),
                 Default::default(),
                 false,
-                CrateOrigin::CratesIo { repo: None },
+                Default::default(),
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -233,7 +233,7 @@ impl ChangeFixture {
                 Env::default(),
                 Vec::new(),
                 false,
-                CrateOrigin::Lang(LangCrateOrigin::Core),
+                CrateOrigin::Lang,
             );
 
             for krate in all_crates {
@@ -270,7 +270,7 @@ impl ChangeFixture {
                 Env::default(),
                 proc_macro,
                 true,
-                CrateOrigin::CratesIo { repo: None },
+                CrateOrigin::Lang,
             );
 
             for krate in all_crates {
@@ -406,11 +406,7 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
         };
         (a.to_owned(), origin, Some(version.to_string()))
     } else {
-        let crate_origin = match &*crate_str {
-            "std" => CrateOrigin::Lang(LangCrateOrigin::Std),
-            _ => CrateOrigin::CratesIo { repo: None },
-        };
-        (crate_str, crate_origin, None)
+        (crate_str, CrateOrigin::Unknown, None)
     }
 }
 
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 43d7ccad49..db3f85604b 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -117,22 +117,21 @@ impl ops::Deref for CrateName {
 }
 
 /// Origin of the crates. It is used in emitting monikers.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Clone)]
 pub enum CrateOrigin {
     /// Crates that are from crates.io official registry,
     CratesIo { repo: Option<String> },
     /// Crates that are provided by the language, like std, core, proc-macro, ...
-    Lang(LangCrateOrigin),
+    Lang,
+    /// Crates that we don't know their origin.
+    // Ideally this enum should cover all cases, and then we remove this variant.
+    Unknown,
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum LangCrateOrigin {
-    Alloc,
-    Core,
-    ProcMacro,
-    Std,
-    Test,
-    Other,
+impl Default for CrateOrigin {
+    fn default() -> Self {
+        Self::Unknown
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -586,8 +585,6 @@ impl fmt::Display for CyclicDependenciesError {
 
 #[cfg(test)]
 mod tests {
-    use crate::CrateOrigin;
-
     use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId};
 
     #[test]
@@ -603,7 +600,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -615,7 +612,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -627,7 +624,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -653,7 +650,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -665,7 +662,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -688,7 +685,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -700,7 +697,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -712,7 +709,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -735,7 +732,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -747,7 +744,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         assert!(graph
             .add_dep(
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index 2454698bb6..d80660f7c9 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -12,8 +12,8 @@ pub use crate::{
     change::Change,
     input::{
         CrateData, CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency,
-        Edition, Env, LangCrateOrigin, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
-        ProcMacroId, ProcMacroKind, SourceRoot, SourceRootId,
+        Edition, Env, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroId,
+        ProcMacroKind, SourceRoot, SourceRootId,
     },
 };
 pub use salsa::{self, Cancelled};
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 8b99662685..c07c017c3d 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -148,10 +148,6 @@ impl Crate {
         db.crate_graph()[self.id].origin.clone()
     }
 
-    pub fn is_builtin(self, db: &dyn HirDatabase) -> bool {
-        matches!(self.origin(db), CrateOrigin::Lang(_))
-    }
-
     pub fn dependencies(self, db: &dyn HirDatabase) -> Vec<CrateDependency> {
         db.crate_graph()[self.id]
             .dependencies
@@ -1745,8 +1741,10 @@ impl BuiltinType {
         BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
     }
 
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
-        Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner))
+    pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type {
+        let resolver = module.id.resolver(db.upcast());
+        Type::new_with_resolver(db, &resolver, TyBuilder::builtin(self.inner))
+            .expect("crate not present in resolver")
     }
 
     pub fn name(self) -> Name {
@@ -2224,7 +2222,7 @@ impl BuiltinAttr {
         Some(BuiltinAttr { krate: Some(krate.id), idx })
     }
 
-    fn builtin(name: &str) -> Option<Self> {
+    pub(crate) fn builtin(name: &str) -> Option<Self> {
         hir_def::builtin_attr::INERT_ATTRIBUTES
             .iter()
             .position(|tool| tool.name == name)
@@ -2263,7 +2261,7 @@ impl ToolModule {
         Some(ToolModule { krate: Some(krate.id), idx })
     }
 
-    fn builtin(name: &str) -> Option<Self> {
+    pub(crate) fn builtin(name: &str) -> Option<Self> {
         hir_def::builtin_attr::TOOL_MODULES
             .iter()
             .position(|&tool| tool == name)
@@ -2613,11 +2611,14 @@ pub struct Type {
 }
 
 impl Type {
-    pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
-        let krate = resolver.krate();
-        Type::new_with_resolver_inner(db, krate, resolver, ty)
+    pub(crate) fn new_with_resolver(
+        db: &dyn HirDatabase,
+        resolver: &Resolver,
+        ty: Ty,
+    ) -> Option<Type> {
+        let krate = resolver.krate()?;
+        Some(Type::new_with_resolver_inner(db, krate, resolver, ty))
     }
-
     pub(crate) fn new_with_resolver_inner(
         db: &dyn HirDatabase,
         krate: CrateId,
@@ -2630,10 +2631,6 @@ impl Type {
         Type { krate, env: environment, ty }
     }
 
-    pub(crate) fn new_for_crate(krate: CrateId, ty: Ty) -> Type {
-        Type { krate, env: Arc::new(TraitEnvironment::empty(krate)), ty }
-    }
-
     pub fn reference(inner: &Type, m: Mutability) -> Type {
         inner.derived(
             TyKind::Ref(
@@ -3034,7 +3031,10 @@ impl Type {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
-        let krate = scope.krate();
+        let 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),
@@ -3091,7 +3091,10 @@ impl Type {
     ) {
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
-        let krate = scope.krate();
+        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),
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 246b93723b..4afdde6494 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -30,9 +30,9 @@ use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    Access, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource, HirFileId, Impl,
-    InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path, ScopeDef,
-    ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
+    Access, AssocItem, BuiltinAttr, Callable, ConstParam, Crate, Field, Function, HasSource,
+    HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef, Name, Path,
+    ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -46,6 +46,7 @@ pub enum PathResolution {
     /// A const parameter
     ConstParam(ConstParam),
     SelfType(Impl),
+    AssocItem(AssocItem),
     BuiltinAttr(BuiltinAttr),
     ToolModule(ToolModule),
 }
@@ -75,6 +76,10 @@ impl PathResolution {
             | PathResolution::ConstParam(_) => None,
             PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
             PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
+            PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None,
+            PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
+                Some(TypeNs::TypeAliasId((*alias).into()))
+            }
         }
     }
 }
@@ -398,15 +403,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.to_module_def(file)
     }
 
-    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
+    pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
         self.imp.scope(node)
     }
 
-    pub fn scope_at_offset(
-        &self,
-        node: &SyntaxNode,
-        offset: TextSize,
-    ) -> Option<SemanticsScope<'db>> {
+    pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
         self.imp.scope_at_offset(node, offset)
     }
 
@@ -455,7 +456,7 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn expand(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
-        let sa = self.analyze_no_infer(macro_call.syntax())?;
+        let sa = self.analyze_no_infer(macro_call.syntax());
         let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?;
         let node = self.parse_or_expand(file_id)?;
         Some(node)
@@ -534,9 +535,9 @@ impl<'db> SemanticsImpl<'db> {
         token_to_map: SyntaxToken,
     ) -> Option<(SyntaxNode, SyntaxToken)> {
         let SourceAnalyzer { file_id, resolver, .. } =
-            self.analyze_no_infer(actual_macro_call.syntax())?;
+            self.analyze_no_infer(actual_macro_call.syntax());
         let macro_call = InFile::new(file_id, actual_macro_call);
-        let krate = resolver.krate();
+        let krate = resolver.krate()?;
         let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
             resolver
                 .resolve_path_as_macro(self.db.upcast(), &path)
@@ -668,10 +669,7 @@ impl<'db> SemanticsImpl<'db> {
             Some(it) => it,
             None => return,
         };
-        let sa = match self.analyze_no_infer(&parent) {
-            Some(it) => it,
-            None => return,
-        };
+        let sa = self.analyze_no_infer(&parent);
         let mut stack: SmallVec<[_; 4]> = smallvec![InFile::new(sa.file_id, token)];
         let mut cache = self.expansion_info_cache.borrow_mut();
         let mut mcache = self.macro_call_cache.borrow_mut();
@@ -905,74 +903,70 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
-        let analyze = self.analyze(ty.syntax())?;
-        let ctx = body::LowerCtx::new(self.db.upcast(), analyze.file_id);
-        let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver)
+        let scope = self.scope(ty.syntax());
+        let ctx = body::LowerCtx::new(self.db.upcast(), scope.file_id);
+        let ty = hir_ty::TyLoweringContext::new(self.db, &scope.resolver)
             .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
-        Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
+        Type::new_with_resolver(self.db, &scope.resolver, ty)
     }
 
     fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
-        self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
+        self.analyze(expr.syntax()).is_implicit_reborrow(self.db, expr)
     }
 
     fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
-        self.analyze(expr.syntax())?
+        self.analyze(expr.syntax())
             .type_of_expr(self.db, expr)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
     }
 
     fn type_of_pat(&self, pat: &ast::Pat) -> Option<TypeInfo> {
-        self.analyze(pat.syntax())?
+        self.analyze(pat.syntax())
             .type_of_pat(self.db, pat)
             .map(|(ty, coerced)| TypeInfo { original: ty, adjusted: coerced })
     }
 
     fn type_of_self(&self, param: &ast::SelfParam) -> Option<Type> {
-        self.analyze(param.syntax())?.type_of_self(self.db, param)
+        self.analyze(param.syntax()).type_of_self(self.db, param)
     }
 
     fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
-        self.analyze(call.syntax())?.resolve_method_call(self.db, call).map(|(id, _)| id)
+        self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id)
     }
 
     fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
-        let source_analyzer = self.analyze(call.syntax())?;
-        let (func, subst) = source_analyzer.resolve_method_call(self.db, call)?;
+        let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
         let ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
-        let resolver = source_analyzer.resolver;
-        let ty = Type::new_with_resolver(self.db, &resolver, ty);
+        let resolver = self.analyze(call.syntax()).resolver;
+        let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
         let mut res = ty.as_callable(self.db)?;
         res.is_bound_method = true;
         Some(res)
     }
 
     fn resolve_field(&self, field: &ast::FieldExpr) -> Option<Field> {
-        self.analyze(field.syntax())?.resolve_field(self.db, field)
+        self.analyze(field.syntax()).resolve_field(self.db, field)
     }
 
     fn resolve_record_field(
         &self,
         field: &ast::RecordExprField,
     ) -> Option<(Field, Option<Local>, Type)> {
-        self.analyze(field.syntax())?.resolve_record_field(self.db, field)
+        self.analyze(field.syntax()).resolve_record_field(self.db, field)
     }
 
     fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
-        self.analyze(field.syntax())?.resolve_record_pat_field(self.db, field)
+        self.analyze(field.syntax()).resolve_record_pat_field(self.db, field)
     }
 
     fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<Macro> {
-        let sa = self.analyze(macro_call.syntax())?;
+        let sa = self.analyze(macro_call.syntax());
         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
         sa.resolve_macro_call(self.db, macro_call)
     }
 
     fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
-        let sa = match self.analyze(macro_call.syntax()) {
-            Some(it) => it,
-            None => return false,
-        };
+        let sa = self.analyze(macro_call.syntax());
         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
         sa.is_unsafe_macro_call(self.db, macro_call)
     }
@@ -987,11 +981,11 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
-        self.analyze(path.syntax())?.resolve_path(self.db, path)
+        self.analyze(path.syntax()).resolve_path(self.db, path)
     }
 
     fn resolve_extern_crate(&self, extern_crate: &ast::ExternCrate) -> Option<Crate> {
-        let krate = self.scope(extern_crate.syntax())?.krate();
+        let krate = self.scope(extern_crate.syntax()).krate()?;
         let name = extern_crate.name_ref()?.as_name();
         if name == known::SELF_PARAM {
             return Some(krate);
@@ -1003,22 +997,22 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
-        self.analyze(record_lit.syntax())?.resolve_variant(self.db, record_lit)
+        self.analyze(record_lit.syntax()).resolve_variant(self.db, record_lit)
     }
 
     fn resolve_bind_pat_to_const(&self, pat: &ast::IdentPat) -> Option<ModuleDef> {
-        self.analyze(pat.syntax())?.resolve_bind_pat_to_const(self.db, pat)
+        self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat)
     }
 
     fn record_literal_missing_fields(&self, literal: &ast::RecordExpr) -> Vec<(Field, Type)> {
         self.analyze(literal.syntax())
-            .and_then(|it| it.record_literal_missing_fields(self.db, literal))
+            .record_literal_missing_fields(self.db, literal)
             .unwrap_or_default()
     }
 
     fn record_pattern_missing_fields(&self, pattern: &ast::RecordPat) -> Vec<(Field, Type)> {
         self.analyze(pattern.syntax())
-            .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
+            .record_pattern_missing_fields(self.db, pattern)
             .unwrap_or_default()
     }
 
@@ -1032,22 +1026,15 @@ impl<'db> SemanticsImpl<'db> {
         self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
     }
 
-    fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
-        self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope {
-            db: self.db,
-            file_id,
-            resolver,
-        })
+    fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
+        let SourceAnalyzer { file_id, resolver, .. } = self.analyze_no_infer(node);
+        SemanticsScope { db: self.db, file_id, resolver }
     }
 
-    fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> Option<SemanticsScope<'db>> {
-        self.analyze_with_offset_no_infer(node, offset).map(
-            |SourceAnalyzer { file_id, resolver, .. }| SemanticsScope {
-                db: self.db,
-                file_id,
-                resolver,
-            },
-        )
+    fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
+        let SourceAnalyzer { file_id, resolver, .. } =
+            self.analyze_with_offset_no_infer(node, offset);
+        SemanticsScope { db: self.db, file_id, resolver }
     }
 
     fn scope_for_def(&self, def: Trait) -> SemanticsScope<'db> {
@@ -1065,21 +1052,15 @@ impl<'db> SemanticsImpl<'db> {
         Some(res)
     }
 
-    /// Returns none if the file of the node is not part of a crate.
-    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
+    fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
         self.analyze_impl(node, None, true)
     }
 
-    /// Returns none if the file of the node is not part of a crate.
-    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
+    fn analyze_no_infer(&self, node: &SyntaxNode) -> SourceAnalyzer {
         self.analyze_impl(node, None, false)
     }
 
-    fn analyze_with_offset_no_infer(
-        &self,
-        node: &SyntaxNode,
-        offset: TextSize,
-    ) -> Option<SourceAnalyzer> {
+    fn analyze_with_offset_no_infer(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
         self.analyze_impl(node, Some(offset), false)
     }
 
@@ -1088,22 +1069,22 @@ impl<'db> SemanticsImpl<'db> {
         node: &SyntaxNode,
         offset: Option<TextSize>,
         infer_body: bool,
-    ) -> Option<SourceAnalyzer> {
+    ) -> SourceAnalyzer {
         let _p = profile::span("Semantics::analyze_impl");
         let node = self.find_file(node);
 
         let container = match self.with_ctx(|ctx| ctx.find_container(node)) {
             Some(it) => it,
-            None => return None,
+            None => return SourceAnalyzer::new_for_resolver(Resolver::default(), node),
         };
 
         let resolver = match container {
             ChildContainer::DefWithBodyId(def) => {
-                return Some(if infer_body {
+                return if infer_body {
                     SourceAnalyzer::new_for_body(self.db, def, node, offset)
                 } else {
                     SourceAnalyzer::new_for_body_no_infer(self.db, def, node, offset)
-                })
+                }
             }
             ChildContainer::TraitId(it) => it.resolver(self.db.upcast()),
             ChildContainer::ImplId(it) => it.resolver(self.db.upcast()),
@@ -1113,7 +1094,7 @@ impl<'db> SemanticsImpl<'db> {
             ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
             ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
         };
-        Some(SourceAnalyzer::new_for_resolver(resolver, node))
+        SourceAnalyzer::new_for_resolver(resolver, node)
     }
 
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
@@ -1137,7 +1118,6 @@ impl<'db> SemanticsImpl<'db> {
         InFile::new(file_id, node)
     }
 
-    /// Wraps the node in a [`InFile`] with the file id it belongs to.
     fn find_file<'node>(&self, node: &'node SyntaxNode) -> InFile<&'node SyntaxNode> {
         let root_node = find_root(node);
         let file_id = self.lookup(&root_node).unwrap_or_else(|| {
@@ -1339,12 +1319,12 @@ pub struct SemanticsScope<'a> {
 }
 
 impl<'a> SemanticsScope<'a> {
-    pub fn module(&self) -> Module {
-        Module { id: self.resolver.module() }
+    pub fn module(&self) -> Option<Module> {
+        Some(Module { id: self.resolver.module()? })
     }
 
-    pub fn krate(&self) -> Crate {
-        Crate { id: self.resolver.krate() }
+    pub fn krate(&self) -> Option<Crate> {
+        Some(Crate { id: self.resolver.krate()? })
     }
 
     pub(crate) fn resolver(&self) -> &Resolver {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 6f5908ceb7..2b818b8eba 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -40,9 +40,8 @@ use syntax::{
 };
 
 use crate::{
-    db::HirDatabase, semantics::PathResolution, Adt, AssocItem, BuiltinAttr, BuiltinType, Const,
-    Field, Function, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias,
-    Variant,
+    db::HirDatabase, semantics::PathResolution, Adt, BuiltinAttr, BuiltinType, Const, Field,
+    Function, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias, Variant,
 };
 use base_db::CrateId;
 
@@ -170,7 +169,7 @@ impl SourceAnalyzer {
             .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
         let ty = infer[expr_id].clone();
         let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
-        Some((mk_ty(ty), coerced.map(mk_ty)))
+        mk_ty(ty).zip(Some(coerced.and_then(mk_ty)))
     }
 
     pub(crate) fn type_of_pat(
@@ -186,7 +185,7 @@ impl SourceAnalyzer {
             .and_then(|adjusts| adjusts.last().map(|adjust| adjust.target.clone()));
         let ty = infer[pat_id].clone();
         let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
-        Some((mk_ty(ty), coerced.map(mk_ty)))
+        mk_ty(ty).zip(Some(coerced.and_then(mk_ty)))
     }
 
     pub(crate) fn type_of_self(
@@ -197,7 +196,7 @@ impl SourceAnalyzer {
         let src = InFile { file_id: self.file_id, value: param };
         let pat_id = self.body_source_map()?.node_self_param(src)?;
         let ty = self.infer.as_ref()?[pat_id].clone();
-        Some(Type::new_with_resolver(db, &self.resolver, ty))
+        Type::new_with_resolver(db, &self.resolver, ty)
     }
 
     pub(crate) fn resolve_method_call(
@@ -245,7 +244,7 @@ impl SourceAnalyzer {
         let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
         let field_ty =
             db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
-        Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)))
+        Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)?))
     }
 
     pub(crate) fn resolve_record_pat_field(
@@ -303,7 +302,7 @@ impl SourceAnalyzer {
             let expr_id = self.expr_id(db, &path_expr.into())?;
             let infer = self.infer.as_ref()?;
             if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
-                return Some(PathResolution::Def(AssocItem::from(assoc).into()));
+                return Some(PathResolution::AssocItem(assoc.into()));
             }
             if let Some(VariantId::EnumVariantId(variant)) =
                 infer.variant_resolution_for_expr(expr_id)
@@ -314,7 +313,7 @@ impl SourceAnalyzer {
         } else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
             let pat_id = self.pat_id(&path_pat.into())?;
             if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
-                return Some(PathResolution::Def(AssocItem::from(assoc).into()));
+                return Some(PathResolution::AssocItem(assoc.into()));
             }
             if let Some(VariantId::EnumVariantId(variant)) =
                 self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
@@ -367,8 +366,11 @@ impl SourceAnalyzer {
             return match resolve_hir_path_qualifier(db, &self.resolver, &hir_path) {
                 None if is_path_of_attr => {
                     path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
-                        ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
-                            .map(PathResolution::ToolModule)
+                        match self.resolver.krate() {
+                            Some(krate) => ToolModule::by_name(db, krate.into(), &name_ref.text()),
+                            None => ToolModule::builtin(&name_ref.text()),
+                        }
+                        .map(PathResolution::ToolModule)
                     })
                 }
                 res => res,
@@ -378,8 +380,9 @@ impl SourceAnalyzer {
             // in this case we have to check for inert/builtin attributes and tools and prioritize
             // resolution of attributes over other namespaces
             let name_ref = path.as_single_name_ref();
-            let builtin = name_ref.as_ref().and_then(|name_ref| {
-                BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text())
+            let builtin = name_ref.as_ref().and_then(|name_ref| match self.resolver.krate() {
+                Some(krate) => BuiltinAttr::by_name(db, krate.into(), &name_ref.text()),
+                None => BuiltinAttr::builtin(&name_ref.text()),
             });
             if let builtin @ Some(_) = builtin {
                 return builtin.map(PathResolution::BuiltinAttr);
@@ -389,8 +392,11 @@ impl SourceAnalyzer {
                 // this labels any path that starts with a tool module as the tool itself, this is technically wrong
                 // but there is no benefit in differentiating these two cases for the time being
                 None => path.first_segment().and_then(|it| it.name_ref()).and_then(|name_ref| {
-                    ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
-                        .map(PathResolution::ToolModule)
+                    match self.resolver.krate() {
+                        Some(krate) => ToolModule::by_name(db, krate.into(), &name_ref.text()),
+                        None => ToolModule::builtin(&name_ref.text()),
+                    }
+                    .map(PathResolution::ToolModule)
                 }),
             };
         }
@@ -406,7 +412,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         literal: &ast::RecordExpr,
     ) -> Option<Vec<(Field, Type)>> {
-        let krate = self.resolver.krate();
+        let krate = self.resolver.krate()?;
         let body = self.body()?;
         let infer = self.infer.as_ref()?;
 
@@ -424,7 +430,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         pattern: &ast::RecordPat,
     ) -> Option<Vec<(Field, Type)>> {
-        let krate = self.resolver.krate();
+        let krate = self.resolver.krate()?;
         let body = self.body()?;
         let infer = self.infer.as_ref()?;
 
@@ -462,7 +468,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         macro_call: InFile<&ast::MacroCall>,
     ) -> Option<HirFileId> {
-        let krate = self.resolver.krate();
+        let krate = self.resolver.krate()?;
         let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| {
             self.resolver
                 .resolve_path_as_macro(db.upcast(), &path)
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index fe0100fb8c..ab99627d18 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -25,14 +25,12 @@ use crate::{
     StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId,
 };
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Default)]
 pub struct Resolver {
     /// The stack of scopes, where the inner-most scope is the last item.
     ///
     /// When using, you generally want to process the scopes in reverse order,
     /// there's `scopes` *method* for that.
-    ///
-    /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
     scopes: Vec<Scope>,
 }
 
@@ -137,7 +135,10 @@ impl Resolver {
         path: &ModPath,
         shadow: BuiltinShadowMode,
     ) -> PerNs {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = match self.module_scope() {
+            Some(it) => it,
+            None => return PerNs::none(),
+        };
         let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
         if segment_index.is_some() {
             return PerNs::none();
@@ -154,7 +155,7 @@ impl Resolver {
         db: &dyn DefDatabase,
         path: &ModPath,
     ) -> Option<PerNs> {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = self.module_scope()?;
         let (module_res, idx) = item_map.resolve_path(db, module, path, BuiltinShadowMode::Module);
         match module_res.take_types()? {
             ModuleDefId::TraitId(it) => {
@@ -234,7 +235,10 @@ impl Resolver {
     ) -> Option<Visibility> {
         match visibility {
             RawVisibility::Module(_) => {
-                let (item_map, module) = self.module_scope();
+                let (item_map, module) = match self.module_scope() {
+                    Some(it) => it,
+                    None => return None,
+                };
                 item_map.resolve_visibility(db, module, visibility)
             }
             RawVisibility::Public => Some(Visibility::Public),
@@ -332,7 +336,7 @@ impl Resolver {
     }
 
     pub fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
-        let (item_map, module) = self.module_scope();
+        let (item_map, module) = self.module_scope()?;
         item_map.resolve_path(db, module, path, BuiltinShadowMode::Other).0.take_macros()
     }
 
@@ -421,22 +425,22 @@ impl Resolver {
         traits
     }
 
-    fn module_scope(&self) -> (&DefMap, LocalModuleId) {
-        self.scopes()
-            .find_map(|scope| match scope {
-                Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
-                _ => None,
-            })
-            .expect("module scope invariant violated")
+    fn module_scope(&self) -> Option<(&DefMap, LocalModuleId)> {
+        self.scopes().find_map(|scope| match scope {
+            Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
+
+            _ => None,
+        })
     }
 
-    pub fn module(&self) -> ModuleId {
-        let (def_map, local_id) = self.module_scope();
-        def_map.module_id(local_id)
+    pub fn module(&self) -> Option<ModuleId> {
+        let (def_map, local_id) = self.module_scope()?;
+        Some(def_map.module_id(local_id))
     }
 
-    pub fn krate(&self) -> CrateId {
-        self.module_scope().0.krate()
+    pub fn krate(&self) -> Option<CrateId> {
+        // FIXME: can this ever be `None`?
+        self.module_scope().map(|t| t.0.krate())
     }
 
     pub fn where_predicates_in_scope(
@@ -745,7 +749,8 @@ impl HasResolver for ModuleId {
             def_map = parent.def_map(db);
             modules.push((def_map.clone(), parent.local_id));
         }
-        let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
+        let mut resolver = Resolver::default();
+        resolver.scopes.reserve(modules.len());
         for (def_map, module) in modules.into_iter().rev() {
             resolver = resolver.push_module_scope(def_map, module);
         }
diff --git a/crates/hir_expand/src/builtin_fn_macro.rs b/crates/hir_expand/src/builtin_fn_macro.rs
index 8d2352f06e..bad5f9aa24 100644
--- a/crates/hir_expand/src/builtin_fn_macro.rs
+++ b/crates/hir_expand/src/builtin_fn_macro.rs
@@ -295,7 +295,7 @@ fn asm_expand(
 
     let expanded = quote! {{
         ##literals
-        loop {}
+        ()
     }};
     ExpandResult::ok(expanded)
 }
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 6972db8495..451245b5d2 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -420,8 +420,9 @@ pub(crate) fn associated_ty_data_query(
         .collect();
 
     if !ctx.unsized_types.borrow().contains(&self_ty) {
-        let sized_trait = db
-            .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+        let sized_trait = resolver
+            .krate()
+            .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
             .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
         let sized_bound = sized_trait.into_iter().map(|sized_trait| {
             let trait_bound =
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 70bb56e02f..71e81b4348 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -762,7 +762,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_lang_item(&self, name: Name) -> Option<LangItemTarget> {
-        let krate = self.resolver.krate();
+        let krate = self.resolver.krate()?;
         self.db.lang_item(krate, name.to_smol_str())
     }
 
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index fc88e97d6a..238aff75c4 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -29,7 +29,7 @@ use crate::{
         const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
     },
     mapping::{from_chalk, ToChalk},
-    method_resolution::{self, VisibleFromModule},
+    method_resolution,
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
     utils::{generics, Generics},
@@ -45,6 +45,10 @@ use super::{
 impl<'a> InferenceContext<'a> {
     pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
         let ty = self.infer_expr_inner(tgt_expr, expected);
+        if self.resolve_ty_shallow(&ty).is_never() {
+            // Any expression that produces a value of type `!` must have diverged
+            self.diverges = Diverges::Always;
+        }
         if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
             let could_unify = self.unify(&ty, &expected_ty);
             if !could_unify {
@@ -65,11 +69,12 @@ impl<'a> InferenceContext<'a> {
             match self.coerce(Some(expr), &ty, &target) {
                 Ok(res) => res,
                 Err(_) => {
-                    self.result.type_mismatches.insert(
-                        expr.into(),
-                        TypeMismatch { expected: target.clone(), actual: ty.clone() },
-                    );
-                    target
+                    self.result
+                        .type_mismatches
+                        .insert(expr.into(), TypeMismatch { expected: target, actual: ty.clone() });
+                    // Return actual type when type mismatch.
+                    // This is needed for diagnostic when return type mismatch.
+                    ty
                 }
             }
         } else {
@@ -487,8 +492,13 @@ impl<'a> InferenceContext<'a> {
                         }
                         _ => return None,
                     };
-                    let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
-                        .is_visible_from(self.db.upcast(), self.resolver.module());
+                    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
@@ -791,10 +801,6 @@ impl<'a> InferenceContext<'a> {
         // use a new type variable if we got unknown here
         let ty = self.insert_type_vars_shallow(ty);
         self.write_expr_ty(tgt_expr, ty.clone());
-        if self.resolve_ty_shallow(&ty).is_never() {
-            // Any expression that produces a value of type `!` must have diverged
-            self.diverges = Diverges::Always;
-        }
         ty
     }
 
@@ -908,16 +914,9 @@ impl<'a> InferenceContext<'a> {
                 self.table.new_maybe_never_var()
             } else {
                 if let Some(t) = expected.only_has_type(&mut self.table) {
-                    if self.coerce(Some(expr), &TyBuilder::unit(), &t).is_err() {
-                        self.result.type_mismatches.insert(
-                            expr.into(),
-                            TypeMismatch { expected: t.clone(), actual: TyBuilder::unit() },
-                        );
-                    }
-                    t
-                } else {
-                    TyBuilder::unit()
+                    let _ = self.coerce(Some(expr), &TyBuilder::unit(), &t);
                 }
+                TyBuilder::unit()
             }
         }
     }
@@ -941,7 +940,7 @@ impl<'a> InferenceContext<'a> {
             self.db,
             self.trait_env.clone(),
             &traits_in_scope,
-            VisibleFromModule::Filter(self.resolver.module()),
+            self.resolver.module().into(),
             method_name,
         );
         let (receiver_ty, method_ty, substs) = match resolved {
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index f580e09e91..53fe2131a3 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -9,11 +9,8 @@ use hir_def::{
 use hir_expand::name::Name;
 
 use crate::{
-    builder::ParamKind,
-    consteval,
-    method_resolution::{self, VisibleFromModule},
-    GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
-    ValueTyDefId,
+    builder::ParamKind, consteval, method_resolution, GenericArgData, Interner, Substitution,
+    TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -234,7 +231,7 @@ impl<'a> InferenceContext<'a> {
             self.db,
             self.table.trait_env.clone(),
             &traits_in_scope,
-            VisibleFromModule::Filter(self.resolver.module()),
+            self.resolver.module().into(),
             Some(name),
             method_resolution::LookupMode::Path,
             move |_ty, item| {
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 81134f666b..d0226cec26 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -205,7 +205,7 @@ impl<'a> TyLoweringContext<'a> {
                     len,
                     self.type_param_mode,
                     || self.generics(),
-                    self.in_binders,
+                    DebruijnIndex::INNERMOST,
                 );
 
                 TyKind::Array(inner_ty, const_len).intern(Interner)
@@ -335,13 +335,12 @@ impl<'a> TyLoweringContext<'a> {
                     let mut expander = self.expander.borrow_mut();
                     if expander.is_some() {
                         (Some(expander), false)
-                    } else {
-                        *expander = Some(Expander::new(
-                            self.db.upcast(),
-                            macro_call.file_id,
-                            self.resolver.module(),
-                        ));
+                    } else if let Some(module_id) = self.resolver.module() {
+                        *expander =
+                            Some(Expander::new(self.db.upcast(), macro_call.file_id, module_id));
                         (Some(expander), true)
+                    } else {
+                        (None, false)
                     }
                 };
                 let ty = if let Some(mut expander) = expander {
@@ -729,7 +728,7 @@ impl<'a> TyLoweringContext<'a> {
                             c,
                             self.type_param_mode,
                             || self.generics(),
-                            self.in_binders,
+                            DebruijnIndex::INNERMOST,
                         )
                     },
                 ) {
@@ -861,8 +860,9 @@ impl<'a> TyLoweringContext<'a> {
             }
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
-                    .db
-                    .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
+                    .resolver
+                    .krate()
+                    .and_then(|krate| self.db.lang_item(krate, SmolStr::new_inline("sized")))
                     .and_then(|lang_item| lang_item.as_trait());
                 // Don't lower associated type bindings as the only possible relaxed trait bound
                 // `?Sized` has no of them.
@@ -1268,8 +1268,9 @@ fn implicitly_sized_clauses<'a>(
 ) -> impl Iterator<Item = WhereClause> + 'a {
     let is_trait_def = matches!(def, GenericDefId::TraitId(..));
     let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..];
-    let sized_trait = db
-        .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
+    let sized_trait = resolver
+        .krate()
+        .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
         .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 
     sized_trait.into_iter().flat_map(move |sized_trait| {
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index a7d6bc2401..775af2b66c 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -63,7 +63,10 @@ pub(crate) fn goto_implementation(
                 Definition::Trait(trait_) => impls_for_trait(&sema, trait_),
                 Definition::Adt(adt) => impls_for_ty(&sema, adt.ty(sema.db)),
                 Definition::TypeAlias(alias) => impls_for_ty(&sema, alias.ty(sema.db)),
-                Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)),
+                Definition::BuiltinType(builtin) => {
+                    let module = sema.to_module_def(position.file_id)?;
+                    impls_for_ty(&sema, builtin.ty(sema.db, module))
+                }
                 Definition::Function(f) => {
                     let assoc = f.as_assoc_item(sema.db)?;
                     let name = assoc.name(sema.db)?;
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 23b995dbb8..ec0435aad0 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -170,7 +170,7 @@ pub(crate) fn hover_for_definition(
     config: &HoverConfig,
 ) -> Option<HoverResult> {
     let famous_defs = match &definition {
-        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node)?.krate())),
+        Definition::BuiltinType(_) => Some(FamousDefs(sema, sema.scope(node).krate())),
         _ => None,
     };
     if let Some(markup) = render::definition(sema.db, definition, famous_defs.as_ref(), config) {
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 0676220272..b2b74ccce3 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -103,7 +103,7 @@ pub(super) fn try_expr(
 
     let adts = inner_ty.as_adt().zip(body_ty.as_adt());
     if let Some((hir::Adt::Enum(inner), hir::Adt::Enum(body))) = adts {
-        let famous_defs = FamousDefs(sema, sema.scope(try_expr.syntax())?.krate());
+        let famous_defs = FamousDefs(sema, sema.scope(try_expr.syntax()).krate());
         // special case for two options, there is no value in showing them
         if let Some(option_enum) = famous_defs.core_option_Option() {
             if inner == option_enum && body == option_enum {
@@ -234,7 +234,7 @@ pub(super) fn keyword(
         return None;
     }
     let parent = token.parent()?;
-    let famous_defs = FamousDefs(sema, sema.scope(&parent)?.krate());
+    let famous_defs = FamousDefs(sema, sema.scope(&parent).krate());
 
     let KeywordHint { description, keyword_mod, actions } = keyword_hints(sema, token, parent);
 
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index ba2b397f2a..4fdb7d0bc3 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -110,10 +110,7 @@ fn hints(
     config: &InlayHintsConfig,
     node: SyntaxNode,
 ) {
-    let krate = match sema.scope(&node) {
-        Some(it) => it.krate(),
-        None => return,
-    };
+    let krate = sema.scope(&node).module().map(|it| it.krate());
     let famous_defs = FamousDefs(sema, krate);
     if let Some(expr) = ast::Expr::cast(node.clone()) {
         chaining_hints(hints, sema, &famous_defs, config, &expr);
@@ -506,7 +503,7 @@ fn bind_pat_hints(
         return None;
     }
 
-    let krate = sema.scope(desc_pat.syntax())?.krate();
+    let krate = sema.scope(desc_pat.syntax()).module().map(|it| it.krate());
     let famous_defs = FamousDefs(sema, krate);
     let label = hint_iterator(sema, &famous_defs, config, &ty);
 
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index e986331105..7fcb09b5e2 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -64,7 +64,7 @@ use cfg::CfgOptions;
 use ide_db::{
     base_db::{
         salsa::{self, ParallelDatabase},
-        CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
+        Env, FileLoader, FileSet, SourceDatabase, VfsPath,
     },
     symbol_index, LineIndexDatabase,
 };
@@ -102,7 +102,7 @@ pub use ide_assists::{
     Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
 };
 pub use ide_completion::{
-    CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, Snippet,
+    CompletionConfig, CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit, Snippet,
     SnippetScope,
 };
 pub use ide_db::{
@@ -232,7 +232,7 @@ impl Analysis {
             Env::default(),
             Default::default(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            Default::default(),
         );
         change.change_file(file_id, Some(Arc::new(text)));
         change.set_crate_graph(crate_graph);
@@ -635,7 +635,7 @@ impl Analysis {
         self.with_db(|db| {
             let rule: ide_ssr::SsrRule = query.parse()?;
             let mut match_finder =
-                ide_ssr::MatchFinder::in_context(db, resolve_context, selections)?;
+                ide_ssr::MatchFinder::in_context(db, resolve_context, selections);
             match_finder.add_rule(rule)?;
             let edits = if parse_only { Default::default() } else { match_finder.edits() };
             Ok(SourceChange::from(edits))
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index 0f75abe55c..2e93d895f0 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -3,7 +3,7 @@
 
 use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics};
 use ide_db::{
-    base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin},
+    base_db::{CrateOrigin, FileId, FileLoader, FilePosition},
     defs::{Definition, IdentClass},
     helpers::pick_best_token,
     RootDatabase,
@@ -151,20 +151,11 @@ pub(crate) fn def_to_moniker(
             let name = krate.display_name(db)?.to_string();
             let (repo, version) = match krate.origin(db) {
                 CrateOrigin::CratesIo { repo } => (repo?, krate.version(db)?),
-                CrateOrigin::Lang(lang) => (
+                CrateOrigin::Lang => (
                     "https://github.com/rust-lang/rust/".to_string(),
-                    format!(
-                        "https://github.com/rust-lang/rust/library/{}",
-                        match lang {
-                            LangCrateOrigin::Alloc => "alloc",
-                            LangCrateOrigin::Core => "core",
-                            LangCrateOrigin::ProcMacro => "proc_macro",
-                            LangCrateOrigin::Std => "std",
-                            LangCrateOrigin::Test => "test",
-                            LangCrateOrigin::Other => "",
-                        }
-                    ),
+                    "compiler_version".to_string(),
                 ),
+                CrateOrigin::Unknown => return None,
             };
             PackageInformation { name, repo, version }
         },
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 1c455c5f30..bcb2c8797d 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -474,7 +474,7 @@ impl TestAttr {
     }
 }
 
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+const RUSTDOC_FENCE: &str = "```";
 const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUNNABLE: &[&str] =
     &["", "rust", "should_panic", "edition2015", "edition2018", "edition2021"];
 
@@ -483,9 +483,7 @@ fn has_runnable_doc_test(attrs: &hir::Attrs) -> bool {
         let mut in_code_block = false;
 
         for line in String::from(doc).lines() {
-            if let Some(header) =
-                RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
-            {
+            if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
                 in_code_block = !in_code_block;
 
                 if in_code_block
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index 6dc8b3046c..f33b09ed57 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -198,6 +198,9 @@ fn signature_help_for_generics(
             | hir::PathResolution::Def(hir::ModuleDef::Macro(_))
             | hir::PathResolution::Def(hir::ModuleDef::Module(_))
             | hir::PathResolution::Def(hir::ModuleDef::Static(_)) => return None,
+            hir::PathResolution::AssocItem(hir::AssocItem::Function(it)) => it.into(),
+            hir::PathResolution::AssocItem(hir::AssocItem::TypeAlias(it)) => it.into(),
+            hir::PathResolution::AssocItem(hir::AssocItem::Const(_)) => return None,
             hir::PathResolution::BuiltinAttr(_)
             | hir::PathResolution::ToolModule(_)
             | hir::PathResolution::Local(_)
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 908bbfde24..e5d4ed8b92 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -179,16 +179,12 @@ pub(crate) fn highlight(
     };
 
     let mut hl = highlights::Highlights::new(root.text_range());
-    let krate = match sema.scope(&root) {
-        Some(it) => it.krate(),
-        None => return hl.to_vec(),
-    };
     traverse(
         &mut hl,
         &sema,
         file_id,
         &root,
-        krate,
+        sema.scope(&root).krate(),
         range_to_highlight,
         syntactic_name_ref_highlighting,
     );
@@ -200,7 +196,7 @@ fn traverse(
     sema: &Semantics<RootDatabase>,
     file_id: FileId,
     root: &SyntaxNode,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     range_to_highlight: TextRange,
     syntactic_name_ref_highlighting: bool,
 ) {
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 5fb87598f4..7ac6775685 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,6 +3,7 @@
 use hir::{AsAssocItem, HasVisibility, Semantics};
 use ide_db::{
     defs::{Definition, IdentClass, NameClass, NameRefClass},
+    famous_defs::FamousDefs,
     RootDatabase, SymbolKind,
 };
 use rustc_hash::FxHashMap;
@@ -48,7 +49,7 @@ pub(super) fn token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Optio
 
 pub(super) fn name_like(
     sema: &Semantics<RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
     syntactic_name_ref_highlighting: bool,
     name_like: ast::NameLike,
@@ -192,7 +193,7 @@ fn keyword(
 
 fn highlight_name_ref(
     sema: &Semantics<RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
     binding_hash: &mut Option<u64>,
     syntactic_name_ref_highlighting: bool,
@@ -278,7 +279,7 @@ fn highlight_name(
     sema: &Semantics<RootDatabase>,
     bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
     binding_hash: &mut Option<u64>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     name: ast::Name,
 ) -> Highlight {
     let name_kind = NameClass::classify(sema, &name);
@@ -322,7 +323,11 @@ fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
     hash((name, shadow_count))
 }
 
-fn highlight_def(sema: &Semantics<RootDatabase>, krate: hir::Crate, def: Definition) -> Highlight {
+fn highlight_def(
+    sema: &Semantics<RootDatabase>,
+    krate: Option<hir::Crate>,
+    def: Definition,
+) -> Highlight {
     let db = sema.db;
     let mut h = match def {
         Definition::Macro(m) => Highlight::new(HlTag::Symbol(m.kind(sema.db).into())),
@@ -467,12 +472,14 @@ fn highlight_def(sema: &Semantics<RootDatabase>, krate: hir::Crate, def: Definit
         Definition::ToolModule(_) => Highlight::new(HlTag::Symbol(SymbolKind::ToolModule)),
     };
 
+    let famous_defs = FamousDefs(sema, krate);
     let def_crate = def.module(db).map(hir::Module::krate).or_else(|| match def {
         Definition::Module(module) => Some(module.krate()),
         _ => None,
     });
-    let is_from_other_crate = def_crate != Some(krate);
-    let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db));
+    let is_from_other_crate = def_crate != krate;
+    let is_from_builtin_crate =
+        def_crate.map_or(false, |def_crate| famous_defs.builtin_crates().any(|it| def_crate == it));
     let is_builtin_type = matches!(def, Definition::BuiltinType(_));
     let is_public = def.visibility(db) == Some(hir::Visibility::Public);
 
@@ -491,7 +498,7 @@ fn highlight_def(sema: &Semantics<RootDatabase>, krate: hir::Crate, def: Definit
 
 fn highlight_method_call_by_name_ref(
     sema: &Semantics<RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     name_ref: &ast::NameRef,
 ) -> Option<Highlight> {
     let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
@@ -500,7 +507,7 @@ fn highlight_method_call_by_name_ref(
 
 fn highlight_method_call(
     sema: &Semantics<RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
     method_call: &ast::MethodCallExpr,
 ) -> Option<Highlight> {
     let func = sema.resolve_method_call(method_call)?;
@@ -518,9 +525,10 @@ fn highlight_method_call(
         h |= HlMod::Trait;
     }
 
+    let famous_defs = FamousDefs(sema, krate);
     let def_crate = func.module(sema.db).krate();
-    let is_from_other_crate = def_crate != krate;
-    let is_from_builtin_crate = def_crate.is_builtin(sema.db);
+    let is_from_other_crate = Some(def_crate) != krate;
+    let is_from_builtin_crate = famous_defs.builtin_crates().any(|it| def_crate == it);
     let is_public = func.visibility(sema.db) == hir::Visibility::Public;
 
     if is_from_other_crate {
@@ -585,7 +593,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
 fn highlight_name_ref_by_syntax(
     name: ast::NameRef,
     sema: &Semantics<RootDatabase>,
-    krate: hir::Crate,
+    krate: Option<hir::Crate>,
 ) -> Highlight {
     let default = HlTag::UnresolvedReference;
 
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 8ac3c2da50..8af0d8007d 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -78,8 +78,7 @@ pub(super) fn ra_fixture(
     Some(())
 }
 
-const RUSTDOC_FENCE_LENGTH: usize = 3;
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+const RUSTDOC_FENCE: &str = "```";
 
 /// Injection of syntax highlighting of doctests.
 pub(super) fn doc_comment(
@@ -167,11 +166,11 @@ pub(super) fn doc_comment(
             };
             let mut pos = TextSize::from(0);
 
-            match RUSTDOC_FENCES.into_iter().find_map(|fence| line.find(fence)) {
+            match line.find(RUSTDOC_FENCE) {
                 Some(idx) => {
                     is_codeblock = !is_codeblock;
                     // Check whether code is rust by inspecting fence guards
-                    let guards = &line[idx + RUSTDOC_FENCE_LENGTH..];
+                    let guards = &line[idx + RUSTDOC_FENCE.len()..];
                     let is_rust = is_rust_fence(guards);
                     is_doctest = is_codeblock && is_rust;
                     continue;
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs
index 6b7db739c8..11f12773e8 100644
--- a/crates/ide_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ide_assists/src/handlers/add_explicit_type.rs
@@ -41,7 +41,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
         return None;
     };
 
-    let module = ctx.sema.scope(pat.syntax())?.module();
+    let module = ctx.sema.scope(pat.syntax()).module()?;
     let pat_range = pat.syntax().text_range();
 
     // Don't enable the assist if there is a type ascription without any placeholders
diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
index 6e700695fb..c82caa3704 100644
--- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
@@ -104,7 +104,6 @@ fn add_missing_impl_members_inner(
 ) -> Option<()> {
     let _p = profile::span("add_missing_impl_members_inner");
     let impl_def = ctx.find_node_at_offset::<ast::Impl>()?;
-    let target_scope = ctx.sema.scope(impl_def.syntax())?;
     let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?;
 
     let missing_items = filter_assoc_items(
@@ -119,6 +118,7 @@ fn add_missing_impl_members_inner(
 
     let target = impl_def.syntax().text_range();
     acc.add(AssistId(assist_id, AssistKind::QuickFix), label, target, |builder| {
+        let target_scope = ctx.sema.scope(impl_def.syntax());
         let missing_items = missing_items
             .into_iter()
             .map(|it| {
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 171b3f4432..0dc67ede36 100644
--- a/crates/ide_assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide_assists/src/handlers/add_missing_match_arms.rs
@@ -73,7 +73,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
         .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
         .collect();
 
-    let module = ctx.sema.scope(expr.syntax())?.module();
+    let module = ctx.sema.scope(expr.syntax()).module()?;
     let (mut missing_pats, is_non_exhaustive): (
         Peekable<Box<dyn Iterator<Item = (ast::Pat, bool)>>>,
         bool,
@@ -92,7 +92,8 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext) ->
             })
             .filter(|(variant_pat, _)| is_variant_missing(&top_lvl_pats, variant_pat));
 
-        let option_enum = FamousDefs(&ctx.sema, module.krate()).core_option_Option().map(lift_enum);
+        let option_enum =
+            FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option().map(lift_enum);
         let missing_pats: Box<dyn Iterator<Item = _>> = if Some(enum_def) == option_enum {
             // Match `Some` variant first.
             cov_mark::hit!(option_order);
diff --git a/crates/ide_assists/src/handlers/add_return_type.rs b/crates/ide_assists/src/handlers/add_return_type.rs
index 42a5b8b672..2c5b61eddb 100644
--- a/crates/ide_assists/src/handlers/add_return_type.rs
+++ b/crates/ide_assists/src/handlers/add_return_type.rs
@@ -1,5 +1,5 @@
 use hir::HirDisplay;
-use syntax::{ast, match_ast, AstNode, SyntaxKind, SyntaxToken, TextRange, TextSize};
+use syntax::{ast, AstNode, SyntaxKind, SyntaxToken, TextRange, TextSize};
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 
@@ -17,8 +17,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 // ```
 pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let (fn_type, tail_expr, builder_edit_pos) = extract_tail(ctx)?;
-    let module = ctx.sema.scope(tail_expr.syntax())?.module();
-    let ty = ctx.sema.type_of_expr(&peel_blocks(tail_expr.clone()))?.original();
+    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
+    let ty = ctx.sema.type_of_expr(&tail_expr)?.adjusted();
     if ty.is_unit() {
         return None;
     }
@@ -93,45 +93,6 @@ enum FnType {
     Closure { wrap_expr: bool },
 }
 
-/// If we're looking at a block that is supposed to return `()`, type inference
-/// will just tell us it has type `()`. We have to look at the tail expression
-/// to see the mismatched actual type. This 'unpeels' the various blocks to
-/// hopefully let us see the type the user intends. (This still doesn't handle
-/// all situations fully correctly; the 'ideal' way to handle this would be to
-/// run type inference on the function again, but with a variable as the return
-/// type.)
-fn peel_blocks(mut expr: ast::Expr) -> ast::Expr {
-    loop {
-        match_ast! {
-            match (expr.syntax()) {
-                ast::BlockExpr(it) => {
-                    if let Some(tail) = it.tail_expr() {
-                        expr = tail.clone();
-                    } else {
-                        break;
-                    }
-                },
-                ast::IfExpr(it) => {
-                    if let Some(then_branch) = it.then_branch() {
-                        expr = ast::Expr::BlockExpr(then_branch.clone());
-                    } else {
-                        break;
-                    }
-                },
-                ast::MatchExpr(it) => {
-                    if let Some(arm_expr) = it.match_arm_list().and_then(|l| l.arms().next()).and_then(|a| a.expr()) {
-                        expr = arm_expr;
-                    } else {
-                        break;
-                    }
-                },
-                _ => break,
-            }
-        }
-    }
-    expr
-}
-
 fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrReplace)> {
     let (fn_type, tail_expr, return_type_range, action) =
         if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
@@ -287,25 +248,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn infer_return_type_nested_match() {
-        check_assist(
-            add_return_type,
-            r#"fn foo() {
-    match true {
-        true => { 3$0 },
-        false => { 5 },
-    }
-}"#,
-            r#"fn foo() -> i32 {
-    match true {
-        true => { 3 },
-        false => { 5 },
-    }
-}"#,
-        );
-    }
-
     #[test]
     fn not_applicable_ret_type_specified() {
         cov_mark::check!(existing_ret_type);
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 874563c6f7..5a2809a1cf 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -54,9 +54,9 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 // The style of imports in the same crate is configurable through the `importPrefix` setting.
 // It has the following configurations:
 //
-// - `crate`: This setting will force paths to be always absolute, starting with the `crate`
+// - `by_crate`: This setting will force paths to be always absolute, starting with the `crate`
 //  prefix, unless the item is defined outside of the current crate.
-// - `self`: This setting will force paths that are relative to the current module to always
+// - `by_self`: This setting will force paths that are relative to the current module to always
 //  start with `self`. This will result in paths that always start with either `crate`, `self`,
 //  `super` or an extern crate identifier.
 // - `plain`: This setting does not impose any restrictions in imports.
diff --git a/crates/ide_assists/src/handlers/convert_bool_then.rs b/crates/ide_assists/src/handlers/convert_bool_then.rs
index f07fde07c0..daec28999e 100644
--- a/crates/ide_assists/src/handlers/convert_bool_then.rs
+++ b/crates/ide_assists/src/handlers/convert_bool_then.rs
@@ -222,7 +222,7 @@ fn option_variants(
     sema: &Semantics<RootDatabase>,
     expr: &SyntaxNode,
 ) -> Option<(hir::Variant, hir::Variant)> {
-    let fam = FamousDefs(sema, sema.scope(expr)?.krate());
+    let fam = FamousDefs(sema, sema.scope(expr).krate());
     let option_variants = fam.core_option_Option()?.variants(sema.db);
     match &*option_variants {
         &[variant0, variant1] => Some(if variant0.name(sema.db) == known::None {
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs
index 869f76951d..9185501a62 100644
--- a/crates/ide_assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs
@@ -36,10 +36,10 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext) -> Op
     let src_type = impl_.self_ty()?;
     let ast_trait = impl_.trait_()?;
 
-    let module = ctx.sema.scope(impl_.syntax())?.module();
+    let module = ctx.sema.scope(impl_.syntax()).module()?;
 
     let trait_ = resolve_target_trait(&ctx.sema, &impl_)?;
-    if trait_ != FamousDefs(&ctx.sema, module.krate()).core_convert_Into()? {
+    if trait_ != FamousDefs(&ctx.sema, Some(module.krate())).core_convert_Into()? {
         return None;
     }
 
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 711b914561..bb75cb5c95 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
@@ -146,10 +146,10 @@ fn is_ref_and_impls_iter_method(
     let wanted_method = if ref_expr.mut_token().is_some() { known::iter_mut } else { known::iter };
     let expr_behind_ref = ref_expr.expr()?;
     let ty = sema.type_of_expr(&expr_behind_ref)?.adjusted();
-    let scope = sema.scope(iterable.syntax())?;
-    let krate = scope.krate();
+    let scope = sema.scope(iterable.syntax());
+    let krate = scope.module()?.krate();
     let traits_in_scope = scope.visible_traits();
-    let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
+    let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
 
     let has_wanted_method = ty
         .iterate_method_candidates(
@@ -175,17 +175,24 @@ fn is_ref_and_impls_iter_method(
 
 /// Whether iterable implements core::Iterator
 fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool {
-    (|| {
-        let it_typ = sema.type_of_expr(iterable)?.adjusted();
+    let it_typ = match sema.type_of_expr(iterable) {
+        Some(it) => it.adjusted(),
+        None => return false,
+    };
 
-        let module = sema.scope(iterable.syntax())?.module();
+    let module = match sema.scope(iterable.syntax()).module() {
+        Some(it) => it,
+        None => return false,
+    };
 
-        let krate = module.krate();
-        let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
-        cov_mark::hit!(test_already_impls_iterator);
-        Some(it_typ.impls_trait(sema.db, iter_trait, &[]))
-    })()
-    .unwrap_or(false)
+    let krate = module.krate();
+    match FamousDefs(sema, Some(krate)).core_iter_Iterator() {
+        Some(iter_trait) => {
+            cov_mark::hit!(test_already_impls_iterator);
+            it_typ.impls_trait(sema.db, iter_trait, &[])
+        }
+        None => false,
+    }
 }
 
 fn validate_method_call_expr(
@@ -207,10 +214,10 @@ fn validate_method_call_expr(
     let expr = ast::Expr::MethodCallExpr(expr);
 
     let it_type = sema.type_of_expr(&receiver)?.adjusted();
-    let module = sema.scope(receiver.syntax())?.module();
+    let module = sema.scope(receiver.syntax()).module()?;
     let krate = module.krate();
 
-    let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
+    let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
     it_type.impls_trait(sema.db, iter_trait, &[]).then(|| (expr, receiver))
 }
 
diff --git a/crates/ide_assists/src/handlers/expand_glob_import.rs b/crates/ide_assists/src/handlers/expand_glob_import.rs
index 3566b1be89..135f2a70b7 100644
--- a/crates/ide_assists/src/handlers/expand_glob_import.rs
+++ b/crates/ide_assists/src/handlers/expand_glob_import.rs
@@ -49,8 +49,8 @@ pub(crate) fn expand_glob_import(acc: &mut Assists, ctx: &AssistContext) -> Opti
         _ => return None,
     };
 
-    let current_scope = ctx.sema.scope(&star.parent()?)?;
-    let current_module = current_scope.module();
+    let current_scope = ctx.sema.scope(&star.parent()?);
+    let current_module = current_scope.module()?;
 
     let refs_in_target = find_refs_in_mod(ctx, target_module, Some(current_module))?;
     let imported_defs = find_imported_defs(ctx, star)?;
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index c26e4b1c75..8352774be4 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -81,7 +81,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
 
     let anchor = if self_param.is_some() { Anchor::Method } else { Anchor::Freestanding };
     let insert_after = node_to_insert_after(&body, anchor)?;
-    let module = ctx.sema.scope(&insert_after)?.module();
+    let module = ctx.sema.scope(&insert_after).module()?;
 
     let ret_ty = body.return_ty(ctx)?;
     let control_flow = body.external_control_flow(ctx, &container_info)?;
@@ -132,7 +132,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
                 };
 
                 let control_flow_enum =
-                    FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow();
+                    FamousDefs(&ctx.sema, Some(module.krate())).core_ops_ControlFlow();
 
                 if let Some(control_flow_enum) = control_flow_enum {
                     let mod_path = module.find_use_path_prefixed(
@@ -4162,7 +4162,7 @@ fn main() {
     match 6 {
         100 => $0{ 100 }$0
         _ => 0,
-    };
+    }
 }
 "#,
             r#"
@@ -4170,7 +4170,7 @@ fn main() {
     match 6 {
         100 => fun_name(),
         _ => 0,
-    };
+    }
 }
 
 fn $0fun_name() -> i32 {
@@ -4185,7 +4185,7 @@ fn main() {
     match 6 {
         100 => $0{ 100 }$0,
         _ => 0,
-    };
+    }
 }
 "#,
             r#"
@@ -4193,7 +4193,7 @@ fn main() {
     match 6 {
         100 => fun_name(),
         _ => 0,
-    };
+    }
 }
 
 fn $0fun_name() -> i32 {
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index 45f98e690f..4b597837aa 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -423,7 +423,7 @@ fn reference_to_node(
             _ => return None,
         }
     };
-    let module = sema.scope(&expr_or_pat)?.module();
+    let module = sema.scope(&expr_or_pat).module()?;
     Some((segment, expr_or_pat, module))
 }
 
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs
index b895208f41..bbb5cf9187 100644
--- a/crates/ide_assists/src/handlers/fix_visibility.rs
+++ b/crates/ide_assists/src/handlers/fix_visibility.rs
@@ -43,7 +43,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
         _ => return None,
     };
 
-    let current_module = ctx.sema.scope(path.syntax())?.module();
+    let current_module = ctx.sema.scope(path.syntax()).module()?;
     let target_module = def.module(ctx.db())?;
 
     if def.visibility(ctx.db()).is_visible_from(ctx.db(), current_module.into()) {
@@ -86,7 +86,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) ->
     let record_field: ast::RecordExprField = ctx.find_node_at_offset()?;
     let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?;
 
-    let current_module = ctx.sema.scope(record_field.syntax())?.module();
+    let current_module = ctx.sema.scope(record_field.syntax()).module()?;
     let visibility = record_field_def.visibility(ctx.db());
     if visibility.is_visible_from(ctx.db(), current_module.into()) {
         return None;
diff --git a/crates/ide_assists/src/handlers/generate_constant.rs b/crates/ide_assists/src/handlers/generate_constant.rs
index c4b759d5f3..52ae60e2ed 100644
--- a/crates/ide_assists/src/handlers/generate_constant.rs
+++ b/crates/ide_assists/src/handlers/generate_constant.rs
@@ -35,8 +35,8 @@ pub(crate) fn generate_constant(acc: &mut Assists, ctx: &AssistContext) -> Optio
     let expr = constant_token.syntax().ancestors().find_map(ast::Expr::cast)?;
     let statement = expr.syntax().ancestors().find_map(ast::Stmt::cast)?;
     let ty = ctx.sema.type_of_expr(&expr)?;
-    let scope = ctx.sema.scope(statement.syntax())?;
-    let module = scope.module();
+    let scope = ctx.sema.scope(statement.syntax());
+    let module = scope.module()?;
     let type_name = ty.original().display_source_code(ctx.db(), module.into()).ok()?;
     let indent = IndentLevel::from_node(statement.syntax());
     if constant_token.to_string().chars().any(|it| !(it.is_uppercase() || it == '_')) {
diff --git a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
index 4d47437f7c..4745ac24e9 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_enum_variant.rs
@@ -75,7 +75,7 @@ fn existing_default_impl(
     let enum_ = variant.parent_enum(sema.db);
     let krate = enum_.module(sema.db).krate();
 
-    let default_trait = FamousDefs(sema, krate).core_default_Default()?;
+    let default_trait = FamousDefs(sema, Some(krate)).core_default_Default()?;
     let enum_type = enum_.ty(sema.db);
 
     if enum_type.impls_trait(sema.db, default_trait, &[]) {
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index 119bb6e07b..669fb28d10 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -132,7 +132,7 @@ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
 
     let ty = impl_def.self_ty(db);
     let krate = impl_def.module(db).krate();
-    let default = FamousDefs(&ctx.sema, krate).core_default_Default();
+    let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
     let default_trait = match default {
         Some(value) => value,
         None => return false,
diff --git a/crates/ide_assists/src/handlers/generate_delegate_methods.rs b/crates/ide_assists/src/handlers/generate_delegate_methods.rs
index 120acde8e5..f6e0d619de 100644
--- a/crates/ide_assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide_assists/src/handlers/generate_delegate_methods.rs
@@ -45,7 +45,7 @@ use syntax::ast::edit::AstNodeEdit;
 pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
     let strukt_name = strukt.name()?;
-    let current_module = ctx.sema.scope(strukt.syntax())?.module();
+    let current_module = ctx.sema.scope(strukt.syntax()).module()?;
 
     let (field_name, field_ty, target) = match ctx.find_node_at_offset::<ast::RecordField>() {
         Some(field) => {
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs
index 3cb8a68687..4328c54c09 100644
--- a/crates/ide_assists/src/handlers/generate_deref.rs
+++ b/crates/ide_assists/src/handlers/generate_deref.rs
@@ -110,7 +110,7 @@ fn existing_deref_impl(
     let strukt = sema.to_def(strukt)?;
     let krate = strukt.module(sema.db).krate();
 
-    let deref_trait = FamousDefs(sema, krate).core_ops_Deref()?;
+    let deref_trait = FamousDefs(sema, Some(krate)).core_ops_Deref()?;
     let strukt_type = strukt.ty(sema.db);
 
     if strukt_type.impls_trait(sema.db, deref_trait, &[]) {
diff --git a/crates/ide_assists/src/handlers/generate_documentation_template.rs b/crates/ide_assists/src/handlers/generate_documentation_template.rs
index 3eaa445d32..15a07492ec 100644
--- a/crates/ide_assists/src/handlers/generate_documentation_template.rs
+++ b/crates/ide_assists/src/handlers/generate_documentation_template.rs
@@ -202,7 +202,7 @@ fn all_parent_mods_public(hir_func: &hir::Function, ctx: &AssistContext) -> bool
 
 /// Returns the name of the current crate
 fn crate_name(ast_func: &ast::Fn, ctx: &AssistContext) -> Option<String> {
-    let krate = ctx.sema.scope(ast_func.syntax())?.krate();
+    let krate = ctx.sema.scope(ast_func.syntax()).module()?.krate();
     Some(krate.display_name(ctx.db())?.to_string())
 }
 
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
index 28e0b433a6..863ada79ba 100644
--- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
@@ -1,4 +1,3 @@
-use ide_db::assists::GroupLabel;
 use stdx::to_lower_snake_case;
 use syntax::ast::HasVisibility;
 use syntax::ast::{self, AstNode, HasName};
@@ -10,7 +9,7 @@ use crate::{
 
 // Assist: generate_enum_is_method
 //
-// Generate an `is_` method for this enum variant.
+// Generate an `is_` method for an enum variant.
 //
 // ```
 // enum Version {
@@ -55,10 +54,9 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
     let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
 
     let target = variant.syntax().text_range();
-    acc.add_group(
-        &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
+    acc.add(
         AssistId("generate_enum_is_method", AssistKind::Generate),
-        "Generate an `is_` method for this enum variant",
+        "Generate an `is_` method for an enum variant",
         target,
         |builder| {
             let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
diff --git a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
index fe7a3cd535..a9116be67c 100644
--- a/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_projection_method.rs
@@ -1,4 +1,3 @@
-use ide_db::assists::GroupLabel;
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::ast::HasVisibility;
@@ -11,7 +10,7 @@ use crate::{
 
 // Assist: generate_enum_try_into_method
 //
-// Generate a `try_into_` method for this enum variant.
+// Generate an `try_into_` method for an enum variant.
 //
 // ```
 // enum Value {
@@ -41,7 +40,7 @@ pub(crate) fn generate_enum_try_into_method(acc: &mut Assists, ctx: &AssistConte
         acc,
         ctx,
         "generate_enum_try_into_method",
-        "Generate a `try_into_` method for this enum variant",
+        "Generate an `try_into_` method for an enum variant",
         ProjectionProps {
             fn_name_prefix: "try_into",
             self_param: "self",
@@ -55,7 +54,7 @@ pub(crate) fn generate_enum_try_into_method(acc: &mut Assists, ctx: &AssistConte
 
 // Assist: generate_enum_as_method
 //
-// Generate an `as_` method for this enum variant.
+// Generate an `as_` method for an enum variant.
 //
 // ```
 // enum Value {
@@ -85,7 +84,7 @@ pub(crate) fn generate_enum_as_method(acc: &mut Assists, ctx: &AssistContext) ->
         acc,
         ctx,
         "generate_enum_as_method",
-        "Generate an `as_` method for this enum variant",
+        "Generate an `as_` method for an enum variant",
         ProjectionProps {
             fn_name_prefix: "as",
             self_param: "&self",
@@ -140,37 +139,31 @@ fn generate_enum_projection_method(
     let impl_def = find_struct_impl(ctx, &parent_enum, &fn_name)?;
 
     let target = variant.syntax().text_range();
-    acc.add_group(
-        &GroupLabel("Generate an `is_`,`as_`, or `try_into_` for this enum variant".to_owned()),
-        AssistId(assist_id, AssistKind::Generate),
-        assist_description,
-        target,
-        |builder| {
-            let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
-            let method = format!(
-                "    {0}fn {1}({2}) -> {3}{4}{5} {{
+    acc.add(AssistId(assist_id, AssistKind::Generate), assist_description, target, |builder| {
+        let vis = parent_enum.visibility().map_or(String::new(), |v| format!("{} ", v));
+        let method = format!(
+            "    {0}fn {1}({2}) -> {3}{4}{5} {{
         if let Self::{6}{7} = self {{
             {8}({9})
         }} else {{
             {10}
         }}
     }}",
-                vis,
-                fn_name,
-                props.self_param,
-                props.return_prefix,
-                field_type.syntax(),
-                props.return_suffix,
-                variant_name,
-                pattern_suffix,
-                props.happy_case,
-                bound_name,
-                props.sad_case,
-            );
+            vis,
+            fn_name,
+            props.self_param,
+            props.return_prefix,
+            field_type.syntax(),
+            props.return_suffix,
+            variant_name,
+            pattern_suffix,
+            props.happy_case,
+            bound_name,
+            props.sad_case,
+        );
 
-            add_method_to_adt(builder, &parent_enum, impl_def, &method);
-        },
-    )
+        add_method_to_adt(builder, &parent_enum, impl_def, &method);
+    })
 }
 
 #[cfg(test)]
diff --git a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
index f7be323824..ee8de5a20e 100644
--- a/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
+++ b/crates/ide_assists/src/handlers/generate_from_impl_for_enum.rs
@@ -5,7 +5,7 @@ use crate::{utils::generate_trait_impl_text, AssistContext, AssistId, AssistKind
 
 // Assist: generate_from_impl_for_enum
 //
-// Adds a From impl for this enum variant with one tuple field.
+// Adds a From impl for an enum variant with one tuple field.
 //
 // ```
 // enum A { $0One(u32) }
@@ -86,7 +86,7 @@ fn existing_from_impl(
     let enum_ = variant.parent_enum(sema.db);
     let krate = enum_.module(sema.db).krate();
 
-    let from_trait = FamousDefs(sema, krate).core_convert_From()?;
+    let from_trait = FamousDefs(sema, Some(krate)).core_convert_From()?;
 
     let enum_type = enum_.ty(sema.db);
 
diff --git a/crates/ide_assists/src/handlers/generate_function.rs b/crates/ide_assists/src/handlers/generate_function.rs
index ae4436ce88..c06498a4c9 100644
--- a/crates/ide_assists/src/handlers/generate_function.rs
+++ b/crates/ide_assists/src/handlers/generate_function.rs
@@ -73,7 +73,7 @@ fn gen_fn(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
                 get_fn_target(ctx, &target_module, call.clone())?
             }
             Some(hir::PathResolution::Def(hir::ModuleDef::Adt(adt))) => {
-                let current_module = ctx.sema.scope(call.syntax())?.module();
+                let current_module = current_module(call.syntax(), ctx)?;
                 let module = adt.module(ctx.sema.db);
                 target_module = if current_module == module { None } else { Some(module) };
                 if current_module.krate() != module.krate() {
@@ -117,7 +117,7 @@ fn gen_method(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let fn_name = call.name_ref()?;
     let adt = ctx.sema.type_of_expr(&call.receiver()?)?.original().strip_references().as_adt()?;
 
-    let current_module = ctx.sema.scope(call.syntax())?.module();
+    let current_module = current_module(call.syntax(), ctx)?;
     let target_module = adt.module(ctx.sema.db);
 
     if current_module.krate() != target_module.krate() {
@@ -166,6 +166,10 @@ fn add_func_to_accumulator(
     })
 }
 
+fn current_module(current_node: &SyntaxNode, ctx: &AssistContext) -> Option<Module> {
+    ctx.sema.scope(current_node).module()
+}
+
 fn get_adt_source(
     ctx: &AssistContext,
     adt: &hir::Adt,
@@ -231,8 +235,7 @@ impl FunctionBuilder {
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
         let needs_pub = target_module.is_some();
-        let target_module =
-            target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
+        let target_module = target_module.or_else(|| current_module(target.syntax(), ctx))?;
         let fn_name = make::name(fn_name);
         let (type_params, params) =
             fn_args(ctx, target_module, ast::CallableExpr::Call(call.clone()))?;
@@ -263,7 +266,7 @@ impl FunctionBuilder {
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
         let needs_pub =
-            !module_is_descendant(&ctx.sema.scope(call.syntax())?.module(), &target_module, ctx);
+            !module_is_descendant(&current_module(call.syntax(), ctx)?, &target_module, ctx);
         let fn_name = make::name(&name.text());
         let (type_params, params) =
             fn_args(ctx, target_module, ast::CallableExpr::MethodCall(call.clone()))?;
@@ -517,7 +520,7 @@ fn fn_arg_type(ctx: &AssistContext, target_module: hir::Module, fn_arg: &ast::Ex
         }
 
         if ty.is_reference() || ty.is_mutable_reference() {
-            let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
+            let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax()).krate());
             convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
                 .map(|conversion| conversion.convert_type(ctx.db()))
                 .or_else(|| ty.display_source_code(ctx.db(), target_module.into()).ok())
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index 9513c112f3..2e81dd13f4 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -121,24 +121,25 @@ pub(crate) fn generate_getter_impl(
                     "a mutable reference to ",
                 )
             } else {
-                (|| {
-                    let krate = ctx.sema.scope(field_ty.syntax())?.krate();
-                    let famous_defs = &FamousDefs(&ctx.sema, krate);
-                    ctx.sema
-                        .resolve_type(&field_ty)
-                        .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
-                        .map(|conversion| {
-                            cov_mark::hit!(convert_reference_type);
-                            (
-                                conversion.convert_type(ctx.db()),
-                                conversion.getter(field_name.to_string()),
-                                if conversion.is_copy() { "" } else { "a reference to " },
-                            )
-                        })
-                })()
-                .unwrap_or_else(|| {
-                    (format!("&{}", field_ty), format!("&self.{}", field_name), "a reference to ")
-                })
+                let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(field_ty.syntax()).krate());
+                ctx.sema
+                    .resolve_type(&field_ty)
+                    .and_then(|ty| convert_reference_type(ty, ctx.db(), famous_defs))
+                    .map(|conversion| {
+                        cov_mark::hit!(convert_reference_type);
+                        (
+                            conversion.convert_type(ctx.db()),
+                            conversion.getter(field_name.to_string()),
+                            if conversion.is_copy() { "" } else { "a reference to " },
+                        )
+                    })
+                    .unwrap_or_else(|| {
+                        (
+                            format!("&{}", field_ty),
+                            format!("&self.{}", field_name),
+                            "a reference to ",
+                        )
+                    })
             };
 
             format_to!(
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 1ad1cea43f..bd7c85c443 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
@@ -93,7 +93,7 @@ fn get_impl_method(
     let db = ctx.sema.db;
     let impl_def: hir::Impl = ctx.sema.to_def(impl_)?;
 
-    let scope = ctx.sema.scope(impl_.syntax())?;
+    let scope = ctx.sema.scope(impl_.syntax());
     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| {
diff --git a/crates/ide_assists/src/handlers/inline_call.rs b/crates/ide_assists/src/handlers/inline_call.rs
index af2cb332e5..994d78303f 100644
--- a/crates/ide_assists/src/handlers/inline_call.rs
+++ b/crates/ide_assists/src/handlers/inline_call.rs
@@ -185,6 +185,7 @@ pub(crate) fn inline_call(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
             }?;
             let function = match ctx.sema.resolve_path(&path)? {
                 PathResolution::Def(hir::ModuleDef::Function(f)) => f,
+                PathResolution::AssocItem(hir::AssocItem::Function(f)) => f,
                 _ => return None,
             };
             (function, format!("Inline `{}`", path))
@@ -390,11 +391,13 @@ fn inline(
         }
     }
     if let Some(generic_arg_list) = generic_arg_list.clone() {
-        if let Some((target, source)) = &sema.scope(node.syntax()).zip(sema.scope(fn_body.syntax()))
-        {
-            PathTransform::function_call(target, source, function, generic_arg_list)
-                .apply(body.syntax());
-        }
+        PathTransform::function_call(
+            &sema.scope(node.syntax()),
+            &sema.scope(fn_body.syntax()),
+            function,
+            generic_arg_list,
+        )
+        .apply(body.syntax());
     }
 
     let original_indentation = match node {
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index e35c962a3f..705ae66617 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -330,7 +330,7 @@ use std$0::{fmt::*};
 use std::{fmt::{self, Display}};
 ",
             r"
-use std::{fmt::{self, *, Display}};
+use std::{fmt::{*, self, Display}};
 ",
         )
     }
@@ -440,4 +440,18 @@ use std::$0
 fn main() {}",
         );
     }
+
+    #[test]
+    fn split_glob() {
+        check_assist(
+            merge_imports,
+            r"
+use foo::$0*;
+use foo::bar::Baz;
+",
+            r"
+use foo::{*, bar::Baz};
+",
+        );
+    }
 }
diff --git a/crates/ide_assists/src/handlers/promote_local_to_const.rs b/crates/ide_assists/src/handlers/promote_local_to_const.rs
index 65c14406f9..58cee8eafb 100644
--- a/crates/ide_assists/src/handlers/promote_local_to_const.rs
+++ b/crates/ide_assists/src/handlers/promote_local_to_const.rs
@@ -53,7 +53,7 @@ pub(crate) fn promote_local_to_const(acc: &mut Assists, ctx: &AssistContext) ->
     }
     let let_stmt = pat.syntax().parent().and_then(ast::LetStmt::cast)?;
 
-    let module = ctx.sema.scope(pat.syntax())?.module();
+    let module = ctx.sema.scope(pat.syntax()).module()?;
     let local = ctx.sema.to_def(&pat)?;
     let ty = ctx.sema.type_of_pat(&pat.into())?.original;
 
diff --git a/crates/ide_assists/src/handlers/qualify_method_call.rs b/crates/ide_assists/src/handlers/qualify_method_call.rs
index ba0a142718..0f232caab6 100644
--- a/crates/ide_assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide_assists/src/handlers/qualify_method_call.rs
@@ -44,7 +44,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext) -> Opt
     let range = call.syntax().text_range();
     let resolved_call = ctx.sema.resolve_method_call(&call)?;
 
-    let current_module = ctx.sema.scope(call.syntax())?.module();
+    let current_module = ctx.sema.scope(call.syntax()).module()?;
     let target_module_def = ModuleDef::from(resolved_call);
     let item_in_ns = ItemInNs::from(target_module_def);
     let receiver_path = current_module
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index 03e41b4340..0d0bd7071f 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -69,7 +69,7 @@ pub(crate) fn replace_derive_with_manual_impl(
     let attr = ast::Attr::cast(value)?;
     let args = attr.token_tree()?;
 
-    let current_module = ctx.sema.scope(adt.syntax())?.module();
+    let current_module = ctx.sema.scope(adt.syntax()).module()?;
     let current_crate = current_module.krate();
 
     let found_traits = items_locator::items_with_name(
@@ -177,7 +177,7 @@ fn impl_def_from_trait(
     trait_path: &ast::Path,
 ) -> Option<(ast::Impl, ast::AssocItem)> {
     let trait_ = trait_?;
-    let target_scope = sema.scope(annotated_name.syntax())?;
+    let target_scope = sema.scope(annotated_name.syntax());
     let trait_items = filter_assoc_items(sema, &trait_.items(sema.db), DefaultMethods::No);
     if trait_items.is_empty() {
         return None;
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 4800d54956..b23b5bf87c 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -63,11 +63,9 @@ pub(crate) fn replace_qualified_name_with_use(
     );
     let path_to_qualifier = starts_with_name_ref
         .then(|| {
-            ctx.sema.scope(path.syntax())?.module().find_use_path_prefixed(
-                ctx.sema.db,
-                module,
-                ctx.config.insert_use.prefix_kind,
-            )
+            ctx.sema.scope(path.syntax()).module().and_then(|m| {
+                m.find_use_path_prefixed(ctx.sema.db, module, ctx.config.insert_use.prefix_kind)
+            })
         })
         .flatten();
 
diff --git a/crates/ide_assists/src/handlers/unwrap_result_return_type.rs b/crates/ide_assists/src/handlers/unwrap_result_return_type.rs
index ff79c5b82a..b890462389 100644
--- a/crates/ide_assists/src/handlers/unwrap_result_return_type.rs
+++ b/crates/ide_assists/src/handlers/unwrap_result_return_type.rs
@@ -38,9 +38,9 @@ pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext)
     };
 
     let type_ref = &ret_type.ty()?;
-    let ty = ctx.sema.resolve_type(type_ref)?.as_adt();
+    let ty = ctx.sema.resolve_type(type_ref).and_then(|ty| ty.as_adt());
     let result_enum =
-        FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?;
+        FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax()).krate()).core_result_Result()?;
 
     if !matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == result_enum) {
         return None;
diff --git a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
index 251b41c84a..972d4765bb 100644
--- a/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
+++ b/crates/ide_assists/src/handlers/wrap_return_type_in_result.rs
@@ -39,9 +39,9 @@ pub(crate) fn wrap_return_type_in_result(acc: &mut Assists, ctx: &AssistContext)
     };
 
     let type_ref = &ret_type.ty()?;
-    let ty = ctx.sema.resolve_type(type_ref)?.as_adt();
+    let ty = ctx.sema.resolve_type(type_ref).and_then(|ty| ty.as_adt());
     let result_enum =
-        FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax())?.krate()).core_result_Result()?;
+        FamousDefs(&ctx.sema, ctx.sema.scope(type_ref.syntax()).krate()).core_result_Result()?;
 
     if matches!(ty, Some(hir::Adt::Enum(ret_type)) if ret_type == result_enum) {
         cov_mark::hit!(wrap_return_type_in_result_simple_return_type_already_result);
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 0add950718..42317ea4da 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -600,7 +600,8 @@ fn handle_as_ref_str(
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs,
 ) -> Option<ReferenceConversionType> {
-    let str_type = hir::BuiltinType::str().ty(db);
+    let module = famous_defs.1?.root_module(db);
+    let str_type = hir::BuiltinType::str().ty(db, module);
 
     ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type])
         .then(|| ReferenceConversionType::AsRefStr)
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index ab442fa64b..867e6bcf48 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -352,6 +352,14 @@ fn enum_variants_with_paths(
 ) {
     let variants = enum_.variants(ctx.db);
 
+    let module = if let Some(module) = ctx.module {
+        // Compute path from the completion site if available.
+        module
+    } else {
+        // Otherwise fall back to the enum's definition site.
+        enum_.module(ctx.db)
+    };
+
     if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
         if impl_.self_ty(ctx.db).as_adt() == Some(hir::Adt::Enum(enum_)) {
             for &variant in &variants {
@@ -365,7 +373,7 @@ fn enum_variants_with_paths(
     }
 
     for variant in variants {
-        if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
+        if let Some(path) = module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
             // Variants with trivial paths are already added by the existing completion logic,
             // so we should avoid adding these twice
             if path.segments().len() > 1 {
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index c79a9816f4..6b51e19bbb 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -91,7 +91,7 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
                 _ => return,
             };
 
-            for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
+            for (name, def) in module.scope(ctx.db, ctx.module) {
                 if let Some(def) = module_or_attr(ctx.db, def) {
                     acc.add_resolution(ctx, name, def);
                 }
diff --git a/crates/ide_completion/src/completions/attribute/cfg.rs b/crates/ide_completion/src/completions/attribute/cfg.rs
index b7e69d7b43..58d0a39949 100644
--- a/crates/ide_completion/src/completions/attribute/cfg.rs
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -27,17 +27,26 @@ pub(crate) fn complete_cfg(acc: &mut Completions, ctx: &CompletionContext) {
         Some("target_os") => KNOWN_OS.iter().copied().for_each(add_completion),
         Some("target_vendor") => KNOWN_VENDOR.iter().copied().for_each(add_completion),
         Some("target_endian") => ["little", "big"].into_iter().for_each(add_completion),
-        Some(name) => ctx.krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
-            let insert_text = format!(r#""{}""#, s);
-            let mut item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
-            item.insert_text(insert_text);
+        Some(name) => {
+            if let Some(krate) = ctx.krate {
+                krate.potential_cfg(ctx.db).get_cfg_values(name).cloned().for_each(|s| {
+                    let insert_text = format!(r#""{}""#, s);
+                    let mut item =
+                        CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
+                    item.insert_text(insert_text);
 
-            acc.add(item.build());
-        }),
-        None => ctx.krate.potential_cfg(ctx.db).get_cfg_keys().cloned().for_each(|s| {
-            let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
-            acc.add(item.build());
-        }),
+                    acc.add(item.build());
+                })
+            };
+        }
+        None => {
+            if let Some(krate) = ctx.krate {
+                krate.potential_cfg(ctx.db).get_cfg_keys().cloned().for_each(|s| {
+                    let item = CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), s);
+                    acc.add(item.build());
+                })
+            }
+        }
     };
 }
 
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 4611811539..3c0e43ceac 100644
--- a/crates/ide_completion/src/completions/attribute/derive.rs
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -34,7 +34,7 @@ pub(crate) fn complete_derive(acc: &mut Completions, ctx: &CompletionContext) {
                 _ => return,
             };
 
-            for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
+            for (name, def) in module.scope(ctx.db, ctx.module) {
                 let add_def = match def {
                     ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
                         !ctx.existing_derives.contains(&mac) && mac.is_derive(ctx.db)
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index c237a65bfe..981e25b55c 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -87,7 +87,7 @@ fn complete_methods(
         ctx.db,
         &ctx.scope,
         &traits_in_scope,
-        Some(ctx.module),
+        ctx.module,
         None,
         |func| {
             if func.self_param(ctx.db).is_some() && seen_methods.insert(func.name(ctx.db)) {
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 2154a1b3cb..ee751f9f77 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -10,6 +10,7 @@ use syntax::{AstNode, SyntaxNode, T};
 use crate::{
     context::{CompletionContext, PathKind},
     render::{render_resolution_with_import, RenderContext},
+    ImportEdit,
 };
 
 use super::Completions;
@@ -135,10 +136,10 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
 
     let user_input_lowercased = potential_import_name.to_lowercase();
     let import_assets = import_assets(ctx, potential_import_name)?;
-    let position = position_for_import(ctx, Some(import_assets.import_candidate()))?;
-    if ImportScope::find_insert_use_container(&position, &ctx.sema).is_none() {
-        return None;
-    }
+    let import_scope = ImportScope::find_insert_use_container(
+        &position_for_import(ctx, Some(import_assets.import_candidate()))?,
+        &ctx.sema,
+    )?;
 
     let path_kind = match ctx.path_kind() {
         Some(kind) => Some(kind),
@@ -198,7 +199,12 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
                     &user_input_lowercased,
                 )
             })
-            .filter_map(|import| render_resolution_with_import(RenderContext::new(ctx), import)),
+            .filter_map(|import| {
+                render_resolution_with_import(
+                    RenderContext::new(ctx),
+                    ImportEdit { import, scope: import_scope.clone() },
+                )
+            }),
     );
     Some(())
 }
@@ -219,7 +225,7 @@ pub(crate) fn position_for_import(
 }
 
 fn import_assets(ctx: &CompletionContext, fuzzy_name: String) -> Option<ImportAssets> {
-    let current_module = ctx.module;
+    let current_module = ctx.module?;
     if let Some(dot_receiver) = ctx.dot_receiver() {
         ImportAssets::for_fuzzy_method_call(
             current_module,
diff --git a/crates/ide_completion/src/completions/fn_param.rs b/crates/ide_completion/src/completions/fn_param.rs
index 7e9c1f49de..c5bc91d73d 100644
--- a/crates/ide_completion/src/completions/fn_param.rs
+++ b/crates/ide_completion/src/completions/fn_param.rs
@@ -120,18 +120,18 @@ fn params_from_stmt_list_scope(
         Some(it) => it,
         None => return,
     };
-    if let Some(scope) =
-        ctx.sema.scope_at_offset(stmt_list.syntax(), syntax_node.text_range().end())
-    {
-        let module = scope.module().into();
-        scope.process_all_names(&mut |name, def| {
-            if let hir::ScopeDef::Local(local) = def {
-                if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module) {
-                    cb(name, ty);
-                }
+    let scope = ctx.sema.scope_at_offset(stmt_list.syntax(), syntax_node.text_range().end());
+    let module = match scope.module() {
+        Some(it) => it,
+        None => return,
+    };
+    scope.process_all_names(&mut |name, def| {
+        if let hir::ScopeDef::Local(local) = def {
+            if let Ok(ty) = local.ty(ctx.db).display_source_code(ctx.db, module.into()) {
+                cb(name, ty);
             }
-        });
-    }
+        }
+    });
 }
 
 fn remove_duplicated(
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index fb42e4e72f..7699c530c6 100644
--- a/crates/ide_completion/src/completions/mod_.rs
+++ b/crates/ide_completion/src/completions/mod_.rs
@@ -22,7 +22,7 @@ pub(crate) fn complete_mod(acc: &mut Completions, ctx: &CompletionContext) -> Op
 
     let _p = profile::span("completion::complete_mod");
 
-    let current_module = ctx.module;
+    let current_module = ctx.module?;
 
     let module_definition_file =
         current_module.definition_source(ctx.db).file_id.original_file(ctx.db);
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 00f9bdfb51..0d3a49c668 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -122,7 +122,7 @@ fn pattern_path_completion(
 
             match resolution {
                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
-                    let module_scope = module.scope(ctx.db, Some(ctx.module));
+                    let module_scope = module.scope(ctx.db, ctx.module);
                     for (name, def) in module_scope {
                         let add_resolution = match def {
                             ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
@@ -159,7 +159,13 @@ fn pattern_path_completion(
                         hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
                             u.ty(ctx.db)
                         }
-                        hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => ty.ty(ctx.db),
+                        hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => {
+                            let module = match ctx.module {
+                                Some(m) => m,
+                                None => return,
+                            };
+                            ty.ty(ctx.db, module)
+                        }
                         _ => return,
                     };
 
@@ -169,7 +175,7 @@ fn pattern_path_completion(
                         ctx.db,
                         &ctx.scope,
                         &traits_in_scope,
-                        Some(ctx.module),
+                        ctx.module,
                         None,
                         |item| {
                             match item {
diff --git a/crates/ide_completion/src/completions/postfix.rs b/crates/ide_completion/src/completions/postfix.rs
index 175d6f1623..ead957a3f1 100644
--- a/crates/ide_completion/src/completions/postfix.rs
+++ b/crates/ide_completion/src/completions/postfix.rs
@@ -12,11 +12,9 @@ use syntax::{
 use text_edit::TextEdit;
 
 use crate::{
-    completions::postfix::format_like::add_format_like_completions,
-    context::CompletionContext,
-    item::{Builder, CompletionRelevancePostfixMatch},
-    patterns::ImmediateLocation,
-    CompletionItem, CompletionItemKind, CompletionRelevance, Completions, SnippetScope,
+    completions::postfix::format_like::add_format_like_completions, context::CompletionContext,
+    item::Builder, patterns::ImmediateLocation, CompletionItem, CompletionItemKind,
+    CompletionRelevance, Completions, SnippetScope,
 };
 
 pub(crate) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
@@ -242,13 +240,12 @@ fn build_postfix_snippet_builder<'ctx>(
             let mut item =
                 CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
             item.detail(detail).snippet_edit(cap, edit);
-            let postfix_match = if ctx.original_token.text() == label {
-                Some(CompletionRelevancePostfixMatch::Exact)
-            } else {
-                Some(CompletionRelevancePostfixMatch::NonExact)
-            };
-            let relevance = CompletionRelevance { postfix_match, ..Default::default() };
-            item.set_relevance(relevance);
+            if ctx.original_token.text() == label {
+                let relevance =
+                    CompletionRelevance { exact_postfix_snippet_match: true, ..Default::default() };
+                item.set_relevance(relevance);
+            }
+
             item
         }
     }
@@ -261,12 +258,10 @@ fn add_custom_postfix_completions(
     postfix_snippet: impl Fn(&str, &str, &str) -> Builder,
     receiver_text: &str,
 ) -> Option<()> {
-    if ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema).is_none() {
-        return None;
-    }
+    let import_scope = ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema)?;
     ctx.config.postfix_snippets().filter(|(_, snip)| snip.scope == SnippetScope::Expr).for_each(
         |(trigger, snippet)| {
-            let imports = match snippet.imports(ctx) {
+            let imports = match snippet.imports(ctx, &import_scope) {
                 Some(imports) => imports,
                 None => return,
             };
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 534d27d983..c1f23ceeca 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -1,6 +1,7 @@
 //! Completion of paths, i.e. `some::prefix::$0`.
 
 use hir::{ScopeDef, Trait};
+use ide_db::famous_defs::FamousDefs;
 use rustc_hash::FxHashSet;
 use syntax::ast;
 
@@ -25,7 +26,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
     };
     let traits_in_scope = |ctx: &CompletionContext| {
         let mut traits_in_scope = ctx.scope.visible_traits();
-        if let Some(drop) = ctx.famous_defs().core_ops_Drop() {
+        if let Some(drop) = FamousDefs(&ctx.sema, ctx.krate).core_ops_Drop() {
             traits_in_scope.remove(&drop.into());
         }
         traits_in_scope
@@ -57,7 +58,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
     match ctx.completion_location {
         Some(ImmediateLocation::ItemList | ImmediateLocation::Trait | ImmediateLocation::Impl) => {
             if let hir::PathResolution::Def(hir::ModuleDef::Module(module)) = resolution {
-                for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
+                for (name, def) in module.scope(ctx.db, ctx.module) {
                     if let Some(def) = module_or_fn_macro(ctx.db, def) {
                         acc.add_resolution(ctx, name, def);
                     }
@@ -89,7 +90,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
 
     match resolution {
         hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
-            let module_scope = module.scope(ctx.db, Some(ctx.module));
+            let module_scope = module.scope(ctx.db, ctx.module);
             for (name, def) in module_scope {
                 let add_resolution = match def {
                     // Don't suggest attribute macros and derives.
@@ -132,8 +133,12 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
                     ty
                 }
                 hir::ModuleDef::BuiltinType(builtin) => {
+                    let module = match ctx.module {
+                        Some(it) => it,
+                        None => return,
+                    };
                     cov_mark::hit!(completes_primitive_assoc_const);
-                    builtin.ty(ctx.db)
+                    builtin.ty(ctx.db, module)
                 }
                 _ => unreachable!(),
             };
@@ -141,26 +146,29 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
             // XXX: For parity with Rust bug #22519, this does not complete Ty::AssocType.
             // (where AssocType is defined on a trait, not an inherent impl)
 
-            let traits_in_scope = traits_in_scope(ctx);
-            ty.iterate_path_candidates(
-                ctx.db,
-                &ctx.scope,
-                &traits_in_scope,
-                Some(ctx.module),
-                None,
-                |item| {
-                    add_assoc_item(acc, ctx, item);
+            let krate = ctx.krate;
+            if let Some(krate) = krate {
+                let traits_in_scope = traits_in_scope(ctx);
+                ty.iterate_path_candidates(
+                    ctx.db,
+                    &ctx.scope,
+                    &traits_in_scope,
+                    ctx.module,
+                    None,
+                    |item| {
+                        add_assoc_item(acc, ctx, item);
+                        None::<()>
+                    },
+                );
+
+                // Iterate assoc types separately
+                ty.iterate_assoc_items(ctx.db, krate, |item| {
+                    if let hir::AssocItem::TypeAlias(ty) = item {
+                        acc.add_type_alias(ctx, ty)
+                    }
                     None::<()>
-                },
-            );
-
-            // Iterate assoc types separately
-            ty.iterate_assoc_items(ctx.db, ctx.krate, |item| {
-                if let hir::AssocItem::TypeAlias(ty) = item {
-                    acc.add_type_alias(ctx, ty)
-                }
-                None::<()>
-            });
+                });
+            }
         }
         hir::PathResolution::Def(hir::ModuleDef::Trait(t)) => {
             // Handles `Trait::assoc` as well as `<Ty as Trait>::assoc`.
@@ -184,7 +192,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
                 ctx.db,
                 &ctx.scope,
                 &traits_in_scope,
-                Some(ctx.module),
+                ctx.module,
                 None,
                 |item| {
                     // We might iterate candidates of a trait multiple times here, so deduplicate
diff --git a/crates/ide_completion/src/completions/record.rs b/crates/ide_completion/src/completions/record.rs
index 6057c0e004..5509ec922f 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -4,7 +4,7 @@ use syntax::{ast::Expr, T};
 
 use crate::{
     patterns::ImmediateLocation, CompletionContext, CompletionItem, CompletionItemKind,
-    CompletionRelevance, CompletionRelevancePostfixMatch, Completions,
+    CompletionRelevance, Completions,
 };
 
 pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -45,7 +45,7 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
                     let completion_text =
                         completion_text.strip_prefix(ctx.token.text()).unwrap_or(completion_text);
                     item.insert_text(completion_text).set_relevance(CompletionRelevance {
-                        postfix_match: Some(CompletionRelevancePostfixMatch::Exact),
+                        exact_postfix_snippet_match: true,
                         ..Default::default()
                     });
                     item.add_to(acc);
@@ -83,18 +83,17 @@ pub(crate) fn complete_record_literal(
 
     match ctx.expected_type.as_ref()?.as_adt()? {
         hir::Adt::Struct(strukt) if ctx.path_qual().is_none() => {
-            let path = ctx
-                .module
+            let module = if let Some(module) = ctx.module { module } else { strukt.module(ctx.db) };
+            let path = module
                 .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
                 .filter(|it| it.len() > 1);
 
             acc.add_struct_literal(ctx, strukt, path, None);
         }
         hir::Adt::Union(un) if ctx.path_qual().is_none() => {
-            let path = ctx
-                .module
-                .find_use_path(ctx.db, hir::ModuleDef::from(un))
-                .filter(|it| it.len() > 1);
+            let module = if let Some(module) = ctx.module { module } else { un.module(ctx.db) };
+            let path =
+                module.find_use_path(ctx.db, hir::ModuleDef::from(un)).filter(|it| it.len() > 1);
 
             acc.add_union_literal(ctx, un, path, None);
         }
diff --git a/crates/ide_completion/src/completions/snippet.rs b/crates/ide_completion/src/completions/snippet.rs
index 0a3d594e41..673ee51f78 100644
--- a/crates/ide_completion/src/completions/snippet.rs
+++ b/crates/ide_completion/src/completions/snippet.rs
@@ -104,12 +104,10 @@ fn add_custom_completions(
     cap: SnippetCap,
     scope: SnippetScope,
 ) -> Option<()> {
-    if ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema).is_none() {
-        return None;
-    }
+    let import_scope = ImportScope::find_insert_use_container(&ctx.token.parent()?, &ctx.sema)?;
     ctx.config.prefix_snippets().filter(|(_, snip)| snip.scope == scope).for_each(
         |(trigger, snip)| {
-            let imports = match snip.imports(ctx) {
+            let imports = match snip.imports(ctx, &import_scope) {
                 Some(imports) => imports,
                 None => return,
             };
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index 9c557aa524..0d59f77a55 100644
--- a/crates/ide_completion/src/completions/trait_impl.rs
+++ b/crates/ide_completion/src/completions/trait_impl.rs
@@ -183,7 +183,7 @@ fn get_transformed_assoc_item(
     let assoc_item = assoc_item.clone_for_update();
     let trait_ = impl_def.trait_(ctx.db)?;
     let source_scope = &ctx.sema.scope_for_def(trait_);
-    let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?;
+    let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value);
     let transform = PathTransform::trait_impl(
         target_scope,
         source_scope,
diff --git a/crates/ide_completion/src/completions/use_.rs b/crates/ide_completion/src/completions/use_.rs
index d7c279f9d9..16b356963d 100644
--- a/crates/ide_completion/src/completions/use_.rs
+++ b/crates/ide_completion/src/completions/use_.rs
@@ -41,7 +41,7 @@ pub(crate) fn complete_use_tree(acc: &mut Completions, ctx: &CompletionContext)
 
             match resolution {
                 hir::PathResolution::Def(hir::ModuleDef::Module(module)) => {
-                    let module_scope = module.scope(ctx.db, Some(ctx.module));
+                    let module_scope = module.scope(ctx.db, ctx.module);
                     let unknown_is_current = |name: &hir::Name| {
                         matches!(
                             ctx.name_syntax.as_ref(),
diff --git a/crates/ide_completion/src/completions/vis.rs b/crates/ide_completion/src/completions/vis.rs
index ca6f6dff1e..c610dcd705 100644
--- a/crates/ide_completion/src/completions/vis.rs
+++ b/crates/ide_completion/src/completions/vis.rs
@@ -22,16 +22,17 @@ pub(crate) fn complete_vis(acc: &mut Completions, ctx: &CompletionContext) {
         Some(PathQualifierCtx { resolution, is_super_chain, .. }) => {
             // Try completing next child module of the path that is still a parent of the current module
             if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) = resolution {
-                let next_towards_current = ctx
-                    .module
-                    .path_to_root(ctx.db)
-                    .into_iter()
-                    .take_while(|it| it != module)
-                    .last();
-                if let Some(next) = next_towards_current {
-                    if let Some(name) = next.name(ctx.db) {
-                        cov_mark::hit!(visibility_qualified);
-                        acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into()));
+                if let Some(current_module) = ctx.module {
+                    let next_towards_current = current_module
+                        .path_to_root(ctx.db)
+                        .into_iter()
+                        .take_while(|it| it != module)
+                        .last();
+                    if let Some(next) = next_towards_current {
+                        if let Some(name) = next.name(ctx.db) {
+                            cov_mark::hit!(visibility_qualified);
+                            acc.add_resolution(ctx, name, ScopeDef::ModuleDef(next.into()));
+                        }
                     }
                 }
             }
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 12747b3ce4..ed59eb6bd3 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -121,9 +121,9 @@ pub(crate) struct CompletionContext<'a> {
     /// The token before the cursor, in the macro-expanded file.
     pub(super) token: SyntaxToken,
     /// The crate of the current file.
-    pub(super) krate: hir::Crate,
+    pub(super) krate: Option<hir::Crate>,
     /// The module of the `scope`.
-    pub(super) module: hir::Module,
+    pub(super) module: Option<hir::Module>,
     pub(super) expected_name: Option<NameOrNameRef>,
     pub(super) expected_type: Option<Type>,
 
@@ -353,7 +353,11 @@ impl<'a> CompletionContext<'a> {
         attrs: &hir::Attrs,
         defining_crate: hir::Crate,
     ) -> Visible {
-        if !vis.is_visible_from(self.db, self.module.into()) {
+        let module = match self.module {
+            Some(it) => it,
+            None => return Visible::No,
+        };
+        if !vis.is_visible_from(self.db, module.into()) {
             if !self.config.enable_private_editable {
                 return Visible::No;
             }
@@ -372,8 +376,11 @@ impl<'a> CompletionContext<'a> {
     }
 
     fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
-        // `doc(hidden)` items are only completed within the defining crate.
-        self.krate != defining_crate && attrs.has_doc_hidden()
+        match self.krate {
+            // `doc(hidden)` items are only completed within the defining crate.
+            Some(krate) => krate != defining_crate && attrs.has_doc_hidden(),
+            None => true,
+        }
     }
 }
 
@@ -402,7 +409,7 @@ impl<'a> CompletionContext<'a> {
 
         let original_token = original_file.syntax().token_at_offset(offset).left_biased()?;
         let token = sema.descend_into_macros_single(original_token.clone());
-        let scope = sema.scope_at_offset(&token.parent()?, offset)?;
+        let scope = sema.scope_at_offset(&token.parent()?, offset);
         let krate = scope.krate();
         let module = scope.module();
         let mut locals = FxHashMap::default();
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index 3c2be32f4e..4b9f7d17c3 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -3,10 +3,17 @@
 use std::fmt;
 
 use hir::{Documentation, Mutability};
-use ide_db::{imports::import_assets::LocatedImport, SnippetCap, SymbolKind};
+use ide_db::{
+    helpers::mod_path_to_ast,
+    imports::{
+        import_assets::LocatedImport,
+        insert_use::{self, ImportScope, InsertUseConfig},
+    },
+    SnippetCap, SymbolKind,
+};
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
-use syntax::{SmolStr, TextRange};
+use syntax::{algo, SmolStr, TextRange};
 use text_edit::TextEdit;
 
 /// `CompletionItem` describes a single completion variant in the editor pop-up.
@@ -66,7 +73,7 @@ pub struct CompletionItem {
     ref_match: Option<Mutability>,
 
     /// The import data to add to completion's edits.
-    import_to_add: SmallVec<[LocatedImport; 1]>,
+    import_to_add: SmallVec<[ImportEdit; 1]>,
 }
 
 // We use custom debug for CompletionItem to make snapshot tests more readable.
@@ -136,8 +143,15 @@ pub struct CompletionRelevance {
     pub is_op_method: bool,
     /// Set for item completions that are private but in the workspace.
     pub is_private_editable: bool,
-    /// Set for postfix snippet item completions
-    pub postfix_match: Option<CompletionRelevancePostfixMatch>,
+    /// This is set in cases like these:
+    ///
+    /// ```
+    /// (a > b).not$0
+    /// ```
+    ///
+    /// Basically, we want to guarantee that postfix snippets always takes
+    /// precedence over everything else.
+    pub exact_postfix_snippet_match: bool,
 }
 
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
@@ -164,22 +178,8 @@ pub enum CompletionRelevanceTypeMatch {
     Exact,
 }
 
-#[derive(Debug, Clone, Copy, Eq, PartialEq)]
-pub enum CompletionRelevancePostfixMatch {
-    /// Set in cases when item is postfix, but not exact
-    NonExact,
-    /// This is set in cases like these:
-    ///
-    /// ```
-    /// (a > b).not$0
-    /// ```
-    ///
-    /// Basically, we want to guarantee that postfix snippets always takes
-    /// precedence over everything else.
-    Exact,
-}
-
 impl CompletionRelevance {
+    const BASE_LINE: u32 = 2;
     /// Provides a relevance score. Higher values are more relevant.
     ///
     /// The absolute value of the relevance score is not meaningful, for
@@ -189,43 +189,32 @@ impl CompletionRelevance {
     ///
     /// See is_relevant if you need to make some judgement about score
     /// in an absolute sense.
-    pub fn score(self) -> u32 {
-        let mut score = 0;
-        let CompletionRelevance {
-            exact_name_match,
-            type_match,
-            is_local,
-            is_op_method,
-            is_private_editable,
-            postfix_match,
-        } = self;
-
-        // lower rank private things
-        if !is_private_editable {
-            score += 1;
+    pub fn score(&self) -> u32 {
+        let mut score = Self::BASE_LINE;
+
+        // score decreases
+        if self.is_op_method {
+            score -= 1;
         }
-        // lower rank trait op methods
-        if !is_op_method {
-            score += 10;
+        if self.is_private_editable {
+            score -= 1;
         }
-        if exact_name_match {
-            score += 10;
+
+        // score increases
+        if self.exact_name_match {
+            score += 1;
         }
-        score += match postfix_match {
-            Some(CompletionRelevancePostfixMatch::Exact) => 100,
-            Some(CompletionRelevancePostfixMatch::NonExact) => 0,
-            None => 3,
-        };
-        score += match type_match {
-            Some(CompletionRelevanceTypeMatch::Exact) => 8,
+        score += match self.type_match {
+            Some(CompletionRelevanceTypeMatch::Exact) => 4,
             Some(CompletionRelevanceTypeMatch::CouldUnify) => 3,
             None => 0,
         };
-        // slightly prefer locals
-        if is_local {
+        if self.is_local {
             score += 1;
         }
-
+        if self.exact_postfix_snippet_match {
+            score += 100;
+        }
         score
     }
 
@@ -233,7 +222,7 @@ impl CompletionRelevance {
     /// some threshold such that we think it is especially likely
     /// to be relevant.
     pub fn is_relevant(&self) -> bool {
-        self.score() > 0
+        self.score() > Self::BASE_LINE
     }
 }
 
@@ -373,17 +362,40 @@ impl CompletionItem {
         self.ref_match.map(|mutability| (mutability, relevance))
     }
 
-    pub fn imports_to_add(&self) -> &[LocatedImport] {
+    pub fn imports_to_add(&self) -> &[ImportEdit] {
         &self.import_to_add
     }
 }
 
+/// An extra import to add after the completion is applied.
+#[derive(Debug, Clone)]
+pub struct ImportEdit {
+    pub import: LocatedImport,
+    pub scope: ImportScope,
+}
+
+impl ImportEdit {
+    /// Attempts to insert the import to the given scope, producing a text edit.
+    /// May return no edit in edge cases, such as scope already containing the import.
+    pub fn to_text_edit(&self, cfg: InsertUseConfig) -> Option<TextEdit> {
+        let _p = profile::span("ImportEdit::to_text_edit");
+
+        let new_ast = self.scope.clone_for_update();
+        insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg);
+        let mut import_insert = TextEdit::builder();
+        algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node())
+            .into_text_edit(&mut import_insert);
+
+        Some(import_insert.finish())
+    }
+}
+
 /// A helper to make `CompletionItem`s.
 #[must_use]
 #[derive(Clone)]
 pub(crate) struct Builder {
     source_range: TextRange,
-    imports_to_add: SmallVec<[LocatedImport; 1]>,
+    imports_to_add: SmallVec<[ImportEdit; 1]>,
     trait_name: Option<SmolStr>,
     label: SmolStr,
     insert_text: Option<String>,
@@ -409,7 +421,7 @@ impl Builder {
 
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
-            if let Some(original_path) = import_edit.original_path.as_ref() {
+            if let Some(original_path) = import_edit.import.original_path.as_ref() {
                 lookup = lookup.or_else(|| Some(label.clone()));
                 label = SmolStr::from(format!("{} (use {})", label, original_path));
             }
@@ -503,7 +515,7 @@ impl Builder {
         self.trigger_call_info = Some(true);
         self
     }
-    pub(crate) fn add_import(&mut self, import_to_add: LocatedImport) -> &mut Builder {
+    pub(crate) fn add_import(&mut self, import_to_add: ImportEdit) -> &mut Builder {
         self.imports_to_add.push(import_to_add);
         self
     }
@@ -518,9 +530,7 @@ mod tests {
     use itertools::Itertools;
     use test_utils::assert_eq_text;
 
-    use super::{
-        CompletionRelevance, CompletionRelevancePostfixMatch, CompletionRelevanceTypeMatch,
-    };
+    use super::{CompletionRelevance, CompletionRelevanceTypeMatch};
 
     /// Check that these are CompletionRelevance are sorted in ascending order
     /// by their relevance score.
@@ -560,34 +570,51 @@ mod tests {
 
     #[test]
     fn relevance_score() {
-        use CompletionRelevance as Cr;
-        let default = Cr::default();
         // This test asserts that the relevance score for these items is ascending, and
         // that any items in the same vec have the same score.
         let expected_relevance_order = vec![
-            vec![],
-            vec![Cr { is_op_method: true, is_private_editable: true, ..default }],
-            vec![Cr { is_op_method: true, ..default }],
-            vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::NonExact), ..default }],
-            vec![Cr { is_private_editable: true, ..default }],
-            vec![default],
-            vec![Cr { is_local: true, ..default }],
-            vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::CouldUnify), ..default }],
-            vec![Cr { type_match: Some(CompletionRelevanceTypeMatch::Exact), ..default }],
-            vec![Cr { exact_name_match: true, ..default }],
-            vec![Cr { exact_name_match: true, is_local: true, ..default }],
-            vec![Cr {
+            vec![CompletionRelevance {
+                is_op_method: true,
+                is_private_editable: true,
+                ..CompletionRelevance::default()
+            }],
+            vec![
+                CompletionRelevance { is_private_editable: true, ..CompletionRelevance::default() },
+                CompletionRelevance { is_op_method: true, ..CompletionRelevance::default() },
+            ],
+            vec![CompletionRelevance::default()],
+            vec![
+                CompletionRelevance { exact_name_match: true, ..CompletionRelevance::default() },
+                CompletionRelevance { is_local: true, ..CompletionRelevance::default() },
+            ],
+            vec![CompletionRelevance {
+                exact_name_match: true,
+                is_local: true,
+                ..CompletionRelevance::default()
+            }],
+            vec![CompletionRelevance {
+                type_match: Some(CompletionRelevanceTypeMatch::CouldUnify),
+                ..CompletionRelevance::default()
+            }],
+            vec![CompletionRelevance {
+                type_match: Some(CompletionRelevanceTypeMatch::Exact),
+                ..CompletionRelevance::default()
+            }],
+            vec![CompletionRelevance {
                 exact_name_match: true,
                 type_match: Some(CompletionRelevanceTypeMatch::Exact),
-                ..default
+                ..CompletionRelevance::default()
             }],
-            vec![Cr {
+            vec![CompletionRelevance {
                 exact_name_match: true,
                 type_match: Some(CompletionRelevanceTypeMatch::Exact),
                 is_local: true,
-                ..default
+                ..CompletionRelevance::default()
+            }],
+            vec![CompletionRelevance {
+                exact_postfix_snippet_match: true,
+                ..CompletionRelevance::default()
             }],
-            vec![Cr { postfix_match: Some(CompletionRelevancePostfixMatch::Exact), ..default }],
         ];
 
         check_relevance_score_ordered(expected_relevance_order);
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 8eb7615f8f..422bda6460 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -28,9 +28,7 @@ use crate::{completions::Completions, context::CompletionContext};
 
 pub use crate::{
     config::CompletionConfig,
-    item::{
-        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
-    },
+    item::{CompletionItem, CompletionItemKind, CompletionRelevance, ImportEdit},
     snippet::{Snippet, SnippetScope},
 };
 
@@ -187,11 +185,12 @@ pub fn resolve_completion_edits(
     let position_for_import = &position_for_import(&ctx, None)?;
     let scope = ImportScope::find_insert_use_container(position_for_import, &ctx.sema)?;
 
-    let current_module = ctx.sema.scope(position_for_import)?.module();
+    let current_module = ctx.sema.scope(position_for_import).module()?;
     let current_crate = current_module.krate();
     let new_ast = scope.clone_for_update();
     let mut import_insert = TextEdit::builder();
 
+    // FIXME: lift out and make some tests here, this is ImportEdit::to_text_edit but changed to work with multiple edits
     imports.into_iter().for_each(|(full_import_path, imported_name)| {
         let items_with_name = items_locator::items_with_name(
             &ctx.sema,
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index e5ec273212..604f217447 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -11,14 +11,12 @@ pub(crate) mod union_literal;
 pub(crate) mod literal;
 
 use hir::{AsAssocItem, HasAttrs, HirDisplay, ScopeDef};
-use ide_db::{
-    helpers::item_name, imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind,
-};
+use ide_db::{helpers::item_name, RootDatabase, SnippetCap, SymbolKind};
 use syntax::{SmolStr, SyntaxKind, TextRange};
 
 use crate::{
     context::{PathCompletionCtx, PathKind},
-    item::CompletionRelevanceTypeMatch,
+    item::{CompletionRelevanceTypeMatch, ImportEdit},
     render::{function::render_fn, literal::render_variant_lit, macro_::render_macro},
     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
 };
@@ -27,7 +25,7 @@ use crate::{
 pub(crate) struct RenderContext<'a> {
     completion: &'a CompletionContext<'a>,
     is_private_editable: bool,
-    import_to_add: Option<LocatedImport>,
+    import_to_add: Option<ImportEdit>,
 }
 
 impl<'a> RenderContext<'a> {
@@ -40,7 +38,7 @@ impl<'a> RenderContext<'a> {
         self
     }
 
-    pub(crate) fn import_to_add(mut self, import_to_add: Option<LocatedImport>) -> Self {
+    pub(crate) fn import_to_add(mut self, import_to_add: Option<ImportEdit>) -> Self {
         self.import_to_add = import_to_add;
         self
     }
@@ -158,14 +156,14 @@ pub(crate) fn render_resolution_simple(
 
 pub(crate) fn render_resolution_with_import(
     ctx: RenderContext<'_>,
-    import_edit: LocatedImport,
+    import_edit: ImportEdit,
 ) -> Option<CompletionItem> {
-    let resolution = ScopeDef::from(import_edit.original_item);
+    let resolution = ScopeDef::from(import_edit.import.original_item);
     let local_name = match resolution {
         ScopeDef::ModuleDef(hir::ModuleDef::Function(f)) => f.name(ctx.completion.db),
         ScopeDef::ModuleDef(hir::ModuleDef::Const(c)) => c.name(ctx.completion.db)?,
         ScopeDef::ModuleDef(hir::ModuleDef::TypeAlias(t)) => t.name(ctx.completion.db),
-        _ => item_name(ctx.db(), import_edit.original_item)?,
+        _ => item_name(ctx.db(), import_edit.import.original_item)?,
     };
     Some(render_resolution_(ctx, local_name, Some(import_edit), resolution))
 }
@@ -173,7 +171,7 @@ pub(crate) fn render_resolution_with_import(
 fn render_resolution_(
     ctx: RenderContext<'_>,
     local_name: hir::Name,
-    import_to_add: Option<LocatedImport>,
+    import_to_add: Option<ImportEdit>,
     resolution: ScopeDef,
 ) -> CompletionItem {
     let _p = profile::span("render_resolution");
@@ -202,7 +200,7 @@ fn render_resolution_(
 fn render_resolution_simple_(
     ctx: RenderContext<'_>,
     local_name: hir::Name,
-    import_to_add: Option<LocatedImport>,
+    import_to_add: Option<ImportEdit>,
     resolution: ScopeDef,
 ) -> CompletionItem {
     let _p = profile::span("render_resolution");
@@ -367,7 +365,7 @@ mod tests {
     use crate::{
         item::CompletionRelevanceTypeMatch,
         tests::{check_edit, do_completion, get_all_items, TEST_CONFIG},
-        CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch,
+        CompletionItem, CompletionItemKind, CompletionRelevance,
     };
 
     #[track_caller]
@@ -434,10 +432,7 @@ mod tests {
                 ),
                 (relevance.exact_name_match, "name"),
                 (relevance.is_local, "local"),
-                (
-                    relevance.postfix_match == Some(CompletionRelevancePostfixMatch::Exact),
-                    "snippet",
-                ),
+                (relevance.exact_postfix_snippet_match, "snippet"),
                 (relevance.is_op_method, "op_method"),
             ]
             .into_iter()
@@ -619,7 +614,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_local: false,
                             is_op_method: false,
                             is_private_editable: false,
-                            postfix_match: None,
+                            exact_postfix_snippet_match: false,
                         },
                     },
                     CompletionItem {
@@ -640,7 +635,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_local: false,
                             is_op_method: false,
                             is_private_editable: false,
-                            postfix_match: None,
+                            exact_postfix_snippet_match: false,
                         },
                     },
                 ]
@@ -727,7 +722,7 @@ fn foo() { A { the$0 } }
                             is_local: false,
                             is_op_method: false,
                             is_private_editable: false,
-                            postfix_match: None,
+                            exact_postfix_snippet_match: false,
                         },
                     },
                 ]
diff --git a/crates/ide_completion/src/render/variant.rs b/crates/ide_completion/src/render/variant.rs
index 39a37dc9f8..a37b4237c4 100644
--- a/crates/ide_completion/src/render/variant.rs
+++ b/crates/ide_completion/src/render/variant.rs
@@ -72,7 +72,7 @@ pub(crate) fn visible_fields(
     fields: &[hir::Field],
     item: impl HasAttrs,
 ) -> Option<(Vec<hir::Field>, bool)> {
-    let module = ctx.module;
+    let module = ctx.module?;
     let n_fields = fields.len();
     let fields = fields
         .iter()
diff --git a/crates/ide_completion/src/snippet.rs b/crates/ide_completion/src/snippet.rs
index 82632f440d..0a154f14e5 100644
--- a/crates/ide_completion/src/snippet.rs
+++ b/crates/ide_completion/src/snippet.rs
@@ -102,11 +102,11 @@ use std::ops::Deref;
 // }
 // ----
 
-use ide_db::imports::import_assets::LocatedImport;
+use ide_db::imports::{import_assets::LocatedImport, insert_use::ImportScope};
 use itertools::Itertools;
 use syntax::{ast, AstNode, GreenNode, SyntaxNode};
 
-use crate::context::CompletionContext;
+use crate::{context::CompletionContext, ImportEdit};
 
 /// A snippet scope describing where a snippet may apply to.
 /// These may differ slightly in meaning depending on the snippet trigger.
@@ -156,8 +156,12 @@ impl Snippet {
     }
 
     /// Returns [`None`] if the required items do not resolve.
-    pub(crate) fn imports(&self, ctx: &CompletionContext) -> Option<Vec<LocatedImport>> {
-        import_edits(ctx, &self.requires)
+    pub(crate) fn imports(
+        &self,
+        ctx: &CompletionContext,
+        import_scope: &ImportScope,
+    ) -> Option<Vec<ImportEdit>> {
+        import_edits(ctx, import_scope, &self.requires)
     }
 
     pub fn snippet(&self) -> String {
@@ -169,7 +173,11 @@ impl Snippet {
     }
 }
 
-fn import_edits(ctx: &CompletionContext, requires: &[GreenNode]) -> Option<Vec<LocatedImport>> {
+fn import_edits(
+    ctx: &CompletionContext,
+    import_scope: &ImportScope,
+    requires: &[GreenNode],
+) -> Option<Vec<ImportEdit>> {
     let resolve = |import: &GreenNode| {
         let path = ast::Path::cast(SyntaxNode::new_root(import.clone()))?;
         let item = match ctx.scope.speculative_resolve(&path)? {
@@ -177,8 +185,11 @@ fn import_edits(ctx: &CompletionContext, requires: &[GreenNode]) -> Option<Vec<L
             _ => return None,
         };
         let path =
-            ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
-        Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
+            ctx.module?.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
+        Some((path.len() > 1).then(|| ImportEdit {
+            import: LocatedImport::new(path.clone(), item, item, None),
+            scope: import_scope.clone(),
+        }))
     };
     let mut res = Vec::with_capacity(requires.len());
     for import in requires {
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index 34b557e21e..36457a5364 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -482,6 +482,14 @@ impl From<PathResolution> for Definition {
     fn from(path_resolution: PathResolution) -> Self {
         match path_resolution {
             PathResolution::Def(def) => def.into(),
+            PathResolution::AssocItem(item) => {
+                let def: ModuleDef = match item {
+                    hir::AssocItem::Function(it) => it.into(),
+                    hir::AssocItem::Const(it) => it.into(),
+                    hir::AssocItem::TypeAlias(it) => it.into(),
+                };
+                def.into()
+            }
             PathResolution::Local(local) => Definition::Local(local),
             PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
             PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
diff --git a/crates/ide_db/src/famous_defs.rs b/crates/ide_db/src/famous_defs.rs
index 58d99ff9df..cc9f2f9151 100644
--- a/crates/ide_db/src/famous_defs.rs
+++ b/crates/ide_db/src/famous_defs.rs
@@ -1,6 +1,4 @@
 //! See [`FamousDefs`].
-
-use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase};
 use hir::{Crate, Enum, Macro, Module, ScopeDef, Semantics, Trait};
 
 use crate::RootDatabase;
@@ -18,28 +16,16 @@ use crate::RootDatabase;
 /// ```
 /// //- minicore: iterator, ord, derive
 /// ```
-pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
+pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
 
 #[allow(non_snake_case)]
 impl FamousDefs<'_, '_> {
     pub fn std(&self) -> Option<Crate> {
-        self.find_lang_crate(LangCrateOrigin::Std)
+        self.find_crate("std")
     }
 
     pub fn core(&self) -> Option<Crate> {
-        self.find_lang_crate(LangCrateOrigin::Core)
-    }
-
-    pub fn alloc(&self) -> Option<Crate> {
-        self.find_lang_crate(LangCrateOrigin::Alloc)
-    }
-
-    pub fn test(&self) -> Option<Crate> {
-        self.find_lang_crate(LangCrateOrigin::Test)
-    }
-
-    pub fn proc_macro(&self) -> Option<Crate> {
-        self.find_lang_crate(LangCrateOrigin::ProcMacro)
+        self.find_crate("core")
     }
 
     pub fn core_cmp_Ord(&self) -> Option<Trait> {
@@ -102,6 +88,18 @@ impl FamousDefs<'_, '_> {
         self.find_macro("core:macros:builtin:derive")
     }
 
+    pub fn alloc(&self) -> Option<Crate> {
+        self.find_crate("alloc")
+    }
+
+    pub fn test(&self) -> Option<Crate> {
+        self.find_crate("test")
+    }
+
+    pub fn proc_macro(&self) -> Option<Crate> {
+        self.find_crate("proc_macro")
+    }
+
     pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
         IntoIterator::into_iter([
             self.std(),
@@ -141,15 +139,11 @@ impl FamousDefs<'_, '_> {
         }
     }
 
-    fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate> {
-        let krate = self.1;
+    fn find_crate(&self, name: &str) -> Option<Crate> {
+        let krate = self.1?;
         let db = self.0.db;
-        let crate_graph = self.0.db.crate_graph();
-        let res = krate
-            .dependencies(db)
-            .into_iter()
-            .find(|dep| crate_graph[dep.krate.into()].origin == CrateOrigin::Lang(origin))?
-            .krate;
+        let res =
+            krate.dependencies(db).into_iter().find(|dep| dep.name.to_smol_str() == name)?.krate;
         Some(res)
     }
 
@@ -157,16 +151,8 @@ impl FamousDefs<'_, '_> {
         let db = self.0.db;
         let mut path = path.split(':');
         let trait_ = path.next_back()?;
-        let lang_crate = path.next()?;
-        let lang_crate = match lang_crate {
-            "core" => LangCrateOrigin::Core,
-            "alloc" => LangCrateOrigin::Alloc,
-            "test" => LangCrateOrigin::Test,
-            "proc_macro" => LangCrateOrigin::ProcMacro,
-            "std" => LangCrateOrigin::Std,
-            _ => return None,
-        };
-        let std_crate = self.find_lang_crate(lang_crate)?;
+        let std_crate = path.next()?;
+        let std_crate = self.find_crate(std_crate)?;
         let mut module = std_crate.root_module(db);
         for segment in path {
             module = module.children(db).find_map(|child| {
diff --git a/crates/ide_db/src/imports/import_assets.rs b/crates/ide_db/src/imports/import_assets.rs
index f8cfe15c89..d6246c7ad6 100644
--- a/crates/ide_db/src/imports/import_assets.rs
+++ b/crates/ide_db/src/imports/import_assets.rs
@@ -104,7 +104,7 @@ impl ImportAssets {
         let candidate_node = method_call.syntax().clone();
         Some(Self {
             import_candidate: ImportCandidate::for_method_call(sema, method_call)?,
-            module_with_candidate: sema.scope(&candidate_node)?.module(),
+            module_with_candidate: sema.scope(&candidate_node).module()?,
             candidate_node,
         })
     }
@@ -119,7 +119,7 @@ impl ImportAssets {
         }
         Some(Self {
             import_candidate: ImportCandidate::for_regular_path(sema, fully_qualified_path)?,
-            module_with_candidate: sema.scope(&candidate_node)?.module(),
+            module_with_candidate: sema.scope(&candidate_node).module()?,
             candidate_node,
         })
     }
@@ -132,7 +132,7 @@ impl ImportAssets {
         let candidate_node = pat.syntax().clone();
         Some(Self {
             import_candidate: ImportCandidate::for_name(sema, &name)?,
-            module_with_candidate: sema.scope(&candidate_node)?.module(),
+            module_with_candidate: sema.scope(&candidate_node).module()?,
             candidate_node,
         })
     }
@@ -248,10 +248,7 @@ impl ImportAssets {
         };
 
         let krate = self.module_with_candidate.krate();
-        let scope = match sema.scope(&self.candidate_node) {
-            Some(it) => it,
-            None => return Vec::new(),
-        };
+        let scope = sema.scope(&self.candidate_node);
 
         match &self.import_candidate {
             ImportCandidate::Path(path_candidate) => {
@@ -274,11 +271,9 @@ impl ImportAssets {
     fn scope_definitions(&self, sema: &Semantics<RootDatabase>) -> FxHashSet<ScopeDef> {
         let _p = profile::span("import_assets::scope_definitions");
         let mut scope_definitions = FxHashSet::default();
-        if let Some(scope) = sema.scope(&self.candidate_node) {
-            scope.process_all_names(&mut |_, scope_def| {
-                scope_definitions.insert(scope_def);
-            });
-        }
+        sema.scope(&self.candidate_node).process_all_names(&mut |_, scope_def| {
+            scope_definitions.insert(scope_def);
+        });
         scope_definitions
     }
 }
@@ -593,7 +588,7 @@ impl ImportCandidate {
 
     fn for_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option<Self> {
         if sema
-            .scope(name.syntax())?
+            .scope(name.syntax())
             .speculative_resolve(&ast::make::ext::ident_path(&name.text()))
             .is_some()
         {
diff --git a/crates/ide_db/src/imports/merge_imports.rs b/crates/ide_db/src/imports/merge_imports.rs
index 9a9097ba5e..c7d9034f74 100644
--- a/crates/ide_db/src/imports/merge_imports.rs
+++ b/crates/ide_db/src/imports/merge_imports.rs
@@ -3,7 +3,7 @@ use std::cmp::Ordering;
 
 use itertools::{EitherOrBoth, Itertools};
 use syntax::{
-    ast::{self, make, AstNode, HasAttrs, HasVisibility, PathSegmentKind},
+    ast::{self, AstNode, HasAttrs, HasVisibility, PathSegmentKind},
     ted,
 };
 
@@ -129,29 +129,7 @@ fn recursive_merge(lhs: &ast::UseTree, rhs: &ast::UseTree, merge: MergeBehavior)
                         _ => (),
                     }
 
-                    // Glob imports aren't part of the use-tree lists so we need
-                    // to special handle them here as well this special handling
-                    // is only required for when we merge a module import into a
-                    // glob import of said module see the `merge_self_glob` or
-                    // `merge_mod_into_glob` tests.
-                    if lhs_t.star_token().is_some() || rhs_t.star_token().is_some() {
-                        if tree_is_self(lhs_t) || tree_is_self(&rhs_t) {
-                            cov_mark::hit!(merge_self_glob);
-                            let self_tree = make::use_tree(
-                                make::path_unqualified(make::path_segment_self()),
-                                None,
-                                None,
-                                false,
-                            )
-                            .clone_for_update();
-                            ted::replace(lhs_t.syntax(), self_tree.syntax());
-                            *lhs_t = self_tree;
-                            let glob = make::use_tree_glob().clone_for_update();
-                            use_trees.insert(idx, glob.clone());
-                            lhs.get_or_create_use_tree_list().add_use_tree(glob);
-                            continue;
-                        }
-                    } else if lhs_t.use_tree_list().is_none() && rhs_t.use_tree_list().is_none() {
+                    if lhs_t.is_simple_path() && rhs_t.is_simple_path() {
                         continue;
                     }
                 }
diff --git a/crates/ide_db/src/path_transform.rs b/crates/ide_db/src/path_transform.rs
index 61b2c3f3b8..558f4f1b63 100644
--- a/crates/ide_db/src/path_transform.rs
+++ b/crates/ide_db/src/path_transform.rs
@@ -2,7 +2,7 @@
 
 use crate::helpers::mod_path_to_ast;
 use either::Either;
-use hir::{AsAssocItem, HirDisplay, SemanticsScope};
+use hir::{HirDisplay, SemanticsScope};
 use rustc_hash::FxHashMap;
 use syntax::{
     ast::{self, AstNode},
@@ -69,13 +69,15 @@ impl<'a> PathTransform<'a> {
     }
 
     pub fn apply(&self, syntax: &SyntaxNode) {
-        self.build_ctx().apply(syntax)
+        if let Some(ctx) = self.build_ctx() {
+            ctx.apply(syntax)
+        }
     }
 
-    fn build_ctx(&self) -> Ctx<'a> {
+    fn build_ctx(&self) -> Option<Ctx<'a>> {
         let db = self.source_scope.db;
-        let target_module = self.target_scope.module();
-        let source_module = self.source_scope.module();
+        let target_module = self.target_scope.module()?;
+        let source_module = self.source_scope.module()?;
         let skip = match self.generic_def {
             // this is a trait impl, so we need to skip the first type parameter -- this is a bit hacky
             hir::GenericDef::Trait(_) => 1,
@@ -109,7 +111,8 @@ impl<'a> PathTransform<'a> {
                 },
             })
             .collect();
-        Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope }
+        let res = Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope };
+        Some(res)
     }
 }
 
@@ -197,7 +200,7 @@ impl<'a> Ctx<'a> {
                     }
                 }
             }
-            hir::PathResolution::Def(def) if def.as_assoc_item(self.source_scope.db).is_none() => {
+            hir::PathResolution::Def(def) => {
                 if let hir::ModuleDef::Trait(_) = def {
                     if matches!(path.segment()?.kind()?, ast::PathSegmentKind::Type { .. }) {
                         // `speculative_resolve` resolves segments like `<T as
@@ -222,7 +225,7 @@ impl<'a> Ctx<'a> {
             hir::PathResolution::Local(_)
             | hir::PathResolution::ConstParam(_)
             | hir::PathResolution::SelfType(_)
-            | hir::PathResolution::Def(_)
+            | hir::PathResolution::AssocItem(_)
             | hir::PathResolution::BuiltinAttr(_)
             | hir::PathResolution::ToolModule(_) => (),
         }
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index fe99c2e2ce..805eac30b8 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -734,7 +734,13 @@ fn def_to_ty(sema: &Semantics<RootDatabase>, def: &Definition) -> Option<hir::Ty
     match def {
         Definition::Adt(adt) => Some(adt.ty(sema.db)),
         Definition::TypeAlias(it) => Some(it.ty(sema.db)),
-        Definition::BuiltinType(it) => Some(it.ty(sema.db)),
+        Definition::BuiltinType(it) => {
+            let graph = sema.db.crate_graph();
+            let krate = graph.iter().next()?;
+            let root_file = graph[krate].root_file_id;
+            let module = sema.to_module_def(root_file)?;
+            Some(it.ty(sema.db, module))
+        }
         Definition::SelfType(it) => Some(it.self_ty(sema.db)),
         _ => None,
     }
diff --git a/crates/ide_diagnostics/src/handlers/missing_fields.rs b/crates/ide_diagnostics/src/handlers/missing_fields.rs
index 414878b230..8b3c22fffc 100644
--- a/crates/ide_diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide_diagnostics/src/handlers/missing_fields.rs
@@ -64,7 +64,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
 
     let new_field_list = old_field_list.clone_for_update();
     let mut locals = FxHashMap::default();
-    ctx.sema.scope(field_list_parent.syntax())?.process_all_names(&mut |name, def| {
+    ctx.sema.scope(field_list_parent.syntax()).process_all_names(&mut |name, def| {
         if let hir::ScopeDef::Local(local) = def {
             locals.insert(name, local);
         }
@@ -171,7 +171,11 @@ fn get_default_constructor(
     if has_new_func {
         Some(make::ext::expr_ty_new(&make_ty(ty, ctx.sema.db, module)))
     } else if !ty.is_array()
-        && ty.impls_trait(ctx.sema.db, FamousDefs(&ctx.sema, krate).core_default_Default()?, &[])
+        && ty.impls_trait(
+            ctx.sema.db,
+            FamousDefs(&ctx.sema, Some(krate)).core_default_Default()?,
+            &[],
+        )
     {
         Some(make::ext::expr_ty_default(&make_ty(ty, ctx.sema.db, module)))
     } else {
diff --git a/crates/ide_diagnostics/src/handlers/type_mismatch.rs b/crates/ide_diagnostics/src/handlers/type_mismatch.rs
index 1b275f7e6c..040dcbd1d9 100644
--- a/crates/ide_diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide_diagnostics/src/handlers/type_mismatch.rs
@@ -1,5 +1,8 @@
-use hir::{db::AstDatabase, HirDisplay, Type};
-use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
+use hir::{db::AstDatabase, HirDisplay, Type, TypeInfo};
+use ide_db::{
+    famous_defs::FamousDefs, source_change::SourceChange,
+    syntax_helpers::node_ext::for_each_tail_expr,
+};
 use syntax::{
     ast::{BlockExpr, ExprStmt},
     AstNode,
@@ -74,9 +77,9 @@ fn add_missing_ok_or_some(
     acc: &mut Vec<Assist>,
 ) -> Option<()> {
     let root = ctx.sema.db.parse_or_expand(d.expr.file_id)?;
-    let expr = d.expr.value.to_node(&root);
-    let expr_range = expr.syntax().text_range();
-    let scope = ctx.sema.scope(expr.syntax())?;
+    let tail_expr = d.expr.value.to_node(&root);
+    let tail_expr_range = tail_expr.syntax().text_range();
+    let scope = ctx.sema.scope(tail_expr.syntax());
 
     let expected_adt = d.expected.as_adt()?;
     let expected_enum = expected_adt.as_enum()?;
@@ -98,12 +101,16 @@ fn add_missing_ok_or_some(
     }
 
     let mut builder = TextEdit::builder();
-    builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
-    builder.insert(expr.syntax().text_range().end(), ")".to_string());
+    for_each_tail_expr(&tail_expr, &mut |expr| {
+        if ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted).as_ref() != Some(&d.expected) {
+            builder.insert(expr.syntax().text_range().start(), format!("{}(", variant_name));
+            builder.insert(expr.syntax().text_range().end(), ")".to_string());
+        }
+    });
     let source_change =
         SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), builder.finish());
     let name = format!("Wrap in {}", variant_name);
-    acc.push(fix("wrap_in_constructor", &name, source_change, expr_range));
+    acc.push(fix("wrap_tail_expr", &name, source_change, tail_expr_range));
     Some(())
 }
 
@@ -323,12 +330,12 @@ fn div(x: i32, y: i32) -> Option<i32> {
 //- minicore: option, result
 fn div(x: i32, y: i32) -> Option<i32> {
     if y == 0 {
-        Some(0)
+        0
     } else if true {
-        100$0
+        100
     } else {
         None
-    }
+    }$0
 }
 "#,
             r#"
diff --git a/crates/ide_ssr/src/from_comment.rs b/crates/ide_ssr/src/from_comment.rs
index c50e74d93a..f1b312284d 100644
--- a/crates/ide_ssr/src/from_comment.rs
+++ b/crates/ide_ssr/src/from_comment.rs
@@ -25,7 +25,7 @@ pub fn ssr_from_comment(db: &RootDatabase, frange: FileRange) -> Option<(MatchFi
 
     let lookup_context = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
 
-    let mut match_finder = MatchFinder::in_context(db, lookup_context, vec![]).ok()?;
+    let mut match_finder = MatchFinder::in_context(db, lookup_context, vec![]);
     match_finder.add_rule(ssr_rule).ok()?;
 
     Some((match_finder, comment.syntax().text_range()))
diff --git a/crates/ide_ssr/src/lib.rs b/crates/ide_ssr/src/lib.rs
index 4db8034212..d56bc12b68 100644
--- a/crates/ide_ssr/src/lib.rs
+++ b/crates/ide_ssr/src/lib.rs
@@ -128,12 +128,11 @@ impl<'db> MatchFinder<'db> {
         db: &'db ide_db::RootDatabase,
         lookup_context: FilePosition,
         mut restrict_ranges: Vec<FileRange>,
-    ) -> Result<MatchFinder<'db>, SsrError> {
+    ) -> MatchFinder<'db> {
         restrict_ranges.retain(|range| !range.range.is_empty());
         let sema = Semantics::new(db);
-        let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context)
-            .ok_or_else(|| SsrError("no resolution scope for file".into()))?;
-        Ok(MatchFinder { sema, rules: Vec::new(), resolution_scope, restrict_ranges })
+        let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context);
+        MatchFinder { sema, rules: Vec::new(), resolution_scope, restrict_ranges }
     }
 
     /// Constructs an instance using the start of the first file in `db` as the lookup context.
@@ -143,11 +142,11 @@ impl<'db> MatchFinder<'db> {
         if let Some(first_file_id) =
             db.local_roots().iter().next().and_then(|root| db.source_root(*root).iter().next())
         {
-            MatchFinder::in_context(
+            Ok(MatchFinder::in_context(
                 db,
                 FilePosition { file_id: first_file_id, offset: 0.into() },
                 vec![],
-            )
+            ))
         } else {
             bail!("No files to search");
         }
diff --git a/crates/ide_ssr/src/matching.rs b/crates/ide_ssr/src/matching.rs
index ba5aa0cc94..88c1d80608 100644
--- a/crates/ide_ssr/src/matching.rs
+++ b/crates/ide_ssr/src/matching.rs
@@ -646,8 +646,8 @@ impl Match {
     ) -> Result<(), MatchFailed> {
         let module = sema
             .scope(&self.matched_node)
-            .ok_or_else(|| match_error!("Matched node isn't in a module"))?
-            .module();
+            .module()
+            .ok_or_else(|| match_error!("Matched node isn't in a module"))?;
         for (path, resolved_path) in &template.resolved_paths {
             if let hir::PathResolution::Def(module_def) = resolved_path.resolution {
                 let mod_path = module.find_use_path(sema.db, module_def).ok_or_else(|| {
@@ -788,7 +788,7 @@ mod tests {
         let input = "fn foo() {} fn bar() {} fn main() { foo(1+2); }";
 
         let (db, position, selections) = crate::tests::single_file(input);
-        let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
+        let mut match_finder = MatchFinder::in_context(&db, position, selections);
         match_finder.add_rule(rule).unwrap();
         let matches = match_finder.matches();
         assert_eq!(matches.matches.len(), 1);
diff --git a/crates/ide_ssr/src/resolving.rs b/crates/ide_ssr/src/resolving.rs
index 84bf792fe0..e15cb874ef 100644
--- a/crates/ide_ssr/src/resolving.rs
+++ b/crates/ide_ssr/src/resolving.rs
@@ -2,7 +2,6 @@
 
 use crate::errors::error;
 use crate::{parsing, SsrError};
-use hir::AsAssocItem;
 use ide_db::base_db::FilePosition;
 use parsing::Placeholder;
 use rustc_hash::FxHashMap;
@@ -83,17 +82,14 @@ impl Resolver<'_, '_> {
             .filter_map(|(path_node, resolved)| {
                 if let Some(grandparent) = path_node.parent().and_then(|parent| parent.parent()) {
                     if let Some(call_expr) = ast::CallExpr::cast(grandparent.clone()) {
-                        if let hir::PathResolution::Def(hir::ModuleDef::Function(function)) =
+                        if let hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) =
                             resolved.resolution
                         {
-                            if function.as_assoc_item(self.resolution_scope.scope.db).is_some() {
-                                let qualifier_type =
-                                    self.resolution_scope.qualifier_type(path_node);
-                                return Some((
-                                    grandparent,
-                                    UfcsCallInfo { call_expr, function, qualifier_type },
-                                ));
-                            }
+                            let qualifier_type = self.resolution_scope.qualifier_type(path_node);
+                            return Some((
+                                grandparent,
+                                UfcsCallInfo { call_expr, function, qualifier_type },
+                            ));
                         }
                     }
                 }
@@ -166,9 +162,7 @@ impl Resolver<'_, '_> {
 
     fn ok_to_use_path_resolution(&self, resolution: &hir::PathResolution) -> bool {
         match resolution {
-            hir::PathResolution::Def(hir::ModuleDef::Function(function))
-                if function.as_assoc_item(self.resolution_scope.scope.db).is_some() =>
-            {
+            hir::PathResolution::AssocItem(hir::AssocItem::Function(function)) => {
                 if function.self_param(self.resolution_scope.scope.db).is_some() {
                     // If we don't use this path resolution, then we won't be able to match method
                     // calls. e.g. `Foo::bar($s)` should match `x.bar()`.
@@ -178,9 +172,7 @@ impl Resolver<'_, '_> {
                     false
                 }
             }
-            hir::PathResolution::Def(
-                def @ (hir::ModuleDef::Const(_) | hir::ModuleDef::TypeAlias(_)),
-            ) if def.as_assoc_item(self.resolution_scope.scope.db).is_some() => {
+            hir::PathResolution::AssocItem(_) => {
                 // Not a function. Could be a constant or an associated type.
                 cov_mark::hit!(replace_associated_trait_constant);
                 false
@@ -194,7 +186,7 @@ impl<'db> ResolutionScope<'db> {
     pub(crate) fn new(
         sema: &hir::Semantics<'db, ide_db::RootDatabase>,
         resolve_context: FilePosition,
-    ) -> Option<ResolutionScope<'db>> {
+    ) -> ResolutionScope<'db> {
         use syntax::ast::AstNode;
         let file = sema.parse(resolve_context.file_id);
         // Find a node at the requested position, falling back to the whole file.
@@ -205,8 +197,8 @@ impl<'db> ResolutionScope<'db> {
             .and_then(|token| token.parent())
             .unwrap_or_else(|| file.syntax().clone());
         let node = pick_node_for_resolution(node);
-        let scope = sema.scope(&node)?;
-        Some(ResolutionScope { scope, node })
+        let scope = sema.scope(&node);
+        ResolutionScope { scope, node }
     }
 
     /// Returns the function in which SSR was invoked, if any.
@@ -227,7 +219,7 @@ impl<'db> ResolutionScope<'db> {
         let resolved_qualifier = self.scope.speculative_resolve(&path.qualifier()?)?;
         if let hir::PathResolution::Def(hir::ModuleDef::Adt(adt)) = resolved_qualifier {
             let name = path.segment()?.name_ref()?;
-            let module = self.scope.module();
+            let module = self.scope.module()?;
             adt.ty(self.scope.db).iterate_path_candidates(
                 self.scope.db,
                 &self.scope,
@@ -237,7 +229,7 @@ impl<'db> ResolutionScope<'db> {
                 |assoc_item| {
                     let item_name = assoc_item.name(self.scope.db)?;
                     if item_name.to_smol_str().as_str() == name.text() {
-                        Some(hir::PathResolution::Def(assoc_item.into()))
+                        Some(hir::PathResolution::AssocItem(assoc_item))
                     } else {
                         None
                     }
diff --git a/crates/parser/src/grammar/params.rs b/crates/parser/src/grammar/params.rs
index c2e633fdb0..a000f515cc 100644
--- a/crates/parser/src/grammar/params.rs
+++ b/crates/parser/src/grammar/params.rs
@@ -71,10 +71,13 @@ fn list_(p: &mut Parser, flavor: Flavor) {
             m.abandon(p);
             break;
         }
-        param(p, m, flavor);
+        let param = param(p, m, flavor);
         if !p.at(ket) {
             p.expect(T![,]);
         }
+        if let Variadic(true) = param {
+            break;
+        }
     }
 
     if let Some(m) = param_marker {
@@ -87,24 +90,27 @@ fn list_(p: &mut Parser, flavor: Flavor) {
 
 const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
 
-fn param(p: &mut Parser, m: Marker, flavor: Flavor) {
+struct Variadic(bool);
+
+fn param(p: &mut Parser, m: Marker, flavor: Flavor) -> Variadic {
+    let mut res = Variadic(false);
     match flavor {
         // test param_list_vararg
-        // extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; }
-        Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => {}
+        // extern "C" { fn printf(format: *const i8, ...) -> i32; }
+        Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => res = Variadic(true),
 
         // test fn_def_param
-        // fn foo(..., (x, y): (i32, i32)) {}
+        // fn foo((x, y): (i32, i32)) {}
         Flavor::FnDef => {
             patterns::pattern(p);
-            if !variadic_param(p) {
-                if p.at(T![:]) {
-                    types::ascription(p);
-                } else {
-                    // test_err missing_fn_param_type
-                    // fn f(x y: i32, z, t: i32) {}
-                    p.error("missing type for function parameter");
-                }
+            if variadic_param(p) {
+                res = Variadic(true);
+            } else if p.at(T![:]) {
+                types::ascription(p);
+            } else {
+                // test_err missing_fn_param_type
+                // fn f(x y: i32, z, t: i32) {}
+                p.error("missing type for function parameter");
             }
         }
         // test value_parameters_no_patterns
@@ -121,12 +127,12 @@ fn param(p: &mut Parser, m: Marker, flavor: Flavor) {
         Flavor::FnPointer => {
             if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) {
                 patterns::pattern_single(p);
-                if !variadic_param(p) {
-                    if p.at(T![:]) {
-                        types::ascription(p);
-                    } else {
-                        p.error("missing type for function parameter");
-                    }
+                if variadic_param(p) {
+                    res = Variadic(true);
+                } else if p.at(T![:]) {
+                    types::ascription(p);
+                } else {
+                    p.error("missing type for function parameter");
                 }
             } else {
                 types::type_(p);
@@ -144,6 +150,7 @@ fn param(p: &mut Parser, m: Marker, flavor: Flavor) {
         }
     }
     m.complete(p, PARAM);
+    res
 }
 
 fn variadic_param(p: &mut Parser) -> bool {
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 46db487d02..ff067f5293 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -57,12 +57,6 @@ fn type_with_bounds_cond(p: &mut Parser, allow_bounds: bool) {
 pub(super) fn ascription(p: &mut Parser) {
     assert!(p.at(T![:]));
     p.bump(T![:]);
-    if p.at(T![=]) {
-        // recover from `let x: = expr;`, `const X: = expr;` and similars
-        // hopefully no type starts with `=`
-        p.error("missing type");
-        return;
-    }
     type_(p);
 }
 
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 509219f0b6..1a86d232eb 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -7,7 +7,7 @@ use std::{collections::VecDeque, fmt, fs, process::Command};
 use anyhow::{format_err, Context, Result};
 use base_db::{
     CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
-    FileId, LangCrateOrigin, ProcMacro,
+    FileId, ProcMacro,
 };
 use cfg::{CfgDiff, CfgOptions};
 use paths::{AbsPath, AbsPathBuf};
@@ -487,7 +487,7 @@ fn project_json_to_crate_graph(
                     if krate.display_name.is_some() {
                         CrateOrigin::CratesIo { repo: krate.repository.clone() }
                     } else {
-                        CrateOrigin::CratesIo { repo: None }
+                        CrateOrigin::Unknown
                     },
                 ),
             )
@@ -710,7 +710,7 @@ fn detached_files_to_crate_graph(
             Env::default(),
             Vec::new(),
             false,
-            CrateOrigin::CratesIo { repo: None },
+            CrateOrigin::Unknown,
         );
 
         public_deps.add(detached_file_crate, &mut crate_graph);
@@ -908,14 +908,7 @@ fn sysroot_to_crate_graph(
                 env,
                 proc_macro,
                 false,
-                CrateOrigin::Lang(match &*sysroot[krate].name {
-                    "alloc" => LangCrateOrigin::Alloc,
-                    "core" => LangCrateOrigin::Core,
-                    "proc_macro" => LangCrateOrigin::ProcMacro,
-                    "std" => LangCrateOrigin::Std,
-                    "test" => LangCrateOrigin::Test,
-                    _ => LangCrateOrigin::Other,
-                }),
+                CrateOrigin::Lang,
             );
             Some((krate, crate_id))
         })
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 15f4978367..8f91f64a69 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -123,14 +123,6 @@ pub(crate) fn handle_view_hir(
     Ok(res)
 }
 
-pub(crate) fn handle_view_file_text(
-    snap: GlobalStateSnapshot,
-    params: lsp_types::TextDocumentIdentifier,
-) -> Result<String> {
-    let file_id = from_proto::file_id(&snap, &params.uri)?;
-    Ok(snap.analysis.file_text(file_id)?.to_string())
-}
-
 pub(crate) fn handle_view_item_tree(
     snap: GlobalStateSnapshot,
     params: lsp_ext::ViewItemTreeParams,
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index b638a57111..2e131eeac9 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -70,14 +70,6 @@ impl Request for ViewHir {
     const METHOD: &'static str = "rust-analyzer/viewHir";
 }
 
-pub enum ViewFileText {}
-
-impl Request for ViewFileText {
-    type Params = lsp_types::TextDocumentIdentifier;
-    type Result = String;
-    const METHOD: &'static str = "rust-analyzer/viewFileText";
-}
-
 #[derive(Deserialize, Serialize, Debug)]
 #[serde(rename_all = "camelCase")]
 pub struct ViewCrateGraphParams {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 2d898d76a6..b62a830803 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -590,7 +590,6 @@ impl GlobalState {
             .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
             .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
             .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
-            .on::<lsp_ext::ViewFileText>(handlers::handle_view_file_text)
             .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
             .on::<lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
             .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs
index 912ed1e764..e1ff0f0178 100644
--- a/crates/rust-analyzer/src/markdown.rs
+++ b/crates/rust-analyzer/src/markdown.rs
@@ -1,7 +1,7 @@
 //! Transforms markdown
 use ide_db::rust_doc::is_rust_fence;
 
-const RUSTDOC_FENCES: [&str; 2] = ["```", "~~~"];
+const RUSTDOC_FENCE: &str = "```";
 
 pub(crate) fn format_docs(src: &str) -> String {
     let mut processed_lines = Vec::new();
@@ -13,8 +13,7 @@ pub(crate) fn format_docs(src: &str) -> String {
             continue;
         }
 
-        if let Some(header) = RUSTDOC_FENCES.into_iter().find_map(|fence| line.strip_prefix(fence))
-        {
+        if let Some(header) = line.strip_prefix(RUSTDOC_FENCE) {
             in_code_block ^= true;
 
             if in_code_block {
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 9b377f742b..7c5785bfb8 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -283,7 +283,7 @@ fn completion_item(
             let imports: Vec<_> = imports
                 .iter()
                 .filter_map(|import_edit| {
-                    let import_path = &import_edit.import_path;
+                    let import_path = &import_edit.import.import_path;
                     let import_name = import_path.segments().last()?;
                     Some(lsp_ext::CompletionImport {
                         full_import_path: import_path.to_string(),
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index bb4d10207d..4a454cb8b7 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -30,7 +30,7 @@ rayon = "1.5.1"
 expect-test = "1.2.2"
 proc-macro2 = "1.0.36"
 quote = "1.0.16"
-ungrammar = "1.16.1"
+ungrammar = "=1.16.1"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
deleted file mode 100644
index cb58486eff..0000000000
--- a/crates/syntax/rust.ungram
+++ /dev/null
@@ -1,664 +0,0 @@
-// Rust Un-Grammar.
-//
-// This grammar specifies the structure of Rust's concrete syntax tree.
-// It does not specify parsing rules (ambiguities, precedence, etc are out of scope).
-// Tokens are processed -- contextual keywords are recognised, compound operators glued.
-//
-// Legend:
-//
-//   //          -- comment
-//   Name =      -- non-terminal definition
-//   'ident'     -- token (terminal)
-//   A B         -- sequence
-//   A | B       -- alternation
-//   A*          -- zero or more repetition
-//   A?          -- zero or one repetition
-//   (A)         -- same as A
-//   label:A     -- suggested name for field of AST node
-
-//*************************//
-// Names, Paths and Macros //
-//*************************//
-
-Name =
-  'ident' | 'self'
-
-NameRef =
-  'ident' | 'int_number' | 'self' | 'super' | 'crate' | 'Self'
-
-Lifetime =
-  'lifetime_ident'
-
-Path =
-  (qualifier:Path '::')? segment:PathSegment
-
-PathSegment =
-  '::'? NameRef
-| NameRef GenericArgList?
-| NameRef ParamList RetType?
-| '<' PathType ('as' PathType)? '>'
-
-GenericArgList =
-  '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>'
-
-GenericArg =
-  TypeArg
-| AssocTypeArg
-| LifetimeArg
-| ConstArg
-
-TypeArg =
-  Type
-
-AssocTypeArg =
-  NameRef GenericParamList? (':' TypeBoundList | '=' Type)
-
-LifetimeArg =
-  Lifetime
-
-ConstArg =
-  Expr
-
-MacroCall =
-  Attr* Path '!' TokenTree ';'?
-
-TokenTree =
-  '(' ')'
-| '{' '}'
-| '[' ']'
-
-MacroItems =
-  Item*
-
-MacroStmts =
-  statements:Stmt*
-  Expr?
-
-//*************************//
-//          Items          //
-//*************************//
-
-SourceFile =
-  'shebang'?
-  Attr*
-  Item*
-
-Item =
-  Const
-| Enum
-| ExternBlock
-| ExternCrate
-| Fn
-| Impl
-| MacroCall
-| MacroRules
-| MacroDef
-| Module
-| Static
-| Struct
-| Trait
-| TypeAlias
-| Union
-| Use
-
-MacroRules =
-  Attr* Visibility?
-  'macro_rules' '!' Name
-  TokenTree
-
-MacroDef =
-  Attr* Visibility?
-  'macro' Name args:TokenTree?
-  body:TokenTree
-
-Module =
-  Attr* Visibility?
-  'mod' Name
-  (ItemList | ';')
-
-ItemList =
-  '{' Attr* Item* '}'
-
-ExternCrate =
-  Attr* Visibility?
-  'extern' 'crate' NameRef Rename? ';'
-
-Rename =
-  'as' (Name | '_')
-
-Use =
-  Attr* Visibility?
-  'use' UseTree ';'
-
-UseTree =
-  (Path? '::')? ('*' | UseTreeList)
-| Path Rename?
-
-UseTreeList =
-  '{' (UseTree (',' UseTree)* ','?)? '}'
-
-Fn =
- Attr* Visibility?
- 'default'? 'const'? 'async'? 'unsafe'? Abi?
- 'fn' Name GenericParamList? ParamList RetType? WhereClause?
- (body:BlockExpr | ';')
-
-Abi =
-  'extern' 'string'?
-
-ParamList =
-  '('(
-    SelfParam
-  | (SelfParam ',')? (Param (',' Param)* ','?)?
-  )')'
-| '|' (Param (',' Param)* ','?)? '|'
-
-SelfParam =
-  Attr* (
-    ('&' Lifetime?)? 'mut'? Name
-  | 'mut'? Name ':' Type
-  )
-
-Param =
-  Attr* (
-    Pat (':' Type)?
-  | Type
-  | '...'
-  )
-
-RetType =
-  '->' Type
-
-TypeAlias =
-  Attr* Visibility?
-  'default'?
-  'type' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
-  ('=' Type)? ';'
-
-Struct =
-  Attr* Visibility?
-  'struct' Name GenericParamList? (
-    WhereClause? (RecordFieldList | ';')
-  | TupleFieldList WhereClause? ';'
-  )
-
-RecordFieldList =
- '{' fields:(RecordField (',' RecordField)* ','?)? '}'
-
-RecordField =
-  Attr* Visibility?
-  Name ':' Type
-
-TupleFieldList =
-  '(' fields:(TupleField (',' TupleField)* ','?)? ')'
-
-TupleField =
-  Attr* Visibility?
-  Type
-
-FieldList =
-  RecordFieldList
-| TupleFieldList
-
-Enum =
-  Attr* Visibility?
-  'enum' Name GenericParamList? WhereClause?
-  VariantList
-
-VariantList =
- '{' (Variant (',' Variant)* ','?)? '}'
-
-Variant =
-  Attr* Visibility?
-  Name FieldList? ('=' Expr)?
-
-Union =
-  Attr* Visibility?
-  'union' Name GenericParamList? WhereClause?
-  RecordFieldList
-
-// A Data Type.
-//
-// Not used directly in the grammar, but handy to have anyway.
-Adt =
-  Enum
-| Struct
-| Union
-
-Const =
-  Attr* Visibility?
-  'default'?
-  'const' (Name | '_') ':' Type
-  ('=' body:Expr)? ';'
-
-Static =
-  Attr* Visibility?
-  'static' 'mut'? Name ':' Type
-  ('=' body:Expr)? ';'
-
-Trait =
-  Attr* Visibility?
-  'unsafe'? 'auto'?
-  'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
-  AssocItemList
-
-AssocItemList =
-  '{' Attr* AssocItem* '}'
-
-AssocItem =
-  Const
-| Fn
-| MacroCall
-| TypeAlias
-
-Impl =
-  Attr* Visibility?
-  'default'? 'unsafe'?
-  'impl' GenericParamList? ('const'? '!'? trait:Type 'for')? self_ty:Type WhereClause?
-  AssocItemList
-
-ExternBlock =
-  Attr* 'unsafe'? Abi ExternItemList
-
-ExternItemList =
-  '{' Attr* ExternItem* '}'
-
-ExternItem =
-  Fn
-| MacroCall
-| Static
-| TypeAlias
-
-GenericParamList =
-  '<' (GenericParam (',' GenericParam)* ','?)? '>'
-
-GenericParam =
-  ConstParam
-| LifetimeParam
-| TypeParam
-
-TypeParam =
-  Attr* Name (':' TypeBoundList?)?
-  ('=' default_type:Type)?
-
-ConstParam =
-  Attr* 'const' Name ':' Type
-  ('=' default_val:Expr)?
-
-LifetimeParam =
-  Attr* Lifetime (':' TypeBoundList?)?
-
-WhereClause =
-  'where' predicates:(WherePred (',' WherePred)* ','?)
-
-WherePred =
-  ('for' GenericParamList)?  (Lifetime | Type) ':' TypeBoundList?
-
-Visibility =
-  'pub' ('(' 'in'? Path ')')?
-
-Attr =
-  '#' '!'? '[' Meta ']'
-
-Meta =
-  Path ('=' Expr | TokenTree)?
-
-//****************************//
-// Statements and Expressions //
-//****************************//
-
-Stmt =
-  ';'
-| ExprStmt
-| Item
-| LetStmt
-
-LetStmt =
-  Attr* 'let' Pat (':' Type)?
-  '=' initializer:Expr
-  LetElse?
-  ';'
-
-LetElse =
-  'else' BlockExpr
-
-ExprStmt =
-  Expr ';'?
-
-Expr =
-  ArrayExpr
-| AwaitExpr
-| BinExpr
-| BlockExpr
-| BoxExpr
-| BreakExpr
-| CallExpr
-| CastExpr
-| ClosureExpr
-| ContinueExpr
-| FieldExpr
-| ForExpr
-| IfExpr
-| IndexExpr
-| Literal
-| LoopExpr
-| MacroCall
-| MacroStmts
-| MatchExpr
-| MethodCallExpr
-| ParenExpr
-| PathExpr
-| PrefixExpr
-| RangeExpr
-| RecordExpr
-| RefExpr
-| ReturnExpr
-| TryExpr
-| TupleExpr
-| WhileExpr
-| YieldExpr
-| LetExpr
-| UnderscoreExpr
-
-Literal =
-  Attr* value:(
-    'int_number' | 'float_number'
-  | 'string' | 'raw_string'
-  | 'byte_string' | 'raw_byte_string'
-  | 'true' | 'false'
-  | 'char' | 'byte'
-  )
-
-PathExpr =
-  Attr* Path
-
-StmtList =
-  '{'
-    Attr*
-    statements:Stmt*
-    tail_expr:Expr?
-  '}'
-
-RefExpr =
-  Attr* '&' ('raw' | 'mut' | 'const') Expr
-
-TryExpr =
-  Attr* Expr '?'
-
-BlockExpr =
-  Attr* Label? ('try' | 'unsafe' | 'async' | 'const') StmtList
-
-PrefixExpr =
-  Attr* op:('-' | '!' | '*') Expr
-
-BinExpr =
-  Attr*
-  lhs:Expr
-  op:(
-    '||' | '&&'
-  | '==' | '!=' | '<=' | '>=' | '<' | '>'
-  | '+' | '*' | '-' | '/' | '%' | '<<' | '>>' | '^' | '|' | '&'
-  | '=' | '+=' | '/=' | '*=' | '%=' | '>>=' | '<<=' | '-=' | '|=' | '&=' | '^='
-  )
-  rhs:Expr
-
-CastExpr =
-  Attr* Expr 'as' Type
-
-ParenExpr =
-  Attr* '(' Attr* Expr ')'
-
-ArrayExpr =
-  Attr* '[' Attr* (
-    (Expr (',' Expr)* ','?)?
-  | Expr ';' Expr
-  ) ']'
-
-IndexExpr =
-  Attr* base:Expr '[' index:Expr ']'
-
-TupleExpr =
-  Attr* '(' Attr* fields:(Expr (',' Expr)* ','?)? ')'
-
-RecordExpr =
-  Path RecordExprFieldList
-
-RecordExprFieldList =
-  '{'
-    Attr*
-    fields:(RecordExprField (',' RecordExprField)* ','?)?
-    ('..' spread:Expr?)?
-  '}'
-
-RecordExprField =
-  Attr* (NameRef ':')? Expr
-
-CallExpr =
-  Attr* Expr ArgList
-
-ArgList =
-  '(' args:(Expr (',' Expr)* ','?)? ')'
-
-MethodCallExpr =
-  Attr* receiver:Expr '.' NameRef GenericArgList? ArgList
-
-FieldExpr =
-  Attr* Expr '.' NameRef
-
-ClosureExpr =
-  Attr* 'static'? 'async'? 'move'?  ParamList RetType?
-  body:Expr
-
-IfExpr =
-  Attr* 'if' condition:Expr then_branch:BlockExpr
-  ('else' else_branch:(IfExpr | BlockExpr))?
-
-LoopExpr =
-  Attr* Label? 'loop'
-  loop_body:BlockExpr
-
-ForExpr =
-  Attr* Label? 'for' Pat 'in' iterable:Expr
-  loop_body:BlockExpr
-
-WhileExpr =
-  Attr* Label? 'while' condition:Expr
-  loop_body:BlockExpr
-
-Label =
-  Lifetime ':'
-
-BreakExpr =
-  Attr* 'break' Lifetime? Expr?
-
-ContinueExpr =
-  Attr* 'continue' Lifetime?
-
-RangeExpr =
-  Attr* start:Expr? op:('..' | '..=') end:Expr?
-
-MatchExpr =
-  Attr* 'match' Expr MatchArmList
-
-MatchArmList =
-  '{'
-    Attr*
-    arms:MatchArm*
-  '}'
-
-MatchArm =
-  Attr* Pat guard:MatchGuard? '=>' Expr ','?
-
-MatchGuard =
-  'if' condition:Expr
-
-ReturnExpr =
-  Attr* 'return' Expr?
-
-YieldExpr =
-  Attr* 'yield' Expr?
-
-LetExpr =
-  Attr* 'let' Pat '=' Expr
-
-UnderscoreExpr =
-  Attr* '_'
-
-AwaitExpr =
-  Attr* Expr '.' 'await'
-
-BoxExpr =
-  Attr* 'box' Expr
-
-//*************************//
-//          Types          //
-//*************************//
-
-Type =
-  ArrayType
-| DynTraitType
-| FnPtrType
-| ForType
-| ImplTraitType
-| InferType
-| MacroType
-| NeverType
-| ParenType
-| PathType
-| PtrType
-| RefType
-| SliceType
-| TupleType
-
-ParenType =
-  '(' Type ')'
-
-NeverType =
-  '!'
-
-MacroType =
-  MacroCall
-
-PathType =
-  Path
-
-TupleType =
-  '(' fields:(Type (',' Type)* ','?)? ')'
-
-PtrType =
-  '*' ('const' | 'mut') Type
-
-RefType =
-  '&' Lifetime? 'mut'? Type
-
-ArrayType =
-  '[' Type ';' Expr ']'
-
-SliceType =
-  '[' Type ']'
-
-InferType =
-  '_'
-
-FnPtrType =
-  'const'? 'async'? 'unsafe'? Abi? 'fn' ParamList RetType?
-
-ForType =
-  'for' GenericParamList Type
-
-ImplTraitType =
-  'impl' TypeBoundList
-
-DynTraitType =
-  'dyn' TypeBoundList
-
-TypeBoundList =
-  bounds:(TypeBound ('+' TypeBound)* '+'?)
-
-TypeBound =
-  Lifetime
-| ('?' | '~' 'const')? Type
-
-//************************//
-//        Patterns        //
-//************************//
-
-Pat =
-  IdentPat
-| BoxPat
-| RestPat
-| LiteralPat
-| MacroPat
-| OrPat
-| ParenPat
-| PathPat
-| WildcardPat
-| RangePat
-| RecordPat
-| RefPat
-| SlicePat
-| TuplePat
-| TupleStructPat
-| ConstBlockPat
-
-LiteralPat =
-  Literal
-
-IdentPat =
-  Attr* 'ref'? 'mut'? Name ('@' Pat)?
-
-WildcardPat =
-  '_'
-
-RangePat =
-  // 1..
-  start:Pat op:('..' | '..=')
-  // 1..2
-  | start:Pat op:('..' | '..=') end:Pat
-  // ..2
-  | op:('..' | '..=') end:Pat
-
-RefPat =
-  '&' 'mut'? Pat
-
-RecordPat =
-  Path RecordPatFieldList
-
-RecordPatFieldList =
-  '{'
-    fields:(RecordPatField (',' RecordPatField)* ','?)?
-    RestPat?
-  '}'
-
-RecordPatField =
-  Attr* (NameRef ':')? Pat
-
-TupleStructPat =
-   Path '(' fields:(Pat (',' Pat)* ','?)? ')'
-
-TuplePat =
-   '(' fields:(Pat (',' Pat)* ','?)? ')'
-
-ParenPat =
-  '(' Pat ')'
-
-SlicePat =
-  '[' (Pat (',' Pat)* ','?)? ']'
-
-PathPat =
-  Path
-
-OrPat =
-  (Pat ('|' Pat)* '|'?)
-
-BoxPat =
-  'box' Pat
-
-RestPat =
-  Attr* '..'
-
-MacroPat =
-  MacroCall
-
-ConstBlockPat =
-  'const' BlockExpr
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index bf4f9d6d18..19edead30a 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -302,16 +302,33 @@ impl ast::UseTree {
 
     /// Splits off the given prefix, making it the path component of the use tree,
     /// appending the rest of the path to all UseTreeList items.
+    ///
+    /// # Examples
+    ///
+    /// `prefix$0::suffix` -> `prefix::{suffix}`
+    ///
+    /// `prefix$0` -> `prefix::{self}`
+    ///
+    /// `prefix$0::*` -> `prefix::{*}`
     pub fn split_prefix(&self, prefix: &ast::Path) {
         debug_assert_eq!(self.path(), Some(prefix.top_path()));
         let path = self.path().unwrap();
         if &path == prefix && self.use_tree_list().is_none() {
-            let self_suffix = make::path_unqualified(make::path_segment_self()).clone_for_update();
-            ted::replace(path.syntax(), self_suffix.syntax());
+            if self.star_token().is_some() {
+                // path$0::* -> *
+                self.coloncolon_token().map(ted::remove);
+                ted::remove(prefix.syntax());
+            } else {
+                // path$0 -> self
+                let self_suffix =
+                    make::path_unqualified(make::path_segment_self()).clone_for_update();
+                ted::replace(path.syntax(), self_suffix.syntax());
+            }
         } else if split_path_prefix(prefix).is_none() {
             return;
         }
-
+        // At this point, prefix path is detached; _self_ use tree has suffix path.
+        // Next, transform 'suffix' use tree into 'prefix::{suffix}'
         let subtree = self.clone_subtree().clone_for_update();
         ted::remove_all_iter(self.syntax().children_with_tokens());
         ted::insert(Position::first_child_of(self.syntax()), prefix.syntax());
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 516d1caccc..3091bdcbf0 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp_ext.rs hash: a61de7db4504a4d1
+lsp_ext.rs hash: 854109e98d02a780
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -494,17 +494,6 @@ Primarily for debugging, but very useful for all people working on rust-analyzer
 Returns a textual representation of the HIR of the function containing the cursor.
 For debugging or when working on rust-analyzer itself.
 
-## View File Text
-
-**Method:** `rust-analyzer/viewFileText`
-
-**Request:** `TextDocumentIdentifier`
-
-**Response:** `string`
-
-Returns the text of a file as seen by the server.
-This is for debugging file sync problems.
-
 ## View ItemTree
 
 **Method:** `rust-analyzer/viewItemTree`
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 27d5d96159..ba28f68029 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -310,7 +310,7 @@ nvim_lsp.rust_analyzer.setup({
         ["rust-analyzer"] = {
             assist = {
                 importGranularity = "module",
-                importPrefix = "self",
+                importPrefix = "by_self",
             },
             cargo = {
                 loadOutDirsFromCheck = true
diff --git a/editors/code/README.md b/editors/code/README.md
index 46c6f6f2aa..b9d2891795 100644
--- a/editors/code/README.md
+++ b/editors/code/README.md
@@ -4,6 +4,20 @@ Provides support for rust-analyzer: novel LSP server for the Rust programming la
 
 **Note** the extension may cause conflicts with the official Rust extension. It is recommended to disable the Rust extension when using the rust-analyzer extension.
 
+## Sponsor
+
+Work on rust-analyzer is sponsored by
+
+[<img src="https://user-images.githubusercontent.com/1711539/58105231-cf306900-7bee-11e9-83d8-9f1102e59d29.png" alt="Ferrous Systems" width="300">](https://ferrous-systems.com/)
+
+- [Mozilla](https://www.mozilla.org/en-US/)
+- [Embark Studios](https://embark-studios.com/)
+
+If you want to sponsor:
+
+- [OpenCollective](https://opencollective.com/rust-analyzer/)
+- [Github Sponsors](https://github.com/sponsors/rust-analyzer)
+
 ## Features
 
 - [code completion], [imports insertion]
diff --git a/editors/code/package.json b/editors/code/package.json
index 7df00d2ef2..c55ef6f0f7 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -104,11 +104,6 @@
                 "title": "View Hir",
                 "category": "Rust Analyzer"
             },
-            {
-                "command": "rust-analyzer.viewFileText",
-                "title": "View File Text (as seen by the server)",
-                "category": "Rust Analyzer"
-            },
             {
                 "command": "rust-analyzer.viewItemTree",
                 "title": "Debug ItemTree",
@@ -1413,10 +1408,6 @@
                     "command": "rust-analyzer.viewHir",
                     "when": "inRustProject"
                 },
-                {
-                    "command": "rust-analyzer.viewFileText",
-                    "when": "inRustProject"
-                },
                 {
                     "command": "rust-analyzer.expandMacro",
                     "when": "inRustProject"
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 2802668be3..fe006a63e2 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -432,54 +432,6 @@ export function viewHir(ctx: Ctx): Cmd {
     };
 }
 
-export function viewFileText(ctx: Ctx): Cmd {
-    const tdcp = new class implements vscode.TextDocumentContentProvider {
-        readonly uri = vscode.Uri.parse('rust-analyzer://viewFileText/file.rs');
-        readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
-        constructor() {
-            vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
-            vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
-        }
-
-        private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
-            if (isRustDocument(event.document)) {
-                // We need to order this after language server updates, but there's no API for that.
-                // Hence, good old sleep().
-                void sleep(10).then(() => this.eventEmitter.fire(this.uri));
-            }
-        }
-        private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
-            if (editor && isRustEditor(editor)) {
-                this.eventEmitter.fire(this.uri);
-            }
-        }
-
-        provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
-            const rustEditor = ctx.activeRustEditor;
-            const client = ctx.client;
-            if (!rustEditor || !client) return '';
-
-            const params = client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document);
-            return client.sendRequest(ra.viewFileText, params, ct);
-        }
-
-        get onDidChange(): vscode.Event<vscode.Uri> {
-            return this.eventEmitter.event;
-        }
-    };
-
-    ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp));
-
-    return async () => {
-        const document = await vscode.workspace.openTextDocument(tdcp.uri);
-        tdcp.eventEmitter.fire(tdcp.uri);
-        void await vscode.window.showTextDocument(document, {
-            viewColumn: vscode.ViewColumn.Two,
-            preserveFocus: true
-        });
-    };
-}
-
 export function viewItemTree(ctx: Ctx): Cmd {
     const tdcp = new class implements vscode.TextDocumentContentProvider {
         readonly uri = vscode.Uri.parse('rust-analyzer://viewItemTree/itemtree.rs');
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 0ae5e93a73..9493a03481 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -36,8 +36,6 @@ export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("ru
 
 export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir");
 
-export const viewFileText = new lc.RequestType<lc.TextDocumentIdentifier, string, void>("rust-analyzer/viewFileText");
-
 export interface ViewItemTreeParams {
     textDocument: lc.TextDocumentIdentifier;
 }
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 36a095bdd3..06e5c1185d 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -114,7 +114,6 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
     ctx.registerCommand('parentModule', commands.parentModule);
     ctx.registerCommand('syntaxTree', commands.syntaxTree);
     ctx.registerCommand('viewHir', commands.viewHir);
-    ctx.registerCommand('viewFileText', commands.viewFileText);
     ctx.registerCommand('viewItemTree', commands.viewItemTree);
     ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph);
     ctx.registerCommand('viewFullCrateGraph', commands.viewFullCrateGraph);


Test patch:
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index d2f13e4351..18523d2db5 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -8,7 +8,6 @@ mod method_resolution;
 mod macros;
 mod display_source_code;
 mod incremental;
-mod diagnostics;
 
 use std::{collections::HashMap, env, sync::Arc};
 
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 268faf8cb3..c0dddb608e 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -2,10 +2,12 @@ use super::{check, check_no_mismatches, check_types};
 
 #[test]
 fn block_expr_type_mismatch() {
+    // FIXME fix double type mismatch
     check(
         r"
 fn test() {
     let a: i32 = { 1i64 };
+              // ^^^^^^^^ expected i32, got i64
                 // ^^^^ expected i32, got i64
 }
         ",
diff --git a/crates/hir_ty/src/tests/diagnostics.rs b/crates/hir_ty/src/tests/diagnostics.rs
deleted file mode 100644
index f00fa97294..0000000000
--- a/crates/hir_ty/src/tests/diagnostics.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use super::check;
-
-#[test]
-fn function_return_type_mismatch_1() {
-    check(
-        r#"
-fn test() -> &'static str {
-    5
-  //^ expected &str, got i32
-}
-"#,
-    );
-}
-
-#[test]
-fn function_return_type_mismatch_2() {
-    check(
-        r#"
-fn test(x: bool) -> &'static str {
-    if x {
-        return 1;
-             //^ expected &str, got i32
-    }
-    "ok"
-}
-"#,
-    );
-}
-
-#[test]
-fn function_return_type_mismatch_3() {
-    check(
-        r#"
-fn test(x: bool) -> &'static str {
-    if x {
-        return "ok";
-    }
-    1
-  //^ expected &str, got i32
-}
-"#,
-    );
-}
-
-#[test]
-fn function_return_type_mismatch_4() {
-    check(
-        r#"
-fn test(x: bool) -> &'static str {
-    if x {
-        "ok"
-    } else {
-        1
-      //^ expected &str, got i32
-    }
-}
-"#,
-    );
-}
-
-#[test]
-fn function_return_type_mismatch_5() {
-    check(
-        r#"
-fn test(x: bool) -> &'static str {
-    if x {
-        1
-      //^ expected &str, got i32
-    } else {
-        "ok"
-    }
-}
-"#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/never_type.rs b/crates/hir_ty/src/tests/never_type.rs
index fbdc8209f8..8be2b8ec10 100644
--- a/crates/hir_ty/src/tests/never_type.rs
+++ b/crates/hir_ty/src/tests/never_type.rs
@@ -1,6 +1,6 @@
 use expect_test::expect;
 
-use super::{check_infer_with_mismatches, check_no_mismatches, check_types};
+use super::{check_infer_with_mismatches, check_types};
 
 #[test]
 fn infer_never1() {
@@ -314,10 +314,11 @@ fn diverging_expression_2() {
         expect![[r#"
             11..84 '{     ..." }; }': ()
             54..55 'x': u32
-            63..81 '{ loop...foo" }': u32
+            63..81 '{ loop...foo" }': &str
             65..72 'loop {}': !
             70..72 '{}': ()
             74..79 '"foo"': &str
+            63..81: expected u32, got &str
             74..79: expected u32, got &str
         "#]],
     );
@@ -349,30 +350,31 @@ fn diverging_expression_3_break() {
             let x: u32 = { while true { return; }; };
         }
         ",
-        expect![[r#"
+        expect![[r"
             11..85 '{     ...} }; }': ()
             54..55 'x': u32
-            63..82 '{ loop...k; } }': u32
+            63..82 '{ loop...k; } }': ()
             65..80 'loop { break; }': ()
             70..80 '{ break; }': ()
             72..77 'break': !
+            63..82: expected u32, got ()
             65..80: expected u32, got ()
             97..343 '{     ...; }; }': ()
             140..141 'x': u32
-            149..175 '{ for ...; }; }': u32
+            149..175 '{ for ...; }; }': ()
             151..172 'for a ...eak; }': ()
             155..156 'a': {unknown}
             160..161 'b': {unknown}
             162..172 '{ break; }': ()
             164..169 'break': !
             226..227 'x': u32
-            235..253 '{ for ... {}; }': u32
+            235..253 '{ for ... {}; }': ()
             237..250 'for a in b {}': ()
             241..242 'a': {unknown}
             246..247 'b': {unknown}
             248..250 '{}': ()
             304..305 'x': u32
-            313..340 '{ for ...; }; }': u32
+            313..340 '{ for ...; }; }': ()
             315..337 'for a ...urn; }': ()
             319..320 'a': {unknown}
             324..325 'b': {unknown}
@@ -383,18 +385,18 @@ fn diverging_expression_3_break() {
             313..340: expected u32, got ()
             355..654 '{     ...; }; }': ()
             398..399 'x': u32
-            407..433 '{ whil...; }; }': u32
+            407..433 '{ whil...; }; }': ()
             409..430 'while ...eak; }': ()
             415..419 'true': bool
             420..430 '{ break; }': ()
             422..427 'break': !
             537..538 'x': u32
-            546..564 '{ whil... {}; }': u32
+            546..564 '{ whil... {}; }': ()
             548..561 'while true {}': ()
             554..558 'true': bool
             559..561 '{}': ()
             615..616 'x': u32
-            624..651 '{ whil...; }; }': u32
+            624..651 '{ whil...; }; }': ()
             626..648 'while ...urn; }': ()
             632..636 'true': bool
             637..648 '{ return; }': ()
@@ -402,7 +404,7 @@ fn diverging_expression_3_break() {
             407..433: expected u32, got ()
             546..564: expected u32, got ()
             624..651: expected u32, got ()
-        "#]],
+        "]],
     );
 }
 
@@ -436,50 +438,8 @@ fn let_else_must_diverge() {
             17..18 '1': i32
             17..18 '1': i32
             21..22 '2': i32
-            28..30 '{}': !
+            28..30 '{}': ()
             28..30: expected !, got ()
         "#]],
     );
 }
-
-#[test]
-fn issue_11837() {
-    check_no_mismatches(
-        r#"
-//- minicore: result
-enum MyErr {
-    Err1,
-    Err2,
-}
-
-fn example_ng() {
-    let value: Result<i32, MyErr> = Ok(3);
-
-    loop {
-        let ret = match value {
-            Ok(value) => value,
-            Err(ref err) => {
-                match err {
-                    MyErr::Err1 => break,
-                    MyErr::Err2 => continue,
-                };
-            }
-        };
-    }
-}
-"#,
-    );
-}
-
-#[test]
-fn issue_11814() {
-    check_no_mismatches(
-        r#"
-fn example() -> bool {
-    match 1 {
-        _ => return true,
-    };
-}
-"#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 2809b1e912..7a7470fd35 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -367,7 +367,7 @@ fn bug_1030() {
         }
         "#,
         expect![[r#"
-            143..145 '{}': HashSet<T, H>
+            143..145 '{}': ()
             168..197 '{     ...t(); }': ()
             174..192 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<{unknown}, FxHasher>
             174..194 'FxHash...ault()': HashSet<{unknown}, FxHasher>
@@ -831,7 +831,7 @@ fn issue_4966() {
         "#,
         expect![[r#"
             225..229 'iter': T
-            244..246 '{}': Vec<A>
+            244..246 '{}': ()
             258..402 '{     ...r(); }': ()
             268..273 'inner': Map<|&f64| -> f64>
             276..300 'Map { ... 0.0 }': Map<|&f64| -> f64>
@@ -914,7 +914,7 @@ fn flush(&self) {
 "#,
         expect![[r#"
             123..127 'self': &Mutex<T>
-            150..152 '{}': MutexGuard<T>
+            150..152 '{}': ()
             234..238 'self': &{unknown}
             240..290 '{     ...()); }': ()
             250..251 'w': &Mutex<BufWriter>
@@ -1039,18 +1039,18 @@ fn cfg_tail() {
         }
         "#,
         expect![[r#"
-            14..53 '{     ...)] 9 }': ()
-            20..31 '{ "first" }': ()
+            14..53 '{     ...)] 9 }': &str
+            20..31 '{ "first" }': &str
             22..29 '"first"': &str
-            72..190 '{     ...] 13 }': ()
+            72..190 '{     ...] 13 }': &str
             78..88 '{ "fake" }': &str
             80..86 '"fake"': &str
             93..103 '{ "fake" }': &str
             95..101 '"fake"': &str
-            108..120 '{ "second" }': ()
+            108..120 '{ "second" }': &str
             110..118 '"second"': &str
-            210..273 '{     ... 15; }': ()
-            216..227 '{ "third" }': ()
+            210..273 '{     ... 15; }': &str
+            216..227 '{ "third" }': &str
             218..225 '"third"': &str
             293..357 '{     ...] 15 }': ()
             299..311 '{ "fourth" }': &str
@@ -1477,23 +1477,3 @@ fn regression_11688_2() {
         "#,
     );
 }
-
-#[test]
-fn regression_11688_3() {
-    check_types(
-        r#"
-        //- minicore: iterator
-        struct Ar<T, const N: u8>(T);
-        fn f<const LEN: usize, T, const BASE: u8>(
-            num_zeros: usize,
-        ) -> dyn Iterator<Item = [Ar<T, BASE>; LEN]> {
-            loop {}
-        }
-        fn dynamic_programming() {
-            for board in f::<9, u8, 7>(1) {
-              //^^^^^ [Ar<u8, 7>; 9]
-            }
-        }
-        "#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index baed34ce23..675f9038f0 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -996,9 +996,9 @@ fn main(foo: Foo) {
             50..106 'if tru...     }': ()
             53..57 'true': bool
             58..66 '{      }': ()
-            72..106 'if fal...     }': ()
+            72..106 'if fal...     }': i32
             75..80 'false': bool
-            81..106 '{     ...     }': ()
+            81..106 '{     ...     }': i32
             91..94 'foo': Foo
             91..100 'foo.field': i32
         "#]],
@@ -1094,10 +1094,10 @@ fn infer_inherent_method() {
         expect![[r#"
             31..35 'self': A
             37..38 'x': u32
-            52..54 '{}': i32
+            52..54 '{}': ()
             106..110 'self': &A
             112..113 'x': u64
-            127..129 '{}': i64
+            127..129 '{}': ()
             147..148 'a': A
             153..201 '{     ...(1); }': ()
             159..160 'a': A
@@ -1129,7 +1129,7 @@ fn infer_inherent_method_str() {
         "#,
         expect![[r#"
             39..43 'self': &str
-            52..54 '{}': i32
+            52..54 '{}': ()
             68..88 '{     ...o(); }': ()
             74..79 '"foo"': &str
             74..85 '"foo".foo()': i32
@@ -1419,7 +1419,7 @@ fn infer_impl_generics_basic() {
             206..210 'self': A<X, Y>
             206..212 'self.y': Y
             214..215 't': T
-            244..341 '{     ...(1); }': i128
+            244..341 '{     ...(1); }': ()
             254..255 'a': A<u64, i64>
             258..280 'A { x:...1i64 }': A<u64, i64>
             265..269 '1u64': u64
@@ -1456,7 +1456,7 @@ fn infer_impl_generics_with_autoderef() {
         "#,
         expect![[r#"
             77..81 'self': &Option<T>
-            97..99 '{}': Option<&T>
+            97..99 '{}': ()
             110..111 'o': Option<u32>
             126..164 '{     ...f(); }': ()
             132..145 '(&o).as_ref()': Option<&u32>
@@ -1852,7 +1852,7 @@ fn closure_return() {
         }
         "#,
         expect![[r#"
-            16..58 '{     ...; }; }': u32
+            16..58 '{     ...; }; }': ()
             26..27 'x': || -> usize
             30..55 '|| -> ...n 1; }': || -> usize
             42..55 '{ return 1; }': usize
@@ -1871,7 +1871,7 @@ fn closure_return_unit() {
         }
         "#,
         expect![[r#"
-            16..47 '{     ...; }; }': u32
+            16..47 '{     ...; }; }': ()
             26..27 'x': || -> ()
             30..44 '|| { return; }': || -> ()
             33..44 '{ return; }': ()
@@ -1889,7 +1889,7 @@ fn closure_return_inferred() {
         }
         "#,
         expect![[r#"
-            16..46 '{     ..." }; }': u32
+            16..46 '{     ..." }; }': ()
             26..27 'x': || -> &str
             30..43 '|| { "test" }': || -> &str
             33..43 '{ "test" }': &str
@@ -2556,20 +2556,6 @@ fn f() {
     )
 }
 
-#[test]
-fn infer_missing_type() {
-    check_types(
-        r#"
-struct S;
-
-fn f() {
-    let s: = S;
-      //^ S
-}
-    "#,
-    );
-}
-
 #[test]
 fn infer_type_alias_variant() {
     check_infer(
@@ -2642,11 +2628,11 @@ fn main() {
         expect![[r#"
             104..108 'self': &Box<T>
             188..192 'self': &Box<Foo<T>>
-            218..220 '{}': &T
+            218..220 '{}': ()
             242..246 'self': &Box<Foo<T>>
-            275..277 '{}': &Foo<T>
+            275..277 '{}': ()
             297..301 'self': Box<Foo<T>>
-            322..324 '{}': Foo<T>
+            322..324 '{}': ()
             338..559 '{     ...r(); }': ()
             348..353 'boxed': Box<Foo<i32>>
             356..359 'Box': Box<Foo<i32>>(Foo<i32>) -> Box<Foo<i32>>
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 5e58d5ad83..a82b8cb466 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -1280,7 +1280,7 @@ fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
         expect![[r#"
             29..33 'self': &Self
             54..58 'self': &Self
-            97..99 '{}': dyn Trait<u64>
+            97..99 '{}': ()
             109..110 'x': dyn Trait<u64>
             128..129 'y': &dyn Trait<u64>
             148..265 '{     ...2(); }': ()
@@ -1361,10 +1361,10 @@ fn test(x: Trait, y: &Trait) -> u64 {
 }"#,
         expect![[r#"
             26..30 'self': &Self
-            60..62 '{}': dyn Trait
+            60..62 '{}': ()
             72..73 'x': dyn Trait
             82..83 'y': &dyn Trait
-            100..175 '{     ...o(); }': u64
+            100..175 '{     ...o(); }': ()
             106..107 'x': dyn Trait
             113..114 'y': &dyn Trait
             124..125 'z': dyn Trait
@@ -1449,9 +1449,9 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
 }"#,
         expect![[r#"
             49..50 't': T
-            77..79 '{}': Trait::Type<T>
+            77..79 '{}': ()
             111..112 't': T
-            122..124 '{}': U
+            122..124 '{}': ()
             154..155 't': T
             165..168 '{t}': T
             166..167 't': T
@@ -1575,7 +1575,7 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
 }"#,
         expect![[r#"
             49..53 'self': &Self
-            62..64 '{}': u32
+            62..64 '{}': ()
             181..182 'x': T
             187..188 'y': U
             193..222 '{     ...o(); }': ()
@@ -1604,7 +1604,7 @@ fn test(x: &impl Trait1) {
 }"#,
         expect![[r#"
             49..53 'self': &Self
-            62..64 '{}': u32
+            62..64 '{}': ()
             115..116 'x': &impl Trait1
             132..148 '{     ...o(); }': ()
             138..139 'x': &impl Trait1
@@ -1653,7 +1653,7 @@ fn test() {
 }"#,
         expect![[r#"
             102..103 't': T
-            113..115 '{}': U
+            113..115 '{}': ()
             145..146 't': T
             156..159 '{t}': T
             157..158 't': T
@@ -1786,9 +1786,9 @@ fn test() {
 }"#,
         expect![[r#"
             36..40 'self': &Foo
-            51..53 '{}': usize
+            51..53 '{}': ()
             131..132 'f': F
-            151..153 '{}': Lazy<T, F>
+            151..153 '{}': ()
             251..497 '{     ...o(); }': ()
             261..266 'lazy1': Lazy<Foo, || -> Foo>
             283..292 'Lazy::new': fn new<Foo, || -> Foo>(|| -> Foo) -> Lazy<Foo, || -> Foo>
@@ -1807,7 +1807,7 @@ fn test() {
             478..480 'r2': usize
             483..488 'lazy2': Lazy<Foo, fn() -> Foo>
             483..494 'lazy2.foo()': usize
-            357..359 '{}': Foo
+            357..359 '{}': ()
         "#]],
     );
 }
@@ -2738,7 +2738,7 @@ fn test() {
         expect![[r#"
             9..11 '{}': ()
             28..29 'T': {unknown}
-            36..38 '{}': T
+            36..38 '{}': ()
             36..38: expected T, got ()
             113..117 'self': &Self
             169..249 '{     ...t(); }': ()
@@ -3167,7 +3167,7 @@ fn f() {
 }"#,
         expect![[r#"
             17..73 '{     ...   } }': ()
-            39..71 '{     ...     }': S
+            39..71 '{     ...     }': ()
             53..54 's': S
             57..62 'inner': fn inner() -> S
             57..64 'inner()': S
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 36e9ec6333..d9126421cd 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -110,11 +110,6 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span>
-    <span class="comment documentation">/// ~~~rust,no_run</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// code block with tilde.</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
-    <span class="comment documentation">/// ~~~</span>
-    <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="comment injected">// functions</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index af41796e21..87b9da46e2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -43,5 +43,5 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
 <pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span>
-<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root library">alloc</span> <span class="keyword">as</span> <span class="module crate_root declaration library">abc</span><span class="semicolon">;</span>
+<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root default_library declaration library">abc</span><span class="semicolon">;</span>
 </code></pre>
\ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index fdfe347a32..2cd4fa809a 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -644,11 +644,6 @@ impl Foo {
     /// let foobar = Foo::new().bar();
     /// ```
     ///
-    /// ~~~rust,no_run
-    /// // code block with tilde.
-    /// let foobar = Foo::new().bar();
-    /// ~~~
-    ///
     /// ```
     /// // functions
     /// fn foo<T, const X: usize>(arg: i32) {
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs
index 470fc37ca7..f505e82d22 100644
--- a/crates/ide_completion/src/tests.rs
+++ b/crates/ide_completion/src/tests.rs
@@ -35,7 +35,7 @@ use stdx::{format_to, trim_indent};
 use syntax::{AstNode, NodeOrToken, SyntaxElement};
 use test_utils::assert_eq_text;
 
-use crate::{resolve_completion_edits, CompletionConfig, CompletionItem, CompletionItemKind};
+use crate::{CompletionConfig, CompletionItem, CompletionItemKind};
 
 /// Lots of basic item definitions
 const BASE_ITEMS_FIXTURE: &str = r#"
@@ -178,24 +178,15 @@ pub(crate) fn check_edit_with_config(
     let mut actual = db.file_text(position.file_id).to_string();
 
     let mut combined_edit = completion.text_edit().to_owned();
-
-    resolve_completion_edits(
-        &db,
-        &config,
-        position,
-        completion.imports_to_add().iter().filter_map(|import_edit| {
-            let import_path = &import_edit.import_path;
-            let import_name = import_path.segments().last()?;
-            Some((import_path.to_string(), import_name.to_string()))
-        }),
-    )
-    .into_iter()
-    .flatten()
-    .for_each(|text_edit| {
-        combined_edit.union(text_edit).expect(
-            "Failed to apply completion resolve changes: change ranges overlap, but should not",
-        )
-    });
+    completion
+        .imports_to_add()
+        .iter()
+        .filter_map(|edit| edit.to_text_edit(config.insert_use))
+        .for_each(|text_edit| {
+            combined_edit.union(text_edit).expect(
+                "Failed to apply completion resolve changes: change ranges overlap, but should not",
+            )
+        });
 
     combined_edit.apply(&mut actual);
     assert_eq_text!(&ra_fixture_after, &actual)
diff --git a/crates/ide_db/src/imports/insert_use/tests.rs b/crates/ide_db/src/imports/insert_use/tests.rs
index 4219358a07..e4b9651e5e 100644
--- a/crates/ide_db/src/imports/insert_use/tests.rs
+++ b/crates/ide_db/src/imports/insert_use/tests.rs
@@ -656,7 +656,7 @@ fn merge_mod_into_glob() {
     check_with_config(
         "token::TokenKind",
         r"use token::TokenKind::*;",
-        r"use token::TokenKind::{self, *};",
+        r"use token::TokenKind::{*, self};",
         &InsertUseConfig {
             granularity: ImportGranularity::Crate,
             enforce_granularity: true,
@@ -670,11 +670,10 @@ fn merge_mod_into_glob() {
 
 #[test]
 fn merge_self_glob() {
-    cov_mark::check!(merge_self_glob);
     check_with_config(
         "self",
         r"use self::*;",
-        r"use self::{self, *};",
+        r"use self::{*, self};",
         &InsertUseConfig {
             granularity: ImportGranularity::Crate,
             enforce_granularity: true,
@@ -693,7 +692,7 @@ fn merge_glob() {
         r"
 use syntax::{SyntaxKind::*};",
         r"
-use syntax::{SyntaxKind::{self, *}};",
+use syntax::{SyntaxKind::{*, self}};",
     )
 }
 
@@ -702,7 +701,7 @@ fn merge_glob_nested() {
     check_crate(
         "foo::bar::quux::Fez",
         r"use foo::bar::{Baz, quux::*};",
-        r"use foo::bar::{Baz, quux::{self::*, Fez}};",
+        r"use foo::bar::{Baz, quux::{*, Fez}};",
     )
 }
 
diff --git a/crates/ide_diagnostics/src/tests.rs b/crates/ide_diagnostics/src/tests.rs
index 7cd79c7cee..7d06e9d36f 100644
--- a/crates/ide_diagnostics/src/tests.rs
+++ b/crates/ide_diagnostics/src/tests.rs
@@ -54,13 +54,13 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
         actual
     };
 
+    assert_eq_text!(&after, &actual);
     assert!(
         fix.target.contains_inclusive(file_position.offset),
         "diagnostic fix range {:?} does not touch cursor position {:?}",
         fix.target,
         file_position.offset
     );
-    assert_eq_text!(&after, &actual);
 }
 
 /// Checks that there's a diagnostic *without* fix at `$0`.
diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs
index 26a043dc98..1862c3bcc2 100644
--- a/crates/ide_ssr/src/tests.rs
+++ b/crates/ide_ssr/src/tests.rs
@@ -94,7 +94,7 @@ fn assert_ssr_transform(rule: &str, input: &str, expected: Expect) {
 
 fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) {
     let (db, position, selections) = single_file(input);
-    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
+    let mut match_finder = MatchFinder::in_context(&db, position, selections);
     for rule in rules {
         let rule: SsrRule = rule.parse().unwrap();
         match_finder.add_rule(rule).unwrap();
@@ -124,7 +124,7 @@ fn print_match_debug_info(match_finder: &MatchFinder, file_id: FileId, snippet:
 
 fn assert_matches(pattern: &str, code: &str, expected: &[&str]) {
     let (db, position, selections) = single_file(code);
-    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
+    let mut match_finder = MatchFinder::in_context(&db, position, selections);
     match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
     let matched_strings: Vec<String> =
         match_finder.matches().flattened().matches.iter().map(|m| m.matched_text()).collect();
@@ -136,7 +136,7 @@ fn assert_matches(pattern: &str, code: &str, expected: &[&str]) {
 
 fn assert_no_match(pattern: &str, code: &str) {
     let (db, position, selections) = single_file(code);
-    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
+    let mut match_finder = MatchFinder::in_context(&db, position, selections);
     match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
     let matches = match_finder.matches().flattened().matches;
     if !matches.is_empty() {
@@ -147,7 +147,7 @@ fn assert_no_match(pattern: &str, code: &str) {
 
 fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expected_reason: &str) {
     let (db, position, selections) = single_file(code);
-    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
+    let mut match_finder = MatchFinder::in_context(&db, position, selections);
     match_finder.add_search_pattern(pattern.parse().unwrap()).unwrap();
     let mut reasons = Vec::new();
     for d in match_finder.debug_where_text_equal(position.file_id, snippet) {
diff --git a/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast b/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast
index 338d53995a..c86cf18bbe 100644
--- a/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast
+++ b/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast
@@ -34,18 +34,6 @@ SOURCE_FILE
           WHITESPACE " "
           PARAM
             DOT3 "..."
-          COMMA ","
-          WHITESPACE " "
-          PARAM
-            WILDCARD_PAT
-              UNDERSCORE "_"
-            COLON ":"
-            WHITESPACE " "
-            PATH_TYPE
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "u8"
           R_PAREN ")"
         WHITESPACE " "
         RET_TYPE
diff --git a/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs b/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs
index 533096cd5b..c59addaf42 100644
--- a/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs
+++ b/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs
@@ -1,1 +1,1 @@
-extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; }
+extern "C" { fn printf(format: *const i8, ...) -> i32; }
diff --git a/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast b/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast
index ce425a1afd..7511877aa8 100644
--- a/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast
+++ b/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast
@@ -6,10 +6,6 @@ SOURCE_FILE
       IDENT "foo"
     PARAM_LIST
       L_PAREN "("
-      PARAM
-        DOT3 "..."
-      COMMA ","
-      WHITESPACE " "
       PARAM
         TUPLE_PAT
           L_PAREN "("
diff --git a/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs b/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs
index 7b4c626582..7b277c16b1 100644
--- a/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs
+++ b/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs
@@ -1,1 +1,1 @@
-fn foo(..., (x, y): (i32, i32)) {}
+fn foo((x, y): (i32, i32)) {}
diff --git a/crates/project_model/src/tests.rs b/crates/project_model/src/tests.rs
index 351e820ada..ca347d71a2 100644
--- a/crates/project_model/src/tests.rs
+++ b/crates/project_model/src/tests.rs
@@ -1261,9 +1261,7 @@ fn rust_project_hello_world_project_model() {
                             },
                         ],
                         proc_macro: [],
-                        origin: Lang(
-                            Alloc,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1293,9 +1291,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Other,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1325,9 +1321,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Other,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1367,9 +1361,7 @@ fn rust_project_hello_world_project_model() {
                             },
                         ],
                         proc_macro: [],
-                        origin: Lang(
-                            ProcMacro,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1399,9 +1391,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Core,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1500,9 +1490,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Other,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1532,9 +1520,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Other,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1564,9 +1550,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Other,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1596,9 +1580,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Test,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1710,9 +1692,7 @@ fn rust_project_hello_world_project_model() {
                             },
                         ],
                         proc_macro: [],
-                        origin: Lang(
-                            Std,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1742,9 +1722,7 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang(
-                            Other,
-                        ),
+                        origin: Lang,
                         is_proc_macro: false,
                     },
                 },
diff --git a/crates/syntax/src/tests/sourcegen_ast.rs b/crates/syntax/src/tests/sourcegen_ast.rs
index c2ed3eab0a..cb38abfe89 100644
--- a/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/crates/syntax/src/tests/sourcegen_ast.rs
@@ -11,7 +11,7 @@ use std::{
 use itertools::Itertools;
 use proc_macro2::{Punct, Spacing};
 use quote::{format_ident, quote};
-use ungrammar::{Grammar, Rule};
+use ungrammar::{rust_grammar, Grammar, Rule};
 
 use crate::tests::ast_src::{
     AstEnumSrc, AstNodeSrc, AstSrc, Cardinality, Field, KindsSrc, KINDS_SRC,
@@ -24,8 +24,7 @@ fn sourcegen_ast() {
         sourcegen::project_root().join("crates/parser/src/syntax_kind/generated.rs");
     sourcegen::ensure_file_contents(syntax_kinds_file.as_path(), &syntax_kinds);
 
-    let grammar =
-        include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/rust.ungram")).parse().unwrap();
+    let grammar = rust_grammar();
     let ast = lower(&grammar);
 
     let ast_tokens = generate_tokens(&ast);