Repository: rust-analyzer/rust-analyzer
Pull request #11827 (2022-03-26 19:09:14)

internal: Enforce Invariant that Resolver always contains a ModuleScope


Patch:
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index d1e2d74a98..daa0e3f699 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},
+    input::{CrateName, CrateOrigin, LangCrateOrigin},
     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,
-                Default::default(),
+                CrateOrigin::CratesIo { repo: None },
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -233,7 +233,7 @@ impl ChangeFixture {
                 Env::default(),
                 Vec::new(),
                 false,
-                CrateOrigin::Lang,
+                CrateOrigin::Lang(LangCrateOrigin::Core),
             );
 
             for krate in all_crates {
@@ -270,7 +270,7 @@ impl ChangeFixture {
                 Env::default(),
                 proc_macro,
                 true,
-                CrateOrigin::Lang,
+                CrateOrigin::CratesIo { repo: None },
             );
 
             for krate in all_crates {
@@ -406,7 +406,11 @@ fn parse_crate(crate_str: String) -> (String, CrateOrigin, Option<String>) {
         };
         (a.to_owned(), origin, Some(version.to_string()))
     } else {
-        (crate_str, CrateOrigin::Unknown, None)
+        let crate_origin = match &*crate_str {
+            "std" => CrateOrigin::Lang(LangCrateOrigin::Std),
+            _ => CrateOrigin::CratesIo { repo: None },
+        };
+        (crate_str, crate_origin, None)
     }
 }
 
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index db3f85604b..43d7ccad49 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -117,21 +117,22 @@ impl ops::Deref for CrateName {
 }
 
 /// Origin of the crates. It is used in emitting monikers.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 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,
-    /// Crates that we don't know their origin.
-    // Ideally this enum should cover all cases, and then we remove this variant.
-    Unknown,
+    Lang(LangCrateOrigin),
 }
 
-impl Default for CrateOrigin {
-    fn default() -> Self {
-        Self::Unknown
-    }
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum LangCrateOrigin {
+    Alloc,
+    Core,
+    ProcMacro,
+    Std,
+    Test,
+    Other,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -585,6 +586,8 @@ impl fmt::Display for CyclicDependenciesError {
 
 #[cfg(test)]
 mod tests {
+    use crate::CrateOrigin;
+
     use super::{CfgOptions, CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId};
 
     #[test]
@@ -600,7 +603,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -612,7 +615,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -624,7 +627,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -650,7 +653,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -662,7 +665,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -685,7 +688,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -697,7 +700,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         let crate3 = graph.add_crate_root(
             FileId(3u32),
@@ -709,7 +712,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
@@ -732,7 +735,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         let crate2 = graph.add_crate_root(
             FileId(2u32),
@@ -744,7 +747,7 @@ mod tests {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         assert!(graph
             .add_dep(
diff --git a/crates/base_db/src/lib.rs b/crates/base_db/src/lib.rs
index d80660f7c9..2454698bb6 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, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroId,
-        ProcMacroKind, SourceRoot, SourceRootId,
+        Edition, Env, LangCrateOrigin, 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 c07c017c3d..8b99662685 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -148,6 +148,10 @@ 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
@@ -1741,10 +1745,8 @@ impl BuiltinType {
         BuiltinType { inner: hir_def::builtin_type::BuiltinType::Str }
     }
 
-    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 ty(self, db: &dyn HirDatabase) -> Type {
+        Type::new_for_crate(db.crate_graph().iter().next().unwrap(), TyBuilder::builtin(self.inner))
     }
 
     pub fn name(self) -> Name {
@@ -2222,7 +2224,7 @@ impl BuiltinAttr {
         Some(BuiltinAttr { krate: Some(krate.id), idx })
     }
 
-    pub(crate) fn builtin(name: &str) -> Option<Self> {
+    fn builtin(name: &str) -> Option<Self> {
         hir_def::builtin_attr::INERT_ATTRIBUTES
             .iter()
             .position(|tool| tool.name == name)
@@ -2261,7 +2263,7 @@ impl ToolModule {
         Some(ToolModule { krate: Some(krate.id), idx })
     }
 
-    pub(crate) fn builtin(name: &str) -> Option<Self> {
+    fn builtin(name: &str) -> Option<Self> {
         hir_def::builtin_attr::TOOL_MODULES
             .iter()
             .position(|&tool| tool == name)
@@ -2611,14 +2613,11 @@ pub struct Type {
 }
 
 impl Type {
-    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(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_inner(
         db: &dyn HirDatabase,
         krate: CrateId,
@@ -2631,6 +2630,10 @@ 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(
@@ -3031,10 +3034,7 @@ impl Type {
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
-        let krate = match scope.krate() {
-            Some(k) => k,
-            None => return,
-        };
+        let krate = scope.krate();
         let environment = scope.resolver().generic_def().map_or_else(
             || Arc::new(TraitEnvironment::empty(krate.id)),
             |d| db.trait_environment(d),
@@ -3091,10 +3091,7 @@ impl Type {
     ) {
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
-        let krate = match scope.krate() {
-            Some(k) => k,
-            None => return,
-        };
+        let krate = scope.krate();
         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 4afdde6494..8a700027a3 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -403,11 +403,15 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.to_module_def(file)
     }
 
-    pub fn scope(&self, node: &SyntaxNode) -> SemanticsScope<'db> {
+    pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> {
         self.imp.scope(node)
     }
 
-    pub fn scope_at_offset(&self, node: &SyntaxNode, offset: TextSize) -> SemanticsScope<'db> {
+    pub fn scope_at_offset(
+        &self,
+        node: &SyntaxNode,
+        offset: TextSize,
+    ) -> Option<SemanticsScope<'db>> {
         self.imp.scope_at_offset(node, offset)
     }
 
@@ -456,7 +460,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)
@@ -535,9 +539,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)
@@ -669,7 +673,10 @@ impl<'db> SemanticsImpl<'db> {
             Some(it) => it,
             None => return,
         };
-        let sa = self.analyze_no_infer(&parent);
+        let sa = match self.analyze_no_infer(&parent) {
+            Some(it) => it,
+            None => return,
+        };
         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();
@@ -903,70 +910,74 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
-        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)
+        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)
             .lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
-        Type::new_with_resolver(self.db, &scope.resolver, ty)
+        Some(Type::new_with_resolver(self.db, &analyze.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 (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
+        let source_analyzer = self.analyze(call.syntax())?;
+        let (func, subst) = source_analyzer.resolve_method_call(self.db, call)?;
         let ty = self.db.value_ty(func.into()).substitute(Interner, &subst);
-        let resolver = self.analyze(call.syntax()).resolver;
-        let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
+        let resolver = source_analyzer.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 = self.analyze(macro_call.syntax());
+        let sa = match self.analyze(macro_call.syntax()) {
+            Some(it) => it,
+            None => return false,
+        };
         let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
         sa.is_unsafe_macro_call(self.db, macro_call)
     }
@@ -981,11 +992,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);
@@ -997,22 +1008,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())
-            .record_literal_missing_fields(self.db, literal)
+            .and_then(|it| it.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())
-            .record_pattern_missing_fields(self.db, pattern)
+            .and_then(|it| it.record_pattern_missing_fields(self.db, pattern))
             .unwrap_or_default()
     }
 
@@ -1026,15 +1037,22 @@ impl<'db> SemanticsImpl<'db> {
         self.with_ctx(|ctx| ctx.file_to_def(file)).into_iter().map(Module::from)
     }
 
-    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(&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_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_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_for_def(&self, def: Trait) -> SemanticsScope<'db> {
@@ -1052,15 +1070,21 @@ impl<'db> SemanticsImpl<'db> {
         Some(res)
     }
 
-    fn analyze(&self, node: &SyntaxNode) -> SourceAnalyzer {
+    /// Returns none if the file of the node is not part of a crate.
+    fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
         self.analyze_impl(node, None, true)
     }
 
-    fn analyze_no_infer(&self, node: &SyntaxNode) -> SourceAnalyzer {
+    /// Returns none if the file of the node is not part of a crate.
+    fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
         self.analyze_impl(node, None, false)
     }
 
-    fn analyze_with_offset_no_infer(&self, node: &SyntaxNode, offset: TextSize) -> SourceAnalyzer {
+    fn analyze_with_offset_no_infer(
+        &self,
+        node: &SyntaxNode,
+        offset: TextSize,
+    ) -> Option<SourceAnalyzer> {
         self.analyze_impl(node, Some(offset), false)
     }
 
@@ -1069,22 +1093,22 @@ impl<'db> SemanticsImpl<'db> {
         node: &SyntaxNode,
         offset: Option<TextSize>,
         infer_body: bool,
-    ) -> SourceAnalyzer {
+    ) -> Option<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 SourceAnalyzer::new_for_resolver(Resolver::default(), node),
+            None => return None,
         };
 
         let resolver = match container {
             ChildContainer::DefWithBodyId(def) => {
-                return if infer_body {
+                return Some(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()),
@@ -1094,7 +1118,7 @@ impl<'db> SemanticsImpl<'db> {
             ChildContainer::TypeAliasId(it) => it.resolver(self.db.upcast()),
             ChildContainer::GenericDefId(it) => it.resolver(self.db.upcast()),
         };
-        SourceAnalyzer::new_for_resolver(resolver, node)
+        Some(SourceAnalyzer::new_for_resolver(resolver, node))
     }
 
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
@@ -1118,6 +1142,7 @@ 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(|| {
@@ -1319,12 +1344,12 @@ pub struct SemanticsScope<'a> {
 }
 
 impl<'a> SemanticsScope<'a> {
-    pub fn module(&self) -> Option<Module> {
-        Some(Module { id: self.resolver.module()? })
+    pub fn module(&self) -> Module {
+        Module { id: self.resolver.module() }
     }
 
-    pub fn krate(&self) -> Option<Crate> {
-        Some(Crate { id: self.resolver.krate()? })
+    pub fn krate(&self) -> Crate {
+        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 2b818b8eba..f918443427 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -169,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);
-        mk_ty(ty).zip(Some(coerced.and_then(mk_ty)))
+        Some((mk_ty(ty), coerced.map(mk_ty)))
     }
 
     pub(crate) fn type_of_pat(
@@ -185,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);
-        mk_ty(ty).zip(Some(coerced.and_then(mk_ty)))
+        Some((mk_ty(ty), coerced.map(mk_ty)))
     }
 
     pub(crate) fn type_of_self(
@@ -196,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();
-        Type::new_with_resolver(db, &self.resolver, ty)
+        Some(Type::new_with_resolver(db, &self.resolver, ty))
     }
 
     pub(crate) fn resolve_method_call(
@@ -244,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(
@@ -366,11 +366,8 @@ 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| {
-                        match self.resolver.krate() {
-                            Some(krate) => ToolModule::by_name(db, krate.into(), &name_ref.text()),
-                            None => ToolModule::builtin(&name_ref.text()),
-                        }
-                        .map(PathResolution::ToolModule)
+                        ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
+                            .map(PathResolution::ToolModule)
                     })
                 }
                 res => res,
@@ -380,9 +377,8 @@ 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| match self.resolver.krate() {
-                Some(krate) => BuiltinAttr::by_name(db, krate.into(), &name_ref.text()),
-                None => BuiltinAttr::builtin(&name_ref.text()),
+            let builtin = name_ref.as_ref().and_then(|name_ref| {
+                BuiltinAttr::by_name(db, self.resolver.krate().into(), &name_ref.text())
             });
             if let builtin @ Some(_) = builtin {
                 return builtin.map(PathResolution::BuiltinAttr);
@@ -392,11 +388,8 @@ 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| {
-                    match self.resolver.krate() {
-                        Some(krate) => ToolModule::by_name(db, krate.into(), &name_ref.text()),
-                        None => ToolModule::builtin(&name_ref.text()),
-                    }
-                    .map(PathResolution::ToolModule)
+                    ToolModule::by_name(db, self.resolver.krate().into(), &name_ref.text())
+                        .map(PathResolution::ToolModule)
                 }),
             };
         }
@@ -412,7 +405,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()?;
 
@@ -430,7 +423,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()?;
 
@@ -468,7 +461,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 ab99627d18..fe0100fb8c 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -25,12 +25,14 @@ use crate::{
     StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, VariantId,
 };
 
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
 pub struct Resolver {
     /// The stack of scopes, where the inner-most scope is the last item.
     ///
     /// When using, you generally want to process the scopes in reverse order,
     /// there's `scopes` *method* for that.
+    ///
+    /// Invariant: There exists at least one Scope::ModuleScope at the start of the vec.
     scopes: Vec<Scope>,
 }
 
@@ -135,10 +137,7 @@ impl Resolver {
         path: &ModPath,
         shadow: BuiltinShadowMode,
     ) -> PerNs {
-        let (item_map, module) = match self.module_scope() {
-            Some(it) => it,
-            None => return PerNs::none(),
-        };
+        let (item_map, module) = self.module_scope();
         let (module_res, segment_index) = item_map.resolve_path(db, module, path, shadow);
         if segment_index.is_some() {
             return PerNs::none();
@@ -155,7 +154,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) => {
@@ -235,10 +234,7 @@ impl Resolver {
     ) -> Option<Visibility> {
         match visibility {
             RawVisibility::Module(_) => {
-                let (item_map, module) = match self.module_scope() {
-                    Some(it) => it,
-                    None => return None,
-                };
+                let (item_map, module) = self.module_scope();
                 item_map.resolve_visibility(db, module, visibility)
             }
             RawVisibility::Public => Some(Visibility::Public),
@@ -336,7 +332,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()
     }
 
@@ -425,22 +421,22 @@ impl Resolver {
         traits
     }
 
-    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,
-        })
+    fn module_scope(&self) -> (&DefMap, LocalModuleId) {
+        self.scopes()
+            .find_map(|scope| match scope {
+                Scope::ModuleScope(m) => Some((&*m.def_map, m.module_id)),
+                _ => None,
+            })
+            .expect("module scope invariant violated")
     }
 
-    pub fn module(&self) -> Option<ModuleId> {
-        let (def_map, local_id) = self.module_scope()?;
-        Some(def_map.module_id(local_id))
+    pub fn module(&self) -> ModuleId {
+        let (def_map, local_id) = self.module_scope();
+        def_map.module_id(local_id)
     }
 
-    pub fn krate(&self) -> Option<CrateId> {
-        // FIXME: can this ever be `None`?
-        self.module_scope().map(|t| t.0.krate())
+    pub fn krate(&self) -> CrateId {
+        self.module_scope().0.krate()
     }
 
     pub fn where_predicates_in_scope(
@@ -749,8 +745,7 @@ impl HasResolver for ModuleId {
             def_map = parent.def_map(db);
             modules.push((def_map.clone(), parent.local_id));
         }
-        let mut resolver = Resolver::default();
-        resolver.scopes.reserve(modules.len());
+        let mut resolver = Resolver { scopes: Vec::with_capacity(modules.len()) };
         for (def_map, module) in modules.into_iter().rev() {
             resolver = resolver.push_module_scope(def_map, module);
         }
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 451245b5d2..6972db8495 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -420,9 +420,8 @@ pub(crate) fn associated_ty_data_query(
         .collect();
 
     if !ctx.unsized_types.borrow().contains(&self_ty) {
-        let sized_trait = resolver
-            .krate()
-            .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
+        let sized_trait = db
+            .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
             .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
         let sized_bound = sized_trait.into_iter().map(|sized_trait| {
             let trait_bound =
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 71e81b4348..70bb56e02f 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 01022f20bd..fc88e97d6a 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,
+    method_resolution::{self, VisibleFromModule},
     primitive::{self, UintTy},
     static_lifetime, to_chalk_trait_id,
     utils::{generics, Generics},
@@ -487,13 +487,8 @@ impl<'a> InferenceContext<'a> {
                         }
                         _ => return None,
                     };
-                    let module = self.resolver.module();
-                    let is_visible = module
-                        .map(|mod_id| {
-                            self.db.field_visibilities(field_id.parent)[field_id.local_id]
-                                .is_visible_from(self.db.upcast(), mod_id)
-                        })
-                        .unwrap_or(true);
+                    let is_visible = self.db.field_visibilities(field_id.parent)[field_id.local_id]
+                        .is_visible_from(self.db.upcast(), self.resolver.module());
                     if !is_visible {
                         // Write down the first field resolution even if it is not visible
                         // This aids IDE features for private fields like goto def and in
@@ -946,7 +941,7 @@ impl<'a> InferenceContext<'a> {
             self.db,
             self.trait_env.clone(),
             &traits_in_scope,
-            self.resolver.module().into(),
+            VisibleFromModule::Filter(self.resolver.module()),
             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 53fe2131a3..f580e09e91 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -9,8 +9,11 @@ use hir_def::{
 use hir_expand::name::Name;
 
 use crate::{
-    builder::ParamKind, consteval, method_resolution, GenericArgData, Interner, Substitution,
-    TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
+    builder::ParamKind,
+    consteval,
+    method_resolution::{self, VisibleFromModule},
+    GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+    ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -231,7 +234,7 @@ impl<'a> InferenceContext<'a> {
             self.db,
             self.table.trait_env.clone(),
             &traits_in_scope,
-            self.resolver.module().into(),
+            VisibleFromModule::Filter(self.resolver.module()),
             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 de56414d30..81134f666b 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -335,12 +335,13 @@ impl<'a> TyLoweringContext<'a> {
                     let mut expander = self.expander.borrow_mut();
                     if expander.is_some() {
                         (Some(expander), false)
-                    } 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)
+                        *expander = Some(Expander::new(
+                            self.db.upcast(),
+                            macro_call.file_id,
+                            self.resolver.module(),
+                        ));
+                        (Some(expander), true)
                     }
                 };
                 let ty = if let Some(mut expander) = expander {
@@ -860,9 +861,8 @@ impl<'a> TyLoweringContext<'a> {
             }
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
-                    .resolver
-                    .krate()
-                    .and_then(|krate| self.db.lang_item(krate, SmolStr::new_inline("sized")))
+                    .db
+                    .lang_item(self.resolver.krate(), SmolStr::new_inline("sized"))
                     .and_then(|lang_item| lang_item.as_trait());
                 // Don't lower associated type bindings as the only possible relaxed trait bound
                 // `?Sized` has no of them.
@@ -1268,9 +1268,8 @@ 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 = resolver
-        .krate()
-        .and_then(|krate| db.lang_item(krate, SmolStr::new_inline("sized")))
+    let sized_trait = db
+        .lang_item(resolver.krate(), SmolStr::new_inline("sized"))
         .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id));
 
     sized_trait.into_iter().flat_map(move |sized_trait| {
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index 775af2b66c..a7d6bc2401 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -63,10 +63,7 @@ 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) => {
-                    let module = sema.to_module_def(position.file_id)?;
-                    impls_for_ty(&sema, builtin.ty(sema.db, module))
-                }
+                Definition::BuiltinType(builtin) => impls_for_ty(&sema, builtin.ty(sema.db)),
                 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 ec0435aad0..23b995dbb8 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 b2b74ccce3..0676220272 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 4fdb7d0bc3..ba2b397f2a 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -110,7 +110,10 @@ fn hints(
     config: &InlayHintsConfig,
     node: SyntaxNode,
 ) {
-    let krate = sema.scope(&node).module().map(|it| it.krate());
+    let krate = match sema.scope(&node) {
+        Some(it) => it.krate(),
+        None => return,
+    };
     let famous_defs = FamousDefs(sema, krate);
     if let Some(expr) = ast::Expr::cast(node.clone()) {
         chaining_hints(hints, sema, &famous_defs, config, &expr);
@@ -503,7 +506,7 @@ fn bind_pat_hints(
         return None;
     }
 
-    let krate = sema.scope(desc_pat.syntax()).module().map(|it| it.krate());
+    let krate = sema.scope(desc_pat.syntax())?.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 7fcb09b5e2..c9b53b1c48 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},
-        Env, FileLoader, FileSet, SourceDatabase, VfsPath,
+        CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
     },
     symbol_index, LineIndexDatabase,
 };
@@ -232,7 +232,7 @@ impl Analysis {
             Env::default(),
             Default::default(),
             false,
-            Default::default(),
+            CrateOrigin::CratesIo { repo: None },
         );
         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 2e93d895f0..0f75abe55c 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},
+    base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin},
     defs::{Definition, IdentClass},
     helpers::pick_best_token,
     RootDatabase,
@@ -151,11 +151,20 @@ 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 => (
+                CrateOrigin::Lang(lang) => (
                     "https://github.com/rust-lang/rust/".to_string(),
-                    "compiler_version".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 => "",
+                        }
+                    ),
                 ),
-                CrateOrigin::Unknown => return None,
             };
             PackageInformation { name, repo, version }
         },
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index e5d4ed8b92..908bbfde24 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -179,12 +179,16 @@ 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,
-        sema.scope(&root).krate(),
+        krate,
         range_to_highlight,
         syntactic_name_ref_highlighting,
     );
@@ -196,7 +200,7 @@ fn traverse(
     sema: &Semantics<RootDatabase>,
     file_id: FileId,
     root: &SyntaxNode,
-    krate: Option<hir::Crate>,
+    krate: 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 7ac6775685..5fb87598f4 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -3,7 +3,6 @@
 use hir::{AsAssocItem, HasVisibility, Semantics};
 use ide_db::{
     defs::{Definition, IdentClass, NameClass, NameRefClass},
-    famous_defs::FamousDefs,
     RootDatabase, SymbolKind,
 };
 use rustc_hash::FxHashMap;
@@ -49,7 +48,7 @@ pub(super) fn token(sema: &Semantics<RootDatabase>, token: SyntaxToken) -> Optio
 
 pub(super) fn name_like(
     sema: &Semantics<RootDatabase>,
-    krate: Option<hir::Crate>,
+    krate: hir::Crate,
     bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
     syntactic_name_ref_highlighting: bool,
     name_like: ast::NameLike,
@@ -193,7 +192,7 @@ fn keyword(
 
 fn highlight_name_ref(
     sema: &Semantics<RootDatabase>,
-    krate: Option<hir::Crate>,
+    krate: hir::Crate,
     bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
     binding_hash: &mut Option<u64>,
     syntactic_name_ref_highlighting: bool,
@@ -279,7 +278,7 @@ fn highlight_name(
     sema: &Semantics<RootDatabase>,
     bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
     binding_hash: &mut Option<u64>,
-    krate: Option<hir::Crate>,
+    krate: hir::Crate,
     name: ast::Name,
 ) -> Highlight {
     let name_kind = NameClass::classify(sema, &name);
@@ -323,11 +322,7 @@ fn calc_binding_hash(name: &hir::Name, shadow_count: u32) -> u64 {
     hash((name, shadow_count))
 }
 
-fn highlight_def(
-    sema: &Semantics<RootDatabase>,
-    krate: Option<hir::Crate>,
-    def: Definition,
-) -> Highlight {
+fn highlight_def(sema: &Semantics<RootDatabase>, krate: 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())),
@@ -472,14 +467,12 @@ fn highlight_def(
         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 != krate;
-    let is_from_builtin_crate =
-        def_crate.map_or(false, |def_crate| famous_defs.builtin_crates().any(|it| def_crate == it));
+    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_builtin_type = matches!(def, Definition::BuiltinType(_));
     let is_public = def.visibility(db) == Some(hir::Visibility::Public);
 
@@ -498,7 +491,7 @@ fn highlight_def(
 
 fn highlight_method_call_by_name_ref(
     sema: &Semantics<RootDatabase>,
-    krate: Option<hir::Crate>,
+    krate: hir::Crate,
     name_ref: &ast::NameRef,
 ) -> Option<Highlight> {
     let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
@@ -507,7 +500,7 @@ fn highlight_method_call_by_name_ref(
 
 fn highlight_method_call(
     sema: &Semantics<RootDatabase>,
-    krate: Option<hir::Crate>,
+    krate: hir::Crate,
     method_call: &ast::MethodCallExpr,
 ) -> Option<Highlight> {
     let func = sema.resolve_method_call(method_call)?;
@@ -525,10 +518,9 @@ 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 = Some(def_crate) != krate;
-    let is_from_builtin_crate = famous_defs.builtin_crates().any(|it| def_crate == it);
+    let is_from_other_crate = def_crate != krate;
+    let is_from_builtin_crate = def_crate.is_builtin(sema.db);
     let is_public = func.visibility(sema.db) == hir::Visibility::Public;
 
     if is_from_other_crate {
@@ -593,7 +585,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
 fn highlight_name_ref_by_syntax(
     name: ast::NameRef,
     sema: &Semantics<RootDatabase>,
-    krate: Option<hir::Crate>,
+    krate: hir::Crate,
 ) -> Highlight {
     let default = HlTag::UnresolvedReference;
 
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs
index 11f12773e8..6b7db739c8 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 c82caa3704..6e700695fb 100644
--- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
@@ -104,6 +104,7 @@ 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(
@@ -118,7 +119,6 @@ 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 0dc67ede36..171b3f4432 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,8 +92,7 @@ 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, Some(module.krate())).core_option_Option().map(lift_enum);
+        let option_enum = FamousDefs(&ctx.sema, 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 c7172741e4..42a5b8b672 100644
--- a/crates/ide_assists/src/handlers/add_return_type.rs
+++ b/crates/ide_assists/src/handlers/add_return_type.rs
@@ -17,7 +17,7 @@ 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 module = ctx.sema.scope(tail_expr.syntax())?.module();
     let ty = ctx.sema.type_of_expr(&peel_blocks(tail_expr.clone()))?.original();
     if ty.is_unit() {
         return None;
diff --git a/crates/ide_assists/src/handlers/convert_bool_then.rs b/crates/ide_assists/src/handlers/convert_bool_then.rs
index daec28999e..f07fde07c0 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 9185501a62..869f76951d 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, Some(module.krate())).core_convert_Into()? {
+    if trait_ != FamousDefs(&ctx.sema, 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 bb75cb5c95..711b914561 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.module()?.krate();
+    let scope = sema.scope(iterable.syntax())?;
+    let krate = scope.krate();
     let traits_in_scope = scope.visible_traits();
-    let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?;
+    let iter_trait = FamousDefs(sema, krate).core_iter_Iterator()?;
 
     let has_wanted_method = ty
         .iterate_method_candidates(
@@ -175,24 +175,17 @@ 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 = match sema.type_of_expr(iterable) {
-        Some(it) => it.adjusted(),
-        None => return false,
-    };
+    (|| {
+        let it_typ = sema.type_of_expr(iterable)?.adjusted();
 
-    let module = match sema.scope(iterable.syntax()).module() {
-        Some(it) => it,
-        None => return false,
-    };
+        let module = sema.scope(iterable.syntax())?.module();
 
-    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,
-    }
+        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)
 }
 
 fn validate_method_call_expr(
@@ -214,10 +207,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, Some(krate)).core_iter_Iterator()?;
+    let iter_trait = FamousDefs(sema, 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 135f2a70b7..3566b1be89 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 fcb4aaf065..c26e4b1c75 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, Some(module.krate())).core_ops_ControlFlow();
+                    FamousDefs(&ctx.sema, module.krate()).core_ops_ControlFlow();
 
                 if let Some(control_flow_enum) = control_flow_enum {
                     let mod_path = module.find_use_path_prefixed(
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 4b597837aa..45f98e690f 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 bbb5cf9187..b895208f41 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 52ae60e2ed..c4b759d5f3 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 4745ac24e9..4d47437f7c 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, Some(krate)).core_default_Default()?;
+    let default_trait = FamousDefs(sema, 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 669fb28d10..119bb6e07b 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, Some(krate)).core_default_Default();
+    let default = FamousDefs(&ctx.sema, 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 f6e0d619de..120acde8e5 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 4328c54c09..3cb8a68687 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, Some(krate)).core_ops_Deref()?;
+    let deref_trait = FamousDefs(sema, 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 15a07492ec..3eaa445d32 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()).module()?.krate();
+    let krate = ctx.sema.scope(ast_func.syntax())?.krate();
     Some(krate.display_name(ctx.db())?.to_string())
 }
 
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 ee8de5a20e..5bb7edb0a7 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
@@ -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, Some(krate)).core_convert_From()?;
+    let from_trait = FamousDefs(sema, 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 c06498a4c9..ae4436ce88 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 = current_module(call.syntax(), ctx)?;
+                let current_module = ctx.sema.scope(call.syntax())?.module();
                 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 = current_module(call.syntax(), ctx)?;
+    let current_module = ctx.sema.scope(call.syntax())?.module();
     let target_module = adt.module(ctx.sema.db);
 
     if current_module.krate() != target_module.krate() {
@@ -166,10 +166,6 @@ 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,
@@ -235,7 +231,8 @@ impl FunctionBuilder {
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
         let needs_pub = target_module.is_some();
-        let target_module = target_module.or_else(|| current_module(target.syntax(), ctx))?;
+        let target_module =
+            target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
         let fn_name = make::name(fn_name);
         let (type_params, params) =
             fn_args(ctx, target_module, ast::CallableExpr::Call(call.clone()))?;
@@ -266,7 +263,7 @@ impl FunctionBuilder {
         target: GeneratedFunctionTarget,
     ) -> Option<Self> {
         let needs_pub =
-            !module_is_descendant(&current_module(call.syntax(), ctx)?, &target_module, ctx);
+            !module_is_descendant(&ctx.sema.scope(call.syntax())?.module(), &target_module, ctx);
         let fn_name = make::name(&name.text());
         let (type_params, params) =
             fn_args(ctx, target_module, ast::CallableExpr::MethodCall(call.clone()))?;
@@ -520,7 +517,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 2e81dd13f4..9513c112f3 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -121,25 +121,24 @@ pub(crate) fn generate_getter_impl(
                     "a mutable reference to ",
                 )
             } else {
-                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 ",
-                        )
-                    })
+                (|| {
+                    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 ")
+                })
             };
 
             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 bd7c85c443..1ad1cea43f 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 994d78303f..5a28cbcc23 100644
--- a/crates/ide_assists/src/handlers/inline_call.rs
+++ b/crates/ide_assists/src/handlers/inline_call.rs
@@ -391,13 +391,11 @@ fn inline(
         }
     }
     if let Some(generic_arg_list) = generic_arg_list.clone() {
-        PathTransform::function_call(
-            &sema.scope(node.syntax()),
-            &sema.scope(fn_body.syntax()),
-            function,
-            generic_arg_list,
-        )
-        .apply(body.syntax());
+        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());
+        }
     }
 
     let original_indentation = match node {
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 58cee8eafb..65c14406f9 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 0f232caab6..ba0a142718 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 0d0bd7071f..03e41b4340 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 b23b5bf87c..4800d54956 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,9 +63,11 @@ pub(crate) fn replace_qualified_name_with_use(
     );
     let path_to_qualifier = starts_with_name_ref
         .then(|| {
-            ctx.sema.scope(path.syntax()).module().and_then(|m| {
-                m.find_use_path_prefixed(ctx.sema.db, module, ctx.config.insert_use.prefix_kind)
-            })
+            ctx.sema.scope(path.syntax())?.module().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 b890462389..ff79c5b82a 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).and_then(|ty| ty.as_adt());
+    let ty = ctx.sema.resolve_type(type_ref)?.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 972d4765bb..251b41c84a 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).and_then(|ty| ty.as_adt());
+    let ty = ctx.sema.resolve_type(type_ref)?.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 42317ea4da..0add950718 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -600,8 +600,7 @@ fn handle_as_ref_str(
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs,
 ) -> Option<ReferenceConversionType> {
-    let module = famous_defs.1?.root_module(db);
-    let str_type = hir::BuiltinType::str().ty(db, module);
+    let str_type = hir::BuiltinType::str().ty(db);
 
     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 867e6bcf48..ab442fa64b 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -352,14 +352,6 @@ 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 {
@@ -373,7 +365,7 @@ fn enum_variants_with_paths(
     }
 
     for variant in variants {
-        if let Some(path) = module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
+        if let Some(path) = ctx.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 6b51e19bbb..c79a9816f4 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, ctx.module) {
+            for (name, def) in module.scope(ctx.db, Some(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 58d0a39949..b7e69d7b43 100644
--- a/crates/ide_completion/src/completions/attribute/cfg.rs
+++ b/crates/ide_completion/src/completions/attribute/cfg.rs
@@ -27,26 +27,17 @@ 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) => {
-            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);
+        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);
 
-                    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());
-                })
-            }
-        }
+            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());
+        }),
     };
 }
 
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
index 3c0e43ceac..4611811539 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, ctx.module) {
+            for (name, def) in module.scope(ctx.db, Some(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 981e25b55c..c237a65bfe 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,
-        ctx.module,
+        Some(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 ee751f9f77..7d5709ec90 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -225,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 c5bc91d73d..7e9c1f49de 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,
     };
-    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);
+    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);
+                }
             }
-        }
-    });
+        });
+    }
 }
 
 fn remove_duplicated(
diff --git a/crates/ide_completion/src/completions/mod_.rs b/crates/ide_completion/src/completions/mod_.rs
index 7699c530c6..fb42e4e72f 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 0d3a49c668..00f9bdfb51 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, ctx.module);
+                    let module_scope = module.scope(ctx.db, Some(ctx.module));
                     for (name, def) in module_scope {
                         let add_resolution = match def {
                             ScopeDef::ModuleDef(hir::ModuleDef::Macro(mac)) => {
@@ -159,13 +159,7 @@ 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)) => {
-                            let module = match ctx.module {
-                                Some(m) => m,
-                                None => return,
-                            };
-                            ty.ty(ctx.db, module)
-                        }
+                        hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => ty.ty(ctx.db),
                         _ => return,
                     };
 
@@ -175,7 +169,7 @@ fn pattern_path_completion(
                         ctx.db,
                         &ctx.scope,
                         &traits_in_scope,
-                        ctx.module,
+                        Some(ctx.module),
                         None,
                         |item| {
                             match item {
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index c1f23ceeca..534d27d983 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -1,7 +1,6 @@
 //! 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;
 
@@ -26,7 +25,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) = FamousDefs(&ctx.sema, ctx.krate).core_ops_Drop() {
+        if let Some(drop) = ctx.famous_defs().core_ops_Drop() {
             traits_in_scope.remove(&drop.into());
         }
         traits_in_scope
@@ -58,7 +57,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, ctx.module) {
+                for (name, def) in module.scope(ctx.db, Some(ctx.module)) {
                     if let Some(def) = module_or_fn_macro(ctx.db, def) {
                         acc.add_resolution(ctx, name, def);
                     }
@@ -90,7 +89,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, ctx.module);
+            let module_scope = module.scope(ctx.db, Some(ctx.module));
             for (name, def) in module_scope {
                 let add_resolution = match def {
                     // Don't suggest attribute macros and derives.
@@ -133,12 +132,8 @@ 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, module)
+                    builtin.ty(ctx.db)
                 }
                 _ => unreachable!(),
             };
@@ -146,29 +141,26 @@ 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 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)
-                    }
+            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);
                     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`.
@@ -192,7 +184,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
                 ctx.db,
                 &ctx.scope,
                 &traits_in_scope,
-                ctx.module,
+                Some(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 5509ec922f..b65cf60a01 100644
--- a/crates/ide_completion/src/completions/record.rs
+++ b/crates/ide_completion/src/completions/record.rs
@@ -83,17 +83,18 @@ 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 module = if let Some(module) = ctx.module { module } else { strukt.module(ctx.db) };
-            let path = module
+            let path = ctx
+                .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 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);
+            let path = ctx
+                .module
+                .find_use_path(ctx.db, hir::ModuleDef::from(un))
+                .filter(|it| it.len() > 1);
 
             acc.add_union_literal(ctx, un, path, None);
         }
diff --git a/crates/ide_completion/src/completions/trait_impl.rs b/crates/ide_completion/src/completions/trait_impl.rs
index 0d59f77a55..9c557aa524 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 16b356963d..d7c279f9d9 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, ctx.module);
+                    let module_scope = module.scope(ctx.db, Some(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 c610dcd705..ca6f6dff1e 100644
--- a/crates/ide_completion/src/completions/vis.rs
+++ b/crates/ide_completion/src/completions/vis.rs
@@ -22,17 +22,16 @@ 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 {
-                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()));
-                        }
+                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()));
                     }
                 }
             }
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index ed59eb6bd3..12747b3ce4 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: Option<hir::Crate>,
+    pub(super) krate: hir::Crate,
     /// The module of the `scope`.
-    pub(super) module: Option<hir::Module>,
+    pub(super) module: hir::Module,
     pub(super) expected_name: Option<NameOrNameRef>,
     pub(super) expected_type: Option<Type>,
 
@@ -353,11 +353,7 @@ impl<'a> CompletionContext<'a> {
         attrs: &hir::Attrs,
         defining_crate: hir::Crate,
     ) -> Visible {
-        let module = match self.module {
-            Some(it) => it,
-            None => return Visible::No,
-        };
-        if !vis.is_visible_from(self.db, module.into()) {
+        if !vis.is_visible_from(self.db, self.module.into()) {
             if !self.config.enable_private_editable {
                 return Visible::No;
             }
@@ -376,11 +372,8 @@ impl<'a> CompletionContext<'a> {
     }
 
     fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
-        match self.krate {
-            // `doc(hidden)` items are only completed within the defining crate.
-            Some(krate) => krate != defining_crate && attrs.has_doc_hidden(),
-            None => true,
-        }
+        // `doc(hidden)` items are only completed within the defining crate.
+        self.krate != defining_crate && attrs.has_doc_hidden()
     }
 }
 
@@ -409,7 +402,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/lib.rs b/crates/ide_completion/src/lib.rs
index 422bda6460..56c41a88e4 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -185,7 +185,7 @@ 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();
diff --git a/crates/ide_completion/src/render/variant.rs b/crates/ide_completion/src/render/variant.rs
index a37b4237c4..39a37dc9f8 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 0a154f14e5..1340080fdf 100644
--- a/crates/ide_completion/src/snippet.rs
+++ b/crates/ide_completion/src/snippet.rs
@@ -185,7 +185,7 @@ fn import_edits(
             _ => return None,
         };
         let path =
-            ctx.module?.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
+            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(),
diff --git a/crates/ide_db/src/famous_defs.rs b/crates/ide_db/src/famous_defs.rs
index cc9f2f9151..58d99ff9df 100644
--- a/crates/ide_db/src/famous_defs.rs
+++ b/crates/ide_db/src/famous_defs.rs
@@ -1,4 +1,6 @@
 //! See [`FamousDefs`].
+
+use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase};
 use hir::{Crate, Enum, Macro, Module, ScopeDef, Semantics, Trait};
 
 use crate::RootDatabase;
@@ -16,16 +18,28 @@ use crate::RootDatabase;
 /// ```
 /// //- minicore: iterator, ord, derive
 /// ```
-pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Option<Crate>);
+pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
 
 #[allow(non_snake_case)]
 impl FamousDefs<'_, '_> {
     pub fn std(&self) -> Option<Crate> {
-        self.find_crate("std")
+        self.find_lang_crate(LangCrateOrigin::Std)
     }
 
     pub fn core(&self) -> Option<Crate> {
-        self.find_crate("core")
+        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)
     }
 
     pub fn core_cmp_Ord(&self) -> Option<Trait> {
@@ -88,18 +102,6 @@ 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(),
@@ -139,11 +141,15 @@ impl FamousDefs<'_, '_> {
         }
     }
 
-    fn find_crate(&self, name: &str) -> Option<Crate> {
-        let krate = self.1?;
+    fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate> {
+        let krate = self.1;
         let db = self.0.db;
-        let res =
-            krate.dependencies(db).into_iter().find(|dep| dep.name.to_smol_str() == name)?.krate;
+        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;
         Some(res)
     }
 
@@ -151,8 +157,16 @@ impl FamousDefs<'_, '_> {
         let db = self.0.db;
         let mut path = path.split(':');
         let trait_ = path.next_back()?;
-        let std_crate = path.next()?;
-        let std_crate = self.find_crate(std_crate)?;
+        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 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 d6246c7ad6..f8cfe15c89 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,7 +248,10 @@ impl ImportAssets {
         };
 
         let krate = self.module_with_candidate.krate();
-        let scope = sema.scope(&self.candidate_node);
+        let scope = match sema.scope(&self.candidate_node) {
+            Some(it) => it,
+            None => return Vec::new(),
+        };
 
         match &self.import_candidate {
             ImportCandidate::Path(path_candidate) => {
@@ -271,9 +274,11 @@ 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();
-        sema.scope(&self.candidate_node).process_all_names(&mut |_, scope_def| {
-            scope_definitions.insert(scope_def);
-        });
+        if let Some(scope) = sema.scope(&self.candidate_node) {
+            scope.process_all_names(&mut |_, scope_def| {
+                scope_definitions.insert(scope_def);
+            });
+        }
         scope_definitions
     }
 }
@@ -588,7 +593,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/path_transform.rs b/crates/ide_db/src/path_transform.rs
index 558f4f1b63..15bd9a8c9c 100644
--- a/crates/ide_db/src/path_transform.rs
+++ b/crates/ide_db/src/path_transform.rs
@@ -69,15 +69,13 @@ impl<'a> PathTransform<'a> {
     }
 
     pub fn apply(&self, syntax: &SyntaxNode) {
-        if let Some(ctx) = self.build_ctx() {
-            ctx.apply(syntax)
-        }
+        self.build_ctx().apply(syntax)
     }
 
-    fn build_ctx(&self) -> Option<Ctx<'a>> {
+    fn build_ctx(&self) -> 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,
@@ -111,8 +109,7 @@ impl<'a> PathTransform<'a> {
                 },
             })
             .collect();
-        let res = Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope };
-        Some(res)
+        Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope }
     }
 }
 
diff --git a/crates/ide_db/src/search.rs b/crates/ide_db/src/search.rs
index 805eac30b8..fe99c2e2ce 100644
--- a/crates/ide_db/src/search.rs
+++ b/crates/ide_db/src/search.rs
@@ -734,13 +734,7 @@ 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) => {
-            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::BuiltinType(it) => Some(it.ty(sema.db)),
         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 8b3c22fffc..414878b230 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,11 +171,7 @@ 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, Some(krate)).core_default_Default()?,
-            &[],
-        )
+        && ty.impls_trait(ctx.sema.db, FamousDefs(&ctx.sema, 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 8ae9a0be53..1b275f7e6c 100644
--- a/crates/ide_diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide_diagnostics/src/handlers/type_mismatch.rs
@@ -76,7 +76,7 @@ fn add_missing_ok_or_some(
     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 scope = ctx.sema.scope(expr.syntax())?;
 
     let expected_adt = d.expected.as_adt()?;
     let expected_enum = expected_adt.as_enum()?;
diff --git a/crates/ide_ssr/src/from_comment.rs b/crates/ide_ssr/src/from_comment.rs
index f1b312284d..c50e74d93a 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![]);
+    let mut match_finder = MatchFinder::in_context(db, lookup_context, vec![]).ok()?;
     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 d56bc12b68..4db8034212 100644
--- a/crates/ide_ssr/src/lib.rs
+++ b/crates/ide_ssr/src/lib.rs
@@ -128,11 +128,12 @@ impl<'db> MatchFinder<'db> {
         db: &'db ide_db::RootDatabase,
         lookup_context: FilePosition,
         mut restrict_ranges: Vec<FileRange>,
-    ) -> MatchFinder<'db> {
+    ) -> Result<MatchFinder<'db>, SsrError> {
         restrict_ranges.retain(|range| !range.range.is_empty());
         let sema = Semantics::new(db);
-        let resolution_scope = resolving::ResolutionScope::new(&sema, lookup_context);
-        MatchFinder { sema, rules: Vec::new(), resolution_scope, restrict_ranges }
+        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 })
     }
 
     /// Constructs an instance using the start of the first file in `db` as the lookup context.
@@ -142,11 +143,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())
         {
-            Ok(MatchFinder::in_context(
+            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 88c1d80608..ba5aa0cc94 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)
-            .module()
-            .ok_or_else(|| match_error!("Matched node isn't in a module"))?;
+            .ok_or_else(|| match_error!("Matched node isn't in a module"))?
+            .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);
+        let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
         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 e15cb874ef..d9b40608b8 100644
--- a/crates/ide_ssr/src/resolving.rs
+++ b/crates/ide_ssr/src/resolving.rs
@@ -186,7 +186,7 @@ impl<'db> ResolutionScope<'db> {
     pub(crate) fn new(
         sema: &hir::Semantics<'db, ide_db::RootDatabase>,
         resolve_context: FilePosition,
-    ) -> ResolutionScope<'db> {
+    ) -> Option<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.
@@ -197,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);
-        ResolutionScope { scope, node }
+        let scope = sema.scope(&node)?;
+        Some(ResolutionScope { scope, node })
     }
 
     /// Returns the function in which SSR was invoked, if any.
@@ -219,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,
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 1a86d232eb..509219f0b6 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, ProcMacro,
+    FileId, LangCrateOrigin, 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::Unknown
+                        CrateOrigin::CratesIo { repo: None }
                     },
                 ),
             )
@@ -710,7 +710,7 @@ fn detached_files_to_crate_graph(
             Env::default(),
             Vec::new(),
             false,
-            CrateOrigin::Unknown,
+            CrateOrigin::CratesIo { repo: None },
         );
 
         public_deps.add(detached_file_crate, &mut crate_graph);
@@ -908,7 +908,14 @@ fn sysroot_to_crate_graph(
                 env,
                 proc_macro,
                 false,
-                CrateOrigin::Lang,
+                CrateOrigin::Lang(match &*sysroot[krate].name {
+                    "alloc" => LangCrateOrigin::Alloc,
+                    "core" => LangCrateOrigin::Core,
+                    "proc_macro" => LangCrateOrigin::ProcMacro,
+                    "std" => LangCrateOrigin::Std,
+                    "test" => LangCrateOrigin::Test,
+                    _ => LangCrateOrigin::Other,
+                }),
             );
             Some((krate, crate_id))
         })


Test patch:
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 87b9da46e2..af41796e21 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 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>
+<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>
 </code></pre>
\ No newline at end of file
diff --git a/crates/ide_ssr/src/tests.rs b/crates/ide_ssr/src/tests.rs
index 1862c3bcc2..26a043dc98 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);
+    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
     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);
+    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
     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);
+    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
     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);
+    let mut match_finder = MatchFinder::in_context(&db, position, selections).unwrap();
     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/project_model/src/tests.rs b/crates/project_model/src/tests.rs
index ca347d71a2..351e820ada 100644
--- a/crates/project_model/src/tests.rs
+++ b/crates/project_model/src/tests.rs
@@ -1261,7 +1261,9 @@ fn rust_project_hello_world_project_model() {
                             },
                         ],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Alloc,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1291,7 +1293,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Other,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1321,7 +1325,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Other,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1361,7 +1367,9 @@ fn rust_project_hello_world_project_model() {
                             },
                         ],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            ProcMacro,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1391,7 +1399,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Core,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1490,7 +1500,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Other,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1520,7 +1532,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Other,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1550,7 +1564,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Other,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1580,7 +1596,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Test,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1692,7 +1710,9 @@ fn rust_project_hello_world_project_model() {
                             },
                         ],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Std,
+                        ),
                         is_proc_macro: false,
                     },
                     CrateId(
@@ -1722,7 +1742,9 @@ fn rust_project_hello_world_project_model() {
                         },
                         dependencies: [],
                         proc_macro: [],
-                        origin: Lang,
+                        origin: Lang(
+                            Other,
+                        ),
                         is_proc_macro: false,
                     },
                 },