]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir/src/lib.rs
Merge #11393
[rust.git] / crates / hir / src / lib.rs
index 7add0f4a4362eb6d27c08f0cf8a796173f0a6935..e091af4bf8cdaa3b1f4ff9bd26334904ae0d0985 100644 (file)
 
 pub mod diagnostics;
 pub mod db;
+pub mod symbols;
 
 mod display;
 
-use std::{iter, ops::ControlFlow, sync::Arc};
+use std::{collections::HashMap, iter, ops::ControlFlow, sync::Arc};
 
 use arrayvec::ArrayVec;
 use base_db::{CrateDisplayName, CrateId, CrateOrigin, Edition, FileId};
     adt::{ReprKind, VariantData},
     body::{BodyDiagnostic, SyntheticSyntax},
     expr::{BindingAnnotation, LabelId, Pat, PatId},
+    item_tree::ItemTreeNode,
     lang_item::LangItemTarget,
-    nameres,
+    nameres::{self, diagnostics::DefDiagnostic},
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
-    AttrDefId, ConstId, ConstParamId, EnumId, FunctionId, GenericDefId, HasModule, LifetimeParamId,
-    LocalEnumVariantId, LocalFieldId, StaticId, StructId, TypeAliasId, TypeParamId, UnionId,
+    src::HasSource as _,
+    AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
+    FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
+    LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
+    TypeParamId, UnionId,
 };
-use hir_expand::{name::name, MacroCallKind, MacroDefKind};
+use hir_expand::{name::name, MacroCallKind, MacroDefId, MacroDefKind};
 use hir_ty::{
     autoderef,
-    consteval::ConstExt,
+    consteval::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt},
     could_unify,
     diagnostics::BodyValidationDiagnostic,
     method_resolution::{self, TyFingerprint},
@@ -68,7 +73,7 @@
 use rustc_hash::FxHashSet;
 use stdx::{format_to, impl_from};
 use syntax::{
-    ast::{self, HasAttrs as _, HasName},
+    ast::{self, HasAttrs as _, HasDocComments, HasName},
     AstNode, AstPtr, SmolStr, SyntaxKind, SyntaxNodePtr,
 };
 use tt::{Ident, Leaf, Literal, TokenTree};
         builtin_attr::AttributeTemplate,
         find_path::PrefixKind,
         import_map,
-        item_scope::ItemScope,
-        item_tree::ItemTreeNode,
-        nameres::{DefMap, ModuleData, ModuleOrigin, ModuleSource},
+        nameres::ModuleSource,
         path::{ModPath, PathKind},
-        src::HasSource as DefHasSource, // xx: I don't like this shadowing of HasSource... :(
         type_ref::{Mutability, TypeRef},
         visibility::Visibility,
-        AdtId,
-        AssocItemId,
-        AssocItemLoc,
-        DefWithBodyId,
-        ImplId,
-        ItemContainerId,
-        ItemLoc,
-        Lookup,
-        ModuleDefId,
-        ModuleId,
-        TraitId,
     },
     hir_expand::{
         name::{known, Name},
-        ExpandResult, HirFileId, InFile, MacroDefId, MacroFile, Origin,
+        ExpandResult, HirFileId, InFile, MacroFile, Origin,
     },
     hir_ty::display::HirDisplay,
 };
@@ -191,6 +182,11 @@ pub fn root_module(self, db: &dyn HirDatabase) -> Module {
         Module { id: def_map.module_id(def_map.root()) }
     }
 
+    pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
+        let def_map = db.crate_def_map(self.id);
+        def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
+    }
+
     pub fn root_file(self, db: &dyn HirDatabase) -> FileId {
         db.crate_graph()[self.id].root_file_id
     }
@@ -523,184 +519,7 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
                 // FIXME: This is accidentally quadratic.
                 continue;
             }
-            match &diag.kind {
-                DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
-                    let decl = declaration.to_node(db.upcast());
-                    acc.push(
-                        UnresolvedModule {
-                            decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
-                            candidate: candidate.clone(),
-                        }
-                        .into(),
-                    )
-                }
-                DefDiagnosticKind::UnresolvedExternCrate { ast } => {
-                    let item = ast.to_node(db.upcast());
-                    acc.push(
-                        UnresolvedExternCrate {
-                            decl: InFile::new(ast.file_id, AstPtr::new(&item)),
-                        }
-                        .into(),
-                    );
-                }
-
-                DefDiagnosticKind::UnresolvedImport { id, index } => {
-                    let file_id = id.file_id();
-                    let item_tree = id.item_tree(db.upcast());
-                    let import = &item_tree[id.value];
-
-                    let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
-                    acc.push(
-                        UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }
-                            .into(),
-                    );
-                }
-
-                DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
-                    let item = ast.to_node(db.upcast());
-                    acc.push(
-                        InactiveCode {
-                            node: ast.with_value(AstPtr::new(&item).into()),
-                            cfg: cfg.clone(),
-                            opts: opts.clone(),
-                        }
-                        .into(),
-                    );
-                }
-
-                DefDiagnosticKind::UnresolvedProcMacro { ast } => {
-                    let mut precise_location = None;
-                    let (node, name) = match ast {
-                        MacroCallKind::FnLike { ast_id, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-                            (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None)
-                        }
-                        MacroCallKind::Derive { ast_id, derive_name, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-
-                            // Compute the precise location of the macro name's token in the derive
-                            // list.
-                            // FIXME: This does not handle paths to the macro, but neither does the
-                            // rest of r-a.
-                            let derive_attrs =
-                                node.attrs().filter_map(|attr| match attr.as_simple_call() {
-                                    Some((name, args)) if name == "derive" => Some(args),
-                                    _ => None,
-                                });
-                            'outer: for attr in derive_attrs {
-                                let tokens =
-                                    attr.syntax().children_with_tokens().filter_map(|elem| {
-                                        match elem {
-                                            syntax::NodeOrToken::Node(_) => None,
-                                            syntax::NodeOrToken::Token(tok) => Some(tok),
-                                        }
-                                    });
-                                for token in tokens {
-                                    if token.kind() == SyntaxKind::IDENT
-                                        && token.text() == &**derive_name
-                                    {
-                                        precise_location = Some(token.text_range());
-                                        break 'outer;
-                                    }
-                                }
-                            }
-
-                            (
-                                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
-                                Some(derive_name.clone()),
-                            )
-                        }
-                        MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-                            let attr =
-                                node.attrs().nth((*invoc_attr_index) as usize).unwrap_or_else(
-                                    || panic!("cannot find attribute #{}", invoc_attr_index),
-                                );
-                            (
-                                ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
-                                Some(attr_name.clone()),
-                            )
-                        }
-                    };
-                    acc.push(
-                        UnresolvedProcMacro {
-                            node,
-                            precise_location,
-                            macro_name: name.map(Into::into),
-                        }
-                        .into(),
-                    );
-                }
-
-                DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
-                    let node = ast.to_node(db.upcast());
-                    acc.push(
-                        UnresolvedMacroCall {
-                            macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
-                            path: path.clone(),
-                        }
-                        .into(),
-                    );
-                }
-
-                DefDiagnosticKind::MacroError { ast, message } => {
-                    let node = match ast {
-                        MacroCallKind::FnLike { ast_id, .. } => {
-                            let node = ast_id.to_node(db.upcast());
-                            ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
-                        }
-                        MacroCallKind::Derive { ast_id, .. }
-                        | MacroCallKind::Attr { ast_id, .. } => {
-                            // FIXME: point to the attribute instead, this creates very large diagnostics
-                            let node = ast_id.to_node(db.upcast());
-                            ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
-                        }
-                    };
-                    acc.push(MacroError { node, message: message.clone() }.into());
-                }
-
-                DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
-                    let node = ast.to_node(db.upcast());
-                    // Must have a name, otherwise we wouldn't emit it.
-                    let name = node.name().expect("unimplemented builtin macro with no name");
-                    acc.push(
-                        UnimplementedBuiltinMacro {
-                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
-                        }
-                        .into(),
-                    );
-                }
-                DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
-                    let node = ast.to_node(db.upcast());
-                    let derive = node.attrs().nth(*id as usize);
-                    match derive {
-                        Some(derive) => {
-                            acc.push(
-                                InvalidDeriveTarget {
-                                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
-                                }
-                                .into(),
-                            );
-                        }
-                        None => stdx::never!("derive diagnostic on item without derive attribute"),
-                    }
-                }
-                DefDiagnosticKind::MalformedDerive { ast, id } => {
-                    let node = ast.to_node(db.upcast());
-                    let derive = node.attrs().nth(*id as usize);
-                    match derive {
-                        Some(derive) => {
-                            acc.push(
-                                MalformedDerive {
-                                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
-                                }
-                                .into(),
-                            );
-                        }
-                        None => stdx::never!("derive diagnostic on item without derive attribute"),
-                    }
-                }
-            }
+            emit_def_diagnostic(db, acc, diag);
         }
         for decl in self.declarations(db) {
             match decl {
@@ -760,6 +579,180 @@ pub fn find_use_path_prefixed(
     }
 }
 
+fn emit_def_diagnostic(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, diag: &DefDiagnostic) {
+    match &diag.kind {
+        DefDiagnosticKind::UnresolvedModule { ast: declaration, candidate } => {
+            let decl = declaration.to_node(db.upcast());
+            acc.push(
+                UnresolvedModule {
+                    decl: InFile::new(declaration.file_id, AstPtr::new(&decl)),
+                    candidate: candidate.clone(),
+                }
+                .into(),
+            )
+        }
+        DefDiagnosticKind::UnresolvedExternCrate { ast } => {
+            let item = ast.to_node(db.upcast());
+            acc.push(
+                UnresolvedExternCrate { decl: InFile::new(ast.file_id, AstPtr::new(&item)) }.into(),
+            );
+        }
+
+        DefDiagnosticKind::UnresolvedImport { id, index } => {
+            let file_id = id.file_id();
+            let item_tree = id.item_tree(db.upcast());
+            let import = &item_tree[id.value];
+
+            let use_tree = import.use_tree_to_ast(db.upcast(), file_id, *index);
+            acc.push(
+                UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
+            );
+        }
+
+        DefDiagnosticKind::UnconfiguredCode { ast, cfg, opts } => {
+            let item = ast.to_node(db.upcast());
+            acc.push(
+                InactiveCode {
+                    node: ast.with_value(AstPtr::new(&item).into()),
+                    cfg: cfg.clone(),
+                    opts: opts.clone(),
+                }
+                .into(),
+            );
+        }
+
+        DefDiagnosticKind::UnresolvedProcMacro { ast } => {
+            let mut precise_location = None;
+            let (node, name) = match ast {
+                MacroCallKind::FnLike { ast_id, .. } => {
+                    let node = ast_id.to_node(db.upcast());
+                    (ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))), None)
+                }
+                MacroCallKind::Derive { ast_id, derive_name, .. } => {
+                    let node = ast_id.to_node(db.upcast());
+
+                    // Compute the precise location of the macro name's token in the derive
+                    // list.
+                    // FIXME: This does not handle paths to the macro, but neither does the
+                    // rest of r-a.
+                    let derive_attrs =
+                        node.attrs().filter_map(|attr| match attr.as_simple_call() {
+                            Some((name, args)) if name == "derive" => Some(args),
+                            _ => None,
+                        });
+                    'outer: for attr in derive_attrs {
+                        let tokens =
+                            attr.syntax().children_with_tokens().filter_map(|elem| match elem {
+                                syntax::NodeOrToken::Node(_) => None,
+                                syntax::NodeOrToken::Token(tok) => Some(tok),
+                            });
+                        for token in tokens {
+                            if token.kind() == SyntaxKind::IDENT && token.text() == &**derive_name {
+                                precise_location = Some(token.text_range());
+                                break 'outer;
+                            }
+                        }
+                    }
+
+                    (
+                        ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node))),
+                        Some(derive_name.clone()),
+                    )
+                }
+                MacroCallKind::Attr { ast_id, invoc_attr_index, attr_name, .. } => {
+                    let node = ast_id.to_node(db.upcast());
+                    let attr = node
+                        .doc_comments_and_attrs()
+                        .nth((*invoc_attr_index) as usize)
+                        .and_then(Either::left)
+                        .unwrap_or_else(|| panic!("cannot find attribute #{}", invoc_attr_index));
+                    (
+                        ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&attr))),
+                        Some(attr_name.clone()),
+                    )
+                }
+            };
+            acc.push(
+                UnresolvedProcMacro { node, precise_location, macro_name: name.map(Into::into) }
+                    .into(),
+            );
+        }
+
+        DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
+            let node = ast.to_node(db.upcast());
+            acc.push(
+                UnresolvedMacroCall {
+                    macro_call: InFile::new(ast.file_id, AstPtr::new(&node)),
+                    path: path.clone(),
+                }
+                .into(),
+            );
+        }
+
+        DefDiagnosticKind::MacroError { ast, message } => {
+            let node = match ast {
+                MacroCallKind::FnLike { ast_id, .. } => {
+                    let node = ast_id.to_node(db.upcast());
+                    ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
+                }
+                MacroCallKind::Derive { ast_id, .. } => {
+                    // FIXME: point to the attribute instead, this creates very large diagnostics
+                    let node = ast_id.to_node(db.upcast());
+                    ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
+                }
+                MacroCallKind::Attr { ast_id, .. } => {
+                    // FIXME: point to the attribute instead, this creates very large diagnostics
+                    let node = ast_id.to_node(db.upcast());
+                    ast_id.with_value(SyntaxNodePtr::from(AstPtr::new(&node)))
+                }
+            };
+            acc.push(MacroError { node, message: message.clone() }.into());
+        }
+
+        DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
+            let node = ast.to_node(db.upcast());
+            // Must have a name, otherwise we wouldn't emit it.
+            let name = node.name().expect("unimplemented builtin macro with no name");
+            acc.push(
+                UnimplementedBuiltinMacro {
+                    node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&name))),
+                }
+                .into(),
+            );
+        }
+        DefDiagnosticKind::InvalidDeriveTarget { ast, id } => {
+            let node = ast.to_node(db.upcast());
+            let derive = node.attrs().nth(*id as usize);
+            match derive {
+                Some(derive) => {
+                    acc.push(
+                        InvalidDeriveTarget {
+                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
+                        }
+                        .into(),
+                    );
+                }
+                None => stdx::never!("derive diagnostic on item without derive attribute"),
+            }
+        }
+        DefDiagnosticKind::MalformedDerive { ast, id } => {
+            let node = ast.to_node(db.upcast());
+            let derive = node.attrs().nth(*id as usize);
+            match derive {
+                Some(derive) => {
+                    acc.push(
+                        MalformedDerive {
+                            node: ast.with_value(SyntaxNodePtr::from(AstPtr::new(&derive))),
+                        }
+                        .into(),
+                    );
+                }
+                None => stdx::never!("derive diagnostic on item without derive attribute"),
+            }
+        }
+    }
+}
+
 impl HasVisibility for Module {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let def_map = self.id.def_map(db.upcast());
@@ -796,7 +789,7 @@ pub fn ty(&self, db: &dyn HirDatabase) -> Type {
             VariantDef::Variant(it) => it.parent.id.into(),
         };
         let substs = TyBuilder::type_params_subst(db, generic_def_id);
-        let ty = db.field_types(var_id)[self.id].clone().substitute(&Interner, &substs);
+        let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
         Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
     }
 
@@ -1100,7 +1093,14 @@ pub fn body_type(self, db: &dyn HirDatabase) -> Type {
     pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
         let krate = self.module(db).id.krate();
 
-        let source_map = db.body_with_source_map(self.into()).1;
+        let (body, source_map) = db.body_with_source_map(self.into());
+
+        for (_, def_map) in body.blocks(db.upcast()) {
+            for diag in def_map.diagnostics() {
+                emit_def_diagnostic(db, acc, diag);
+            }
+        }
+
         for diag in source_map.diagnostics() {
             match diag {
                 BodyDiagnostic::InactiveCode { node, cfg, opts } => acc.push(
@@ -1266,17 +1266,14 @@ pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
                             if let ast::Expr::MatchExpr(match_expr) =
                                 &source_ptr.value.to_node(&root)
                             {
-                                if let (Some(match_expr), Some(arms)) =
-                                    (match_expr.expr(), match_expr.match_arm_list())
-                                {
+                                if let Some(match_expr) = match_expr.expr() {
                                     acc.push(
                                         MissingMatchArms {
                                             file: source_ptr.file_id,
                                             match_expr: AstPtr::new(&match_expr),
-                                            arms: AstPtr::new(&arms),
                                         }
                                         .into(),
-                                    )
+                                    );
                                 }
                             }
                         }
@@ -1343,7 +1340,7 @@ pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param> {
             .params
             .iter()
             .enumerate()
-            .map(|(idx, type_ref)| {
+            .map(|(idx, (_, type_ref))| {
                 let ty = Type { krate, env: environment.clone(), ty: ctx.lower_ty(type_ref) };
                 Param { func: self, ty, idx }
             })
@@ -1421,6 +1418,10 @@ pub fn ty(&self) -> &Type {
         &self.ty
     }
 
+    pub fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
+        db.function_data(self.func.id).params[self.idx].0.clone()
+    }
+
     pub fn as_local(&self, db: &dyn HirDatabase) -> Local {
         let parent = DefWithBodyId::FunctionId(self.func.into());
         let body = db.body(parent);
@@ -1454,7 +1455,7 @@ pub fn access(self, db: &dyn HirDatabase) -> Access {
         func_data
             .params
             .first()
-            .map(|param| match &**param {
+            .map(|(_, param)| match &**param {
                 TypeRef::Reference(.., mutability) => match mutability {
                     hir_def::type_ref::Mutability::Shared => Access::Shared,
                     hir_def::type_ref::Mutability::Mut => Access::Exclusive,
@@ -1479,6 +1480,19 @@ pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
             .and_then(|params| params.self_param())
             .map(|value| InFile { file_id, value })
     }
+
+    pub fn ty(&self, db: &dyn HirDatabase) -> Type {
+        let resolver = self.func.resolver(db.upcast());
+        let krate = self.func.lookup(db.upcast()).container.module(db.upcast()).krate();
+        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
+        let environment = db.trait_environment(self.func.into());
+
+        Type {
+            krate,
+            env: environment.clone(),
+            ty: ctx.lower_ty(&db.function_data(self.func).params[0].1),
+        }
+    }
 }
 
 impl HasVisibility for Function {
@@ -1515,6 +1529,23 @@ pub fn ty(self, db: &dyn HirDatabase) -> Type {
         let ty = ctx.lower_ty(&data.type_ref);
         Type::new_with_resolver_inner(db, krate.id, &resolver, ty)
     }
+
+    pub fn eval(self, db: &dyn HirDatabase) -> Result<ComputedExpr, ConstEvalError> {
+        let body = db.body(self.id.into());
+        let root = &body.exprs[body.body_expr];
+        let infer = db.infer_query(self.id.into());
+        let infer = infer.as_ref();
+        let result = eval_const(
+            root,
+            &mut ConstEvalCtx {
+                exprs: &body.exprs,
+                pats: &body.pats,
+                local_data: HashMap::default(),
+                infer: &mut |x| infer[x].clone(),
+            },
+        );
+        result
+    }
 }
 
 impl HasVisibility for Const {
@@ -1569,6 +1600,12 @@ pub struct Trait {
 }
 
 impl Trait {
+    pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option<Trait> {
+        db.lang_item(krate.into(), name.to_smol_str())
+            .and_then(LangItemTarget::as_trait)
+            .map(Into::into)
+    }
+
     pub fn module(self, db: &dyn HirDatabase) -> Module {
         Module { id: self.id.lookup(db.upcast()).container }
     }
@@ -1651,6 +1688,26 @@ pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type {
     pub fn name(self) -> Name {
         self.inner.as_name()
     }
+
+    pub fn is_int(&self) -> bool {
+        matches!(self.inner, hir_def::builtin_type::BuiltinType::Int(_))
+    }
+
+    pub fn is_uint(&self) -> bool {
+        matches!(self.inner, hir_def::builtin_type::BuiltinType::Uint(_))
+    }
+
+    pub fn is_float(&self) -> bool {
+        matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
+    }
+
+    pub fn is_char(&self) -> bool {
+        matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
+    }
+
+    pub fn is_str(&self) -> bool {
+        matches!(self.inner, hir_def::builtin_type::BuiltinType::Str)
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -2030,37 +2087,75 @@ pub fn source(self, db: &dyn HirDatabase) -> InFile<Either<ast::IdentPat, ast::S
     }
 }
 
+// FIXME: Wrong name? This is could also be a registered attribute
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct BuiltinAttr(usize);
+pub struct BuiltinAttr {
+    krate: Option<CrateId>,
+    idx: usize,
+}
 
 impl BuiltinAttr {
-    pub(crate) fn by_name(name: &str) -> Option<Self> {
-        // FIXME: def maps registered attrs?
-        hir_def::builtin_attr::find_builtin_attr_idx(name).map(Self)
+    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
+    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
+        if let builtin @ Some(_) = Self::builtin(name) {
+            return builtin;
+        }
+        let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
+        Some(BuiltinAttr { krate: Some(krate.id), idx })
+    }
+
+    pub(crate) fn builtin(name: &str) -> Option<Self> {
+        hir_def::builtin_attr::INERT_ATTRIBUTES
+            .iter()
+            .position(|tool| tool.name == name)
+            .map(|idx| BuiltinAttr { krate: None, idx })
     }
 
-    pub fn name(&self, _: &dyn HirDatabase) -> &str {
+    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
         // FIXME: Return a `Name` here
-        hir_def::builtin_attr::INERT_ATTRIBUTES[self.0].name
+        match self.krate {
+            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
+            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
+        }
     }
 
-    pub fn template(&self, _: &dyn HirDatabase) -> AttributeTemplate {
-        hir_def::builtin_attr::INERT_ATTRIBUTES[self.0].template
+    pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
+        match self.krate {
+            Some(_) => None,
+            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
+        }
     }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
-pub struct ToolModule(usize);
+pub struct ToolModule {
+    krate: Option<CrateId>,
+    idx: usize,
+}
 
 impl ToolModule {
-    pub(crate) fn by_name(name: &str) -> Option<Self> {
-        // FIXME: def maps registered tools
-        hir_def::builtin_attr::TOOL_MODULES.iter().position(|&tool| tool == name).map(Self)
+    // FIXME: consider crates\hir_def\src\nameres\attr_resolution.rs?
+    pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
+        if let builtin @ Some(_) = Self::builtin(name) {
+            return builtin;
+        }
+        let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
+        Some(ToolModule { krate: Some(krate.id), idx })
     }
 
-    pub fn name(&self, _: &dyn HirDatabase) -> &str {
+    pub(crate) fn builtin(name: &str) -> Option<Self> {
+        hir_def::builtin_attr::TOOL_MODULES
+            .iter()
+            .position(|&tool| tool == name)
+            .map(|idx| ToolModule { krate: None, idx })
+    }
+
+    pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
         // FIXME: Return a `Name` here
-        hir_def::builtin_attr::TOOL_MODULES[self.0]
+        match self.krate {
+            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
+            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
+        }
     }
 }
 
@@ -2136,7 +2231,7 @@ pub fn module(self, db: &dyn HirDatabase) -> Module {
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
         let resolver = self.id.parent.resolver(db.upcast());
         let krate = self.id.parent.module(db.upcast()).krate();
-        let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id)).intern(&Interner);
+        let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id)).intern(Interner);
         Type::new_with_resolver_inner(db, krate, &resolver, ty)
     }
 
@@ -2159,7 +2254,7 @@ pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
         let krate = self.id.parent.module(db.upcast()).krate();
         let ty = params.get(local_idx)?.clone();
         let subst = TyBuilder::type_params_subst(db, self.id.parent);
-        let ty = ty.substitute(&Interner, &subst_prefix(&subst, local_idx));
+        let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
         Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
     }
 }
@@ -2381,31 +2476,31 @@ pub fn new_slice(ty: Type) -> Type {
     }
 
     pub fn is_unit(&self) -> bool {
-        matches!(self.ty.kind(&Interner), TyKind::Tuple(0, ..))
+        matches!(self.ty.kind(Interner), TyKind::Tuple(0, ..))
     }
 
     pub fn is_bool(&self) -> bool {
-        matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Bool))
+        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
     }
 
     pub fn is_never(&self) -> bool {
-        matches!(self.ty.kind(&Interner), TyKind::Never)
+        matches!(self.ty.kind(Interner), TyKind::Never)
     }
 
     pub fn is_mutable_reference(&self) -> bool {
-        matches!(self.ty.kind(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
+        matches!(self.ty.kind(Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
     }
 
     pub fn is_reference(&self) -> bool {
-        matches!(self.ty.kind(&Interner), TyKind::Ref(..))
+        matches!(self.ty.kind(Interner), TyKind::Ref(..))
     }
 
     pub fn is_usize(&self) -> bool {
-        matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
+        matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
     }
 
     pub fn remove_ref(&self) -> Option<Type> {
-        match &self.ty.kind(&Interner) {
+        match &self.ty.kind(Interner) {
             TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
             _ => None,
         }
@@ -2434,7 +2529,7 @@ pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
         };
 
         let canonical_ty =
-            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
+            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
         method_resolution::implements_trait(
             &canonical_ty,
             db,
@@ -2457,7 +2552,7 @@ pub fn impls_fnonce(&self, db: &dyn HirDatabase) -> bool {
         };
 
         let canonical_ty =
-            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
+            Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
         method_resolution::implements_trait_unique(
             &canonical_ty,
             db,
@@ -2474,8 +2569,8 @@ pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) ->
             .build();
 
         let goal = Canonical {
-            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(&Interner)),
-            binders: CanonicalVarKinds::empty(&Interner),
+            value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(Interner)),
+            binders: CanonicalVarKinds::empty(Interner),
         };
 
         db.trait_solve(self.krate, goal).is_some()
@@ -2497,9 +2592,9 @@ pub fn normalize_trait_assoc_type(
                 AliasEq {
                     alias: AliasTy::Projection(projection),
                     ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
-                        .intern(&Interner),
+                        .intern(Interner),
                 }
-                .cast(&Interner),
+                .cast(Interner),
             ),
             [TyVariableKind::General].into_iter(),
         );
@@ -2508,9 +2603,9 @@ pub fn normalize_trait_assoc_type(
             Solution::Unique(s) => s
                 .value
                 .subst
-                .as_slice(&Interner)
+                .as_slice(Interner)
                 .first()
-                .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
+                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
             Solution::Ambig(_) => None,
         }
     }
@@ -2532,15 +2627,19 @@ pub fn as_callable(&self, db: &dyn HirDatabase) -> Option<Callable> {
     }
 
     pub fn is_closure(&self) -> bool {
-        matches!(&self.ty.kind(&Interner), TyKind::Closure { .. })
+        matches!(&self.ty.kind(Interner), TyKind::Closure { .. })
     }
 
     pub fn is_fn(&self) -> bool {
-        matches!(&self.ty.kind(&Interner), TyKind::FnDef(..) | TyKind::Function { .. })
+        matches!(&self.ty.kind(Interner), TyKind::FnDef(..) | TyKind::Function { .. })
+    }
+
+    pub fn is_array(&self) -> bool {
+        matches!(&self.ty.kind(Interner), TyKind::Array(..))
     }
 
     pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
-        let adt_id = match *self.ty.kind(&Interner) {
+        let adt_id = match *self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
             _ => return false,
         };
@@ -2553,14 +2652,14 @@ pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
     }
 
     pub fn is_raw_ptr(&self) -> bool {
-        matches!(&self.ty.kind(&Interner), TyKind::Raw(..))
+        matches!(&self.ty.kind(Interner), TyKind::Raw(..))
     }
 
     pub fn contains_unknown(&self) -> bool {
         return go(&self.ty);
 
         fn go(ty: &Ty) -> bool {
-            match ty.kind(&Interner) {
+            match ty.kind(Interner) {
                 TyKind::Error => true,
 
                 TyKind::Adt(_, substs)
@@ -2569,7 +2668,7 @@ fn go(ty: &Ty) -> bool {
                 | TyKind::OpaqueType(_, substs)
                 | TyKind::FnDef(_, substs)
                 | TyKind::Closure(_, substs) => {
-                    substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
+                    substs.iter(Interner).filter_map(|a| a.ty(Interner)).any(go)
                 }
 
                 TyKind::Array(_ty, len) if len.is_unknown() => true,
@@ -2595,7 +2694,7 @@ fn go(ty: &Ty) -> bool {
     }
 
     pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
-        let (variant_id, substs) = match self.ty.kind(&Interner) {
+        let (variant_id, substs) = match self.ty.kind(Interner) {
             TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), substs) => ((*s).into(), substs),
             TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), substs) => ((*u).into(), substs),
             _ => return Vec::new(),
@@ -2605,17 +2704,17 @@ pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
             .iter()
             .map(|(local_id, ty)| {
                 let def = Field { parent: variant_id.into(), id: local_id };
-                let ty = ty.clone().substitute(&Interner, substs);
+                let ty = ty.clone().substitute(Interner, substs);
                 (def, self.derived(ty))
             })
             .collect()
     }
 
     pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
-        if let TyKind::Tuple(_, substs) = &self.ty.kind(&Interner) {
+        if let TyKind::Tuple(_, substs) = &self.ty.kind(Interner) {
             substs
-                .iter(&Interner)
-                .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone()))
+                .iter(Interner)
+                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone()))
                 .collect()
         } else {
             Vec::new()
@@ -2637,7 +2736,7 @@ pub fn autoderef_<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item =
     // This would be nicer if it just returned an iterator, but that runs into
     // lifetime problems, because we need to borrow temp `CrateImplDefs`.
     pub fn iterate_assoc_items<T>(
-        self,
+        &self,
         db: &dyn HirDatabase,
         krate: Crate,
         mut callback: impl FnMut(AssocItem) -> Option<T>,
@@ -2651,7 +2750,7 @@ pub fn iterate_assoc_items<T>(
     }
 
     fn iterate_assoc_items_dyn(
-        self,
+        &self,
         db: &dyn HirDatabase,
         krate: Crate,
         callback: &mut dyn FnMut(AssocItemId) -> bool,
@@ -2678,8 +2777,8 @@ pub fn type_arguments(&self) -> impl Iterator<Item = Type> + '_ {
             .strip_references()
             .as_adt()
             .into_iter()
-            .flat_map(|(_, substs)| substs.iter(&Interner))
-            .filter_map(|arg| arg.ty(&Interner).cloned())
+            .flat_map(|(_, substs)| substs.iter(Interner))
+            .filter_map(|arg| arg.ty(Interner).cloned())
             .map(move |ty| self.derived(ty))
     }
 
@@ -2688,15 +2787,18 @@ pub fn iterate_method_candidates<T>(
         db: &dyn HirDatabase,
         krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
+        with_local_impls: Option<Module>,
         name: Option<&Name>,
         mut callback: impl FnMut(Type, Function) -> Option<T>,
     ) -> Option<T> {
         let _p = profile::span("iterate_method_candidates");
         let mut slot = None;
+
         self.iterate_method_candidates_dyn(
             db,
             krate,
             traits_in_scope,
+            with_local_impls,
             name,
             &mut |ty, assoc_item_id| {
                 if let AssocItemId::FunctionId(func) = assoc_item_id {
@@ -2716,6 +2818,7 @@ fn iterate_method_candidates_dyn(
         db: &dyn HirDatabase,
         krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
+        with_local_impls: Option<Module>,
         name: Option<&Name>,
         callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
     ) {
@@ -2731,7 +2834,7 @@ fn iterate_method_candidates_dyn(
             env,
             krate,
             traits_in_scope,
-            None,
+            with_local_impls.and_then(|b| b.id.containing_block()).into(),
             name,
             method_resolution::LookupMode::MethodCall,
             &mut |ty, id| callback(&ty.value, id),
@@ -2743,6 +2846,7 @@ pub fn iterate_path_candidates<T>(
         db: &dyn HirDatabase,
         krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
+        with_local_impls: Option<Module>,
         name: Option<&Name>,
         mut callback: impl FnMut(Type, AssocItem) -> Option<T>,
     ) -> Option<T> {
@@ -2752,6 +2856,7 @@ pub fn iterate_path_candidates<T>(
             db,
             krate,
             traits_in_scope,
+            with_local_impls,
             name,
             &mut |ty, assoc_item_id| {
                 if let Some(res) = callback(self.derived(ty.clone()), assoc_item_id.into()) {
@@ -2769,6 +2874,7 @@ fn iterate_path_candidates_dyn(
         db: &dyn HirDatabase,
         krate: Crate,
         traits_in_scope: &FxHashSet<TraitId>,
+        with_local_impls: Option<Module>,
         name: Option<&Name>,
         callback: &mut dyn FnMut(&Ty, AssocItemId) -> ControlFlow<()>,
     ) {
@@ -2783,7 +2889,7 @@ fn iterate_path_candidates_dyn(
             env,
             krate,
             traits_in_scope,
-            None,
+            with_local_impls.and_then(|b| b.id.containing_block()).into(),
             name,
             method_resolution::LookupMode::Path,
             &mut |ty, id| callback(&ty.value, id),
@@ -2819,7 +2925,7 @@ pub fn applicable_inherent_traits<'a>(
     pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator<Item = Trait> + 'a {
         let _p = profile::span("env_traits");
         self.autoderef_(db)
-            .filter(|ty| matches!(ty.kind(&Interner), TyKind::Placeholder(_)))
+            .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_)))
             .flat_map(|ty| {
                 self.env
                     .traits_in_scope_from_clauses(ty)
@@ -2857,7 +2963,7 @@ fn walk_substs(
             substs: &Substitution,
             cb: &mut impl FnMut(Type),
         ) {
-            for ty in substs.iter(&Interner).filter_map(|a| a.ty(&Interner)) {
+            for ty in substs.iter(Interner).filter_map(|a| a.ty(Interner)) {
                 walk_type(db, &type_.derived(ty.clone()), cb);
             }
         }
@@ -2872,11 +2978,8 @@ fn walk_bounds(
                 if let WhereClause::Implemented(trait_ref) = pred.skip_binders() {
                     cb(type_.clone());
                     // skip the self type. it's likely the type we just got the bounds from
-                    for ty in trait_ref
-                        .substitution
-                        .iter(&Interner)
-                        .skip(1)
-                        .filter_map(|a| a.ty(&Interner))
+                    for ty in
+                        trait_ref.substitution.iter(Interner).skip(1).filter_map(|a| a.ty(Interner))
                     {
                         walk_type(db, &type_.derived(ty.clone()), cb);
                     }
@@ -2886,7 +2989,7 @@ fn walk_bounds(
 
         fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
             let ty = type_.ty.strip_references();
-            match ty.kind(&Interner) {
+            match ty.kind(Interner) {
                 TyKind::Adt(_, substs) => {
                     cb(type_.derived(ty.clone()));
                     walk_substs(db, type_, substs, cb);
@@ -3023,7 +3126,7 @@ pub fn return_type(&self) -> Type {
 }
 
 /// For IDE only
-#[derive(Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum ScopeDef {
     ModuleDef(ModuleDef),
     MacroDef(MacroDef),