diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index b5d63e8201..9825d52cfc 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -160,6 +160,7 @@ pub trait FilesDatabase: salsa::Database { /// Contents of the source root. #[salsa::input] fn source_root(&self, id: SourceRootId) -> Arc; + fn source_root_crates(&self, id: SourceRootId) -> Arc>; /// The set of "local" (that is, from the current workspace) roots. /// Files in local roots are assumed to change frequently. #[salsa::input] @@ -173,6 +174,17 @@ pub trait FilesDatabase: salsa::Database { fn crate_graph(&self) -> Arc; } +fn source_root_crates(db: &impl FilesDatabase, id: SourceRootId) -> Arc> { + let root = db.source_root(id); + let graph = db.crate_graph(); + let res = root + .files + .values() + .filter_map(|&it| graph.crate_id_for_crate_root(it)) + .collect::>(); + Arc::new(res) +} + #[cfg(test)] mod tests { use super::{CrateGraph, FileId, SmolStr}; diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 32d7e09b99..84759c75af 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -13,7 +13,7 @@ pub use crate::{ cancellation::Canceled, input::{ FilesDatabase, FileId, CrateId, SourceRoot, SourceRootId, CrateGraph, Dependency, - FileTextQuery, FileSourceRootQuery, SourceRootQuery, LocalRootsQuery, LibraryRootsQuery, CrateGraphQuery, + FileTextQuery, FileSourceRootQuery, SourceRootQuery, SourceRootCratesQuery, LocalRootsQuery, LibraryRootsQuery, CrateGraphQuery, FileRelativePathQuery }, loc2id::LocationIntener, diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs index ab1c428db7..6b13b464d2 100644 --- a/crates/ra_hir/src/adt.rs +++ b/crates/ra_hir/src/adt.rs @@ -3,25 +3,35 @@ use std::sync::Arc; -use ra_syntax::{ - SyntaxNode, - ast::{self, NameOwner, StructFlavor, AstNode} -}; +use ra_syntax::ast::{self, NameOwner, StructFlavor}; use crate::{ - DefId, DefLoc, Name, AsName, Struct, Enum, EnumVariant, - HirDatabase, DefKind, - SourceItemId, + Name, AsName, Struct, Enum, EnumVariant, Crate, + HirDatabase, type_ref::TypeRef, + ids::LocationCtx, }; -impl Struct { - pub(crate) fn new(def_id: DefId) -> Self { - Struct { def_id } - } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum AdtDef { + Struct(Struct), + Enum(Enum), +} +impl_froms!(AdtDef: Struct, Enum); +impl AdtDef { + pub(crate) fn krate(self, db: &impl HirDatabase) -> Option { + match self { + AdtDef::Struct(s) => s.module(db), + AdtDef::Enum(e) => e.module(db), + } + .krate(db) + } +} + +impl Struct { pub(crate) fn variant_data(&self, db: &impl HirDatabase) -> Arc { - db.struct_data(self.def_id).variant_data.clone() + db.struct_data((*self).into()).variant_data.clone() } } @@ -39,38 +49,12 @@ impl StructData { StructData { name, variant_data } } - pub(crate) fn struct_data_query(db: &impl HirDatabase, def_id: DefId) -> Arc { - let def_loc = def_id.loc(db); - assert!(def_loc.kind == DefKind::Struct); - let syntax = db.file_item(def_loc.source_item_id); - let struct_def = - ast::StructDef::cast(&syntax).expect("struct def should point to StructDef node"); - Arc::new(StructData::new(struct_def)) + pub(crate) fn struct_data_query(db: &impl HirDatabase, struct_: Struct) -> Arc { + let (_, struct_def) = struct_.source(db); + Arc::new(StructData::new(&*struct_def)) } } -fn get_def_id( - db: &impl HirDatabase, - same_file_loc: &DefLoc, - node: &SyntaxNode, - expected_kind: DefKind, -) -> DefId { - let file_id = same_file_loc.source_item_id.file_id; - let file_items = db.file_items(file_id); - - let item_id = file_items.id_of(file_id, node); - let source_item_id = SourceItemId { - item_id: Some(item_id), - ..same_file_loc.source_item_id - }; - let loc = DefLoc { - kind: expected_kind, - source_item_id, - ..*same_file_loc - }; - loc.id(db) -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct EnumData { pub(crate) name: Option, @@ -83,27 +67,24 @@ impl EnumData { EnumData { name, variants } } - pub(crate) fn enum_data_query(db: &impl HirDatabase, def_id: DefId) -> Arc { - let def_loc = def_id.loc(db); - assert!(def_loc.kind == DefKind::Enum); - let syntax = db.file_item(def_loc.source_item_id); - let enum_def = ast::EnumDef::cast(&syntax).expect("enum def should point to EnumDef node"); + pub(crate) fn enum_data_query(db: &impl HirDatabase, e: Enum) -> Arc { + let (file_id, enum_def) = e.source(db); + let module = e.module(db); + let ctx = LocationCtx::new(db, module, file_id); let variants = if let Some(vl) = enum_def.variant_list() { vl.variants() .filter_map(|variant_def| { - let name = variant_def.name().map(|n| n.as_name()); - - name.map(|n| { - let def_id = - get_def_id(db, &def_loc, variant_def.syntax(), DefKind::EnumVariant); - (n, EnumVariant::new(def_id)) - }) + let name = variant_def.name()?.as_name(); + let var = EnumVariant { + id: ctx.to_def(variant_def), + }; + Some((name, var)) }) .collect() } else { Vec::new() }; - Arc::new(EnumData::new(enum_def, variants)) + Arc::new(EnumData::new(&*enum_def, variants)) } } @@ -128,21 +109,15 @@ impl EnumVariantData { pub(crate) fn enum_variant_data_query( db: &impl HirDatabase, - def_id: DefId, + var: EnumVariant, ) -> Arc { - let def_loc = def_id.loc(db); - assert!(def_loc.kind == DefKind::EnumVariant); - let syntax = db.file_item(def_loc.source_item_id); - let variant_def = ast::EnumVariant::cast(&syntax) - .expect("enum variant def should point to EnumVariant node"); - let enum_node = syntax - .parent() - .expect("enum variant should have enum variant list ancestor") - .parent() - .expect("enum variant list should have enum ancestor"); - let enum_def_id = get_def_id(db, &def_loc, enum_node, DefKind::Enum); - - Arc::new(EnumVariantData::new(variant_def, Enum::new(enum_def_id))) + let (file_id, variant_def) = var.source(db); + let enum_def = variant_def.parent_enum(); + let ctx = LocationCtx::new(db, var.module(db), file_id); + let e = Enum { + id: ctx.to_def(enum_def), + }; + Arc::new(EnumVariantData::new(&*variant_def, e)) } } diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index 3ff07bd60c..6739627b4e 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -5,22 +5,23 @@ use ra_db::{CrateId, FileId}; use ra_syntax::{ast::self, TreeArc, SyntaxNode}; use crate::{ - Name, DefId, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId, + Name, Path, PerNs, ScopesWithSyntaxMapping, Ty, HirFileId, type_ref::TypeRef, nameres::{ModuleScope, lower::ImportId}, db::HirDatabase, expr::BodySyntaxMapping, - ty::InferenceResult, + ty::{InferenceResult, VariantDef}, adt::VariantData, generics::GenericParams, - code_model_impl::def_id_to_ast, - docs::{Documentation, Docs, docs_from_ast} + docs::{Documentation, Docs, docs_from_ast}, + module_tree::ModuleId, + ids::{FunctionId, StructId, EnumId, EnumVariantId, AstItemDef, ConstId, StaticId, TraitId, TypeId}, }; /// hir::Crate describes a single crate. It's the main interface with which /// a crate's dependencies interact. Mostly, it should be just a proxy for the /// root module. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Crate { pub(crate) crate_id: CrateId, } @@ -45,22 +46,40 @@ impl Crate { #[derive(Debug)] pub enum Def { + Item, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Module { + pub(crate) krate: CrateId, + pub(crate) module_id: ModuleId, +} + +/// The defs which can be visible in the module. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ModuleDef { Module(Module), + Function(Function), Struct(Struct), Enum(Enum), + // Can't be directly declared, but can be imported. EnumVariant(EnumVariant), - Function(Function), Const(Const), Static(Static), Trait(Trait), Type(Type), - Item, -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Module { - pub(crate) def_id: DefId, } +impl_froms!( + ModuleDef: Module, + Function, + Struct, + Enum, + EnumVariant, + Const, + Static, + Trait, + Type +); pub enum ModuleSource { SourceFile(TreeArc), @@ -149,7 +168,7 @@ impl Module { self.scope_impl(db) } - pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs { + pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs { self.resolve_path_impl(db, path) } @@ -160,7 +179,7 @@ impl Module { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StructField { - parent: DefId, + parent: VariantDef, name: Name, } @@ -174,38 +193,38 @@ impl StructField { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Struct { - pub(crate) def_id: DefId, + pub(crate) id: StructId, } impl Struct { - pub fn def_id(&self) -> DefId { - self.def_id + pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { + self.id.source(db) + } + + pub fn module(&self, db: &impl HirDatabase) -> Module { + self.id.module(db) } pub fn name(&self, db: &impl HirDatabase) -> Option { - db.struct_data(self.def_id).name.clone() + db.struct_data(*self).name.clone() } pub fn fields(&self, db: &impl HirDatabase) -> Vec { - db.struct_data(self.def_id) + db.struct_data(*self) .variant_data .fields() .iter() .map(|it| StructField { - parent: self.def_id, + parent: (*self).into(), name: it.name.clone(), }) .collect() } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) - } - pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params((*self).into()) } } @@ -215,34 +234,30 @@ impl Docs for Struct { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Enum { - pub(crate) def_id: DefId, + pub(crate) id: EnumId, } impl Enum { - pub(crate) fn new(def_id: DefId) -> Self { - Enum { def_id } + pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { + self.id.source(db) } - pub fn def_id(&self) -> DefId { - self.def_id + pub fn module(&self, db: &impl HirDatabase) -> Module { + self.id.module(db) } pub fn name(&self, db: &impl HirDatabase) -> Option { - db.enum_data(self.def_id).name.clone() + db.enum_data(*self).name.clone() } pub fn variants(&self, db: &impl HirDatabase) -> Vec<(Name, EnumVariant)> { - db.enum_data(self.def_id).variants.clone() - } - - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + db.enum_data(*self).variants.clone() } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params((*self).into()) } } @@ -252,30 +267,28 @@ impl Docs for Enum { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariant { - pub(crate) def_id: DefId, + pub(crate) id: EnumVariantId, } impl EnumVariant { - pub(crate) fn new(def_id: DefId) -> Self { - EnumVariant { def_id } + pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { + self.id.source(db) } - - pub fn def_id(&self) -> DefId { - self.def_id + pub fn module(&self, db: &impl HirDatabase) -> Module { + self.id.module(db) } - pub fn parent_enum(&self, db: &impl HirDatabase) -> Enum { - db.enum_variant_data(self.def_id).parent_enum.clone() + db.enum_variant_data(*self).parent_enum.clone() } pub fn name(&self, db: &impl HirDatabase) -> Option { - db.enum_variant_data(self.def_id).name.clone() + db.enum_variant_data(*self).name.clone() } pub fn variant_data(&self, db: &impl HirDatabase) -> Arc { - db.enum_variant_data(self.def_id).variant_data.clone() + db.enum_variant_data(*self).variant_data.clone() } pub fn fields(&self, db: &impl HirDatabase) -> Vec { @@ -283,15 +296,11 @@ impl EnumVariant { .fields() .iter() .map(|it| StructField { - parent: self.def_id, + parent: (*self).into(), name: it.name.clone(), }) .collect() } - - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) - } } impl Docs for EnumVariant { @@ -300,9 +309,9 @@ impl Docs for EnumVariant { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Function { - pub(crate) def_id: DefId, + pub(crate) id: FunctionId, } pub use crate::code_model_impl::function::ScopeEntryWithSyntax; @@ -339,21 +348,21 @@ impl FnSignature { } impl Function { - pub fn def_id(&self) -> DefId { - self.def_id + pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { + self.id.source(db) } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + pub fn module(&self, db: &impl HirDatabase) -> Module { + self.id.module(db) } pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Arc { - db.body_syntax_mapping(self.def_id) + db.body_syntax_mapping(*self) } pub fn scopes(&self, db: &impl HirDatabase) -> ScopesWithSyntaxMapping { - let scopes = db.fn_scopes(self.def_id); - let syntax_mapping = db.body_syntax_mapping(self.def_id); + let scopes = db.fn_scopes(*self); + let syntax_mapping = db.body_syntax_mapping(*self); ScopesWithSyntaxMapping { scopes, syntax_mapping, @@ -361,15 +370,15 @@ impl Function { } pub fn signature(&self, db: &impl HirDatabase) -> Arc { - db.fn_signature(self.def_id) + db.fn_signature(*self) } pub fn infer(&self, db: &impl HirDatabase) -> Arc { - db.infer(self.def_id) + db.infer(*self) } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params((*self).into()) } } @@ -379,18 +388,14 @@ impl Docs for Function { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Const { - pub(crate) def_id: DefId, + pub(crate) id: ConstId, } impl Const { - pub(crate) fn new(def_id: DefId) -> Const { - Const { def_id } - } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + self.id.source(db) } } @@ -400,18 +405,14 @@ impl Docs for Const { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Static { - pub(crate) def_id: DefId, + pub(crate) id: StaticId, } impl Static { - pub(crate) fn new(def_id: DefId) -> Static { - Static { def_id } - } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + self.id.source(db) } } @@ -421,22 +422,18 @@ impl Docs for Static { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Trait { - pub(crate) def_id: DefId, + pub(crate) id: TraitId, } impl Trait { - pub(crate) fn new(def_id: DefId) -> Trait { - Trait { def_id } - } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + self.id.source(db) } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params((*self).into()) } } @@ -446,22 +443,18 @@ impl Docs for Trait { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Type { - pub(crate) def_id: DefId, + pub(crate) id: TypeId, } impl Type { - pub(crate) fn new(def_id: DefId) -> Type { - Type { def_id } - } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + self.id.source(db) } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params((*self).into()) } } diff --git a/crates/ra_hir/src/code_model_impl.rs b/crates/ra_hir/src/code_model_impl.rs index 0cea9f7b6f..1f28fab748 100644 --- a/crates/ra_hir/src/code_model_impl.rs +++ b/crates/ra_hir/src/code_model_impl.rs @@ -1,18 +1,3 @@ mod krate; // `crate` is invalid ident :( mod module; pub(crate) mod function; - -use ra_syntax::{AstNode, TreeArc}; - -use crate::{HirDatabase, DefId, HirFileId}; - -pub(crate) fn def_id_to_ast( - db: &impl HirDatabase, - def_id: DefId, -) -> (HirFileId, TreeArc) { - let (file_id, syntax) = def_id.source(db); - let ast = N::cast(&syntax) - .unwrap_or_else(|| panic!("def points to wrong source {:?} {:?}", def_id, syntax)) - .to_owned(); - (file_id, ast) -} diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs index c68c6bfbf0..e0dd4d6290 100644 --- a/crates/ra_hir/src/code_model_impl/function.rs +++ b/crates/ra_hir/src/code_model_impl/function.rs @@ -2,41 +2,32 @@ mod scope; use std::sync::Arc; -use ra_syntax::{TreeArc, ast::{self, NameOwner}}; +use ra_syntax::ast::{self, NameOwner}; use crate::{ - DefId, HirDatabase, Name, AsName, Function, FnSignature, Module, + HirDatabase, Name, AsName, Function, FnSignature, type_ref::{TypeRef, Mutability}, expr::Body, impl_block::ImplBlock, - code_model_impl::def_id_to_ast, }; pub use self::scope::{FnScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax}; impl Function { - pub(crate) fn new(def_id: DefId) -> Function { - Function { def_id } - } - pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc { - db.body_hir(self.def_id) - } - - pub(crate) fn module(&self, db: &impl HirDatabase) -> Module { - self.def_id.module(db) + db.body_hir(*self) } /// The containing impl block, if this is a method. pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option { - self.def_id.impl_block(db) + let module_impls = db.impls_in_module(self.module(db)); + ImplBlock::containing(module_impls, (*self).into()) } } impl FnSignature { - pub(crate) fn fn_signature_query(db: &impl HirDatabase, def_id: DefId) -> Arc { - // FIXME: we're using def_id_to_ast here to avoid returning Cancelable... this is a bit hacky - let node: TreeArc = def_id_to_ast(db, def_id).1; + pub(crate) fn fn_signature_query(db: &impl HirDatabase, func: Function) -> Arc { + let (_, node) = func.source(db); let name = node .name() .map(|n| n.as_name()) diff --git a/crates/ra_hir/src/code_model_impl/krate.rs b/crates/ra_hir/src/code_model_impl/krate.rs index 8c6e34873b..cdd30b402c 100644 --- a/crates/ra_hir/src/code_model_impl/krate.rs +++ b/crates/ra_hir/src/code_model_impl/krate.rs @@ -1,7 +1,7 @@ use ra_db::CrateId; use crate::{ - HirFileId, Crate, CrateDependency, AsName, DefLoc, DefKind, Module, SourceItemId, + Crate, CrateDependency, AsName, Module, db::HirDatabase, }; @@ -21,27 +21,13 @@ impl Crate { .collect() } pub(crate) fn root_module_impl(&self, db: &impl HirDatabase) -> Option { - let crate_graph = db.crate_graph(); - let file_id = crate_graph.crate_root(self.crate_id); - let source_root_id = db.file_source_root(file_id); - let file_id = HirFileId::from(file_id); - let module_tree = db.module_tree(source_root_id); - // FIXME: teach module tree about crate roots instead of guessing - let source = SourceItemId { - file_id, - item_id: None, - }; - let module_id = module_tree.find_module_by_source(source)?; + let module_tree = db.module_tree(self.crate_id); + let module_id = module_tree.modules().next()?; - let def_loc = DefLoc { - kind: DefKind::Module, - source_root_id, + let module = Module { + krate: self.crate_id, module_id, - source_item_id: module_id.source(&module_tree), }; - let def_id = def_loc.id(db); - - let module = Module::new(def_id); Some(module) } } diff --git a/crates/ra_hir/src/code_model_impl/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index d94079f11c..6419d3934c 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs @@ -1,52 +1,33 @@ -use ra_db::{SourceRootId, FileId}; -use ra_syntax::{ast, SyntaxNode, AstNode, TreeArc}; +use ra_db::FileId; +use ra_syntax::{ast, SyntaxNode, TreeArc}; use crate::{ - Module, ModuleSource, Problem, - Crate, DefId, DefLoc, DefKind, Name, Path, PathKind, PerNs, Def, + Module, ModuleSource, Problem, ModuleDef, + Crate, Name, Path, PathKind, PerNs, module_tree::ModuleId, nameres::{ModuleScope, lower::ImportId}, db::HirDatabase, }; impl Module { - pub(crate) fn new(def_id: DefId) -> Self { - crate::code_model_api::Module { def_id } - } - - pub(crate) fn from_module_id( - db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, - ) -> Self { - let module_tree = db.module_tree(source_root_id); - let def_loc = DefLoc { - kind: DefKind::Module, - source_root_id, + fn with_module_id(&self, module_id: ModuleId) -> Module { + Module { module_id, - source_item_id: module_id.source(&module_tree), - }; - let def_id = def_loc.id(db); - Module::new(def_id) + krate: self.krate, + } } pub(crate) fn name_impl(&self, db: &impl HirDatabase) -> Option { - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - let link = loc.module_id.parent_link(&module_tree)?; + let module_tree = db.module_tree(self.krate); + let link = self.module_id.parent_link(&module_tree)?; Some(link.name(&module_tree).clone()) } pub(crate) fn definition_source_impl(&self, db: &impl HirDatabase) -> (FileId, ModuleSource) { - let loc = self.def_id.loc(db); - let file_id = loc.source_item_id.file_id.as_original_file(); - let syntax_node = db.file_item(loc.source_item_id); - let module_source = if let Some(source_file) = ast::SourceFile::cast(&syntax_node) { - ModuleSource::SourceFile(source_file.to_owned()) - } else { - let module = ast::Module::cast(&syntax_node).unwrap(); - ModuleSource::Module(module.to_owned()) - }; + let module_tree = db.module_tree(self.krate); + let source = self.module_id.source(&module_tree); + let module_source = ModuleSource::from_source_item_id(db, source); + let file_id = source.file_id.as_original_file(); (file_id, module_source) } @@ -54,9 +35,8 @@ impl Module { &self, db: &impl HirDatabase, ) -> Option<(FileId, TreeArc)> { - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - let link = loc.module_id.parent_link(&module_tree)?; + let module_tree = db.module_tree(self.krate); + let link = self.module_id.parent_link(&module_tree)?; let file_id = link .owner(&module_tree) .source(&module_tree) @@ -71,85 +51,67 @@ impl Module { db: &impl HirDatabase, import: ImportId, ) -> TreeArc { - let loc = self.def_id.loc(db); - let source_map = db.lower_module_source_map(loc.source_root_id, loc.module_id); + let source_map = db.lower_module_source_map(self.clone()); let (_, source) = self.definition_source(db); source_map.get(&source, import) } - pub(crate) fn krate_impl(&self, db: &impl HirDatabase) -> Option { - let root = self.crate_root(db); - let loc = root.def_id.loc(db); - let file_id = loc.source_item_id.file_id.as_original_file(); - - let crate_graph = db.crate_graph(); - let crate_id = crate_graph.crate_id_for_crate_root(file_id)?; - Some(Crate::new(crate_id)) + pub(crate) fn krate_impl(&self, _db: &impl HirDatabase) -> Option { + Some(Crate::new(self.krate)) } pub(crate) fn crate_root_impl(&self, db: &impl HirDatabase) -> Module { - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - let module_id = loc.module_id.crate_root(&module_tree); - Module::from_module_id(db, loc.source_root_id, module_id) + let module_tree = db.module_tree(self.krate); + let module_id = self.module_id.crate_root(&module_tree); + self.with_module_id(module_id) } /// Finds a child module with the specified name. pub(crate) fn child_impl(&self, db: &impl HirDatabase, name: &Name) -> Option { - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - let child_id = loc.module_id.child(&module_tree, name)?; - Some(Module::from_module_id(db, loc.source_root_id, child_id)) + let module_tree = db.module_tree(self.krate); + let child_id = self.module_id.child(&module_tree, name)?; + Some(self.with_module_id(child_id)) } /// Iterates over all child modules. pub(crate) fn children_impl(&self, db: &impl HirDatabase) -> impl Iterator { - // FIXME this should be implementable without collecting into a vec, but - // it's kind of hard since the iterator needs to keep a reference to the - // module tree. - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - let children = loc + let module_tree = db.module_tree(self.krate); + let children = self .module_id .children(&module_tree) - .map(|(_, module_id)| Module::from_module_id(db, loc.source_root_id, module_id)) + .map(|(_, module_id)| self.with_module_id(module_id)) .collect::>(); children.into_iter() } pub(crate) fn parent_impl(&self, db: &impl HirDatabase) -> Option { - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - let parent_id = loc.module_id.parent(&module_tree)?; - Some(Module::from_module_id(db, loc.source_root_id, parent_id)) + let module_tree = db.module_tree(self.krate); + let parent_id = self.module_id.parent(&module_tree)?; + Some(self.with_module_id(parent_id)) } /// Returns a `ModuleScope`: a set of items, visible in this module. pub(crate) fn scope_impl(&self, db: &impl HirDatabase) -> ModuleScope { - let loc = self.def_id.loc(db); - let item_map = db.item_map(loc.source_root_id); - item_map.per_module[&loc.module_id].clone() + let item_map = db.item_map(self.krate); + item_map.per_module[&self.module_id].clone() } - pub(crate) fn resolve_path_impl(&self, db: &impl HirDatabase, path: &Path) -> PerNs { - let mut curr_per_ns = PerNs::types( - match path.kind { - PathKind::Crate => self.crate_root(db), - PathKind::Self_ | PathKind::Plain => self.clone(), - PathKind::Super => { - if let Some(p) = self.parent(db) { - p - } else { - return PerNs::none(); - } - } - PathKind::Abs => { - // TODO: absolute use is not supported + pub(crate) fn resolve_path_impl(&self, db: &impl HirDatabase, path: &Path) -> PerNs { + let mut curr_per_ns: PerNs = PerNs::types(match path.kind { + PathKind::Crate => self.crate_root(db).into(), + PathKind::Self_ | PathKind::Plain => self.clone().into(), + PathKind::Super => { + if let Some(p) = self.parent(db) { + p.into() + } else { return PerNs::none(); } } - .def_id, - ); + PathKind::Abs => { + // TODO: absolute use is not supported + return PerNs::none(); + } + }); for segment in path.segments.iter() { let curr = match curr_per_ns.as_ref().take_types() { @@ -164,15 +126,16 @@ impl Module { } }; // resolve segment in curr - curr_per_ns = match curr.resolve(db) { - Def::Module(m) => { + + curr_per_ns = match curr { + ModuleDef::Module(m) => { let scope = m.scope(db); match scope.get(&segment.name) { - Some(r) => r.def_id, + Some(r) => r.def_id.clone(), None => PerNs::none(), } } - Def::Enum(e) => { + ModuleDef::Enum(e) => { // enum variant let matching_variant = e .variants(db) @@ -180,7 +143,7 @@ impl Module { .find(|(n, _variant)| n == &segment.name); match matching_variant { - Some((_n, variant)) => PerNs::both(variant.def_id(), e.def_id()), + Some((_n, variant)) => PerNs::both(variant.into(), (*e).into()), None => PerNs::none(), } } @@ -199,8 +162,7 @@ impl Module { &self, db: &impl HirDatabase, ) -> Vec<(TreeArc, Problem)> { - let loc = self.def_id.loc(db); - let module_tree = db.module_tree(loc.source_root_id); - loc.module_id.problems(&module_tree, db) + let module_tree = db.module_tree(self.krate); + self.module_id.problems(&module_tree, db) } } diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index cc03da1e25..5304f5d313 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -1,20 +1,21 @@ use std::sync::Arc; use ra_syntax::{SyntaxNode, TreeArc, SourceFile}; -use ra_db::{SourceRootId, SyntaxDatabase, salsa}; +use ra_db::{SyntaxDatabase, CrateId, salsa}; use crate::{ - HirInterner, DefId, MacroCallId, Name, HirFileId, - SourceFileItems, SourceItemId, Crate, + MacroCallId, Name, HirFileId, + SourceFileItems, SourceItemId, Crate, Module, HirInterner, query_definitions, - FnSignature, FnScopes, + Function, FnSignature, FnScopes, + Struct, Enum, EnumVariant, macros::MacroExpansion, - module_tree::{ModuleId, ModuleTree}, + module_tree::ModuleTree, nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, - ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks}, + ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, VariantDef}, adt::{StructData, EnumData, EnumVariantData}, impl_block::ModuleImplBlocks, - generics::GenericParams, + generics::{GenericParams, GenericDef}, }; #[salsa::query_group] @@ -26,25 +27,25 @@ pub trait HirDatabase: SyntaxDatabase + AsRef { fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option>; #[salsa::invoke(query_definitions::fn_scopes)] - fn fn_scopes(&self, def_id: DefId) -> Arc; + fn fn_scopes(&self, func: Function) -> Arc; #[salsa::invoke(crate::adt::StructData::struct_data_query)] - fn struct_data(&self, def_id: DefId) -> Arc; + fn struct_data(&self, s: Struct) -> Arc; #[salsa::invoke(crate::adt::EnumData::enum_data_query)] - fn enum_data(&self, def_id: DefId) -> Arc; + fn enum_data(&self, e: Enum) -> Arc; #[salsa::invoke(crate::adt::EnumVariantData::enum_variant_data_query)] - fn enum_variant_data(&self, def_id: DefId) -> Arc; + fn enum_variant_data(&self, var: EnumVariant) -> Arc; #[salsa::invoke(crate::ty::infer)] - fn infer(&self, def_id: DefId) -> Arc; + fn infer(&self, func: Function) -> Arc; #[salsa::invoke(crate::ty::type_for_def)] - fn type_for_def(&self, def_id: DefId) -> Ty; + fn type_for_def(&self, def: TypableDef) -> Ty; #[salsa::invoke(crate::ty::type_for_field)] - fn type_for_field(&self, def_id: DefId, field: Name) -> Option; + fn type_for_field(&self, def: VariantDef, field: Name) -> Option; #[salsa::invoke(query_definitions::file_items)] fn file_items(&self, file_id: HirFileId) -> Arc; @@ -56,51 +57,35 @@ pub trait HirDatabase: SyntaxDatabase + AsRef { fn submodules(&self, source: SourceItemId) -> Arc>; #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)] - fn lower_module( - &self, - source_root_id: SourceRootId, - module_id: ModuleId, - ) -> (Arc, Arc); + fn lower_module(&self, module: Module) -> (Arc, Arc); #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_module_query)] - fn lower_module_module( - &self, - source_root_id: SourceRootId, - module_id: ModuleId, - ) -> Arc; + fn lower_module_module(&self, module: Module) -> Arc; #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_source_map_query)] - fn lower_module_source_map( - &self, - source_root_id: SourceRootId, - module_id: ModuleId, - ) -> Arc; + fn lower_module_source_map(&self, module: Module) -> Arc; #[salsa::invoke(query_definitions::item_map)] - fn item_map(&self, source_root_id: SourceRootId) -> Arc; + fn item_map(&self, crate_id: CrateId) -> Arc; #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)] - fn module_tree(&self, source_root_id: SourceRootId) -> Arc; + fn module_tree(&self, crate_id: CrateId) -> Arc; #[salsa::invoke(crate::impl_block::impls_in_module)] - fn impls_in_module( - &self, - source_root_id: SourceRootId, - module_id: ModuleId, - ) -> Arc; + fn impls_in_module(&self, module: Module) -> Arc; #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] fn impls_in_crate(&self, krate: Crate) -> Arc; #[salsa::invoke(crate::expr::body_hir)] - fn body_hir(&self, def_id: DefId) -> Arc; + fn body_hir(&self, func: Function) -> Arc; #[salsa::invoke(crate::expr::body_syntax_mapping)] - fn body_syntax_mapping(&self, def_id: DefId) -> Arc; + fn body_syntax_mapping(&self, func: Function) -> Arc; #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] - fn generic_params(&self, def_id: DefId) -> Arc; + fn generic_params(&self, def: GenericDef) -> Arc; #[salsa::invoke(crate::FnSignature::fn_signature_query)] - fn fn_signature(&self, def_id: DefId) -> Arc; + fn fn_signature(&self, func: Function) -> Arc; } diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 1a38216922..29469af2cf 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -9,7 +9,11 @@ use ra_syntax::{ ast::{self, LoopBodyOwner, ArgListOwner, NameOwner, LiteralFlavor} }; -use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName}; +use crate::{ + Path, Name, HirDatabase, Function, + name::AsName, + type_ref::{Mutability, TypeRef}, +}; use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -435,8 +439,8 @@ impl Pat { // Queries -pub(crate) fn body_hir(db: &impl HirDatabase, def_id: DefId) -> Arc { - Arc::clone(&body_syntax_mapping(db, def_id).body) +pub(crate) fn body_hir(db: &impl HirDatabase, func: Function) -> Arc { + Arc::clone(&body_syntax_mapping(db, func).body) } struct ExprCollector { @@ -955,14 +959,8 @@ pub(crate) fn collect_fn_body_syntax(node: &ast::FnDef) -> BodySyntaxMapping { collector.into_body_syntax_mapping(params, body) } -pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, def_id: DefId) -> Arc { - let def = def_id.resolve(db); - - let body_syntax_mapping = match def { - Def::Function(f) => collect_fn_body_syntax(&f.source(db).1), - // TODO: consts, etc. - _ => panic!("Trying to get body for item type without body"), - }; - +pub(crate) fn body_syntax_mapping(db: &impl HirDatabase, func: Function) -> Arc { + let (_, fn_def) = func.source(db); + let body_syntax_mapping = collect_fn_body_syntax(&fn_def); Arc::new(body_syntax_mapping) } diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index d8248ad491..64c20a4622 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -5,9 +5,9 @@ use std::sync::Arc; -use ra_syntax::ast::{TypeParamList, AstNode, NameOwner}; +use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; -use crate::{db::HirDatabase, DefId, Name, AsName}; +use crate::{db::HirDatabase, Name, AsName, Function, Struct, Enum, Trait, Type}; /// Data about a generic parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug)] @@ -22,26 +22,53 @@ pub struct GenericParams { pub(crate) params: Vec, } +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum GenericDef { + Function(Function), + Struct(Struct), + Enum(Enum), + Trait(Trait), + Type(Type), +} +impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type); + impl GenericParams { - pub(crate) fn generic_params_query(db: &impl HirDatabase, def_id: DefId) -> Arc { - let (_file_id, node) = def_id.source(db); + pub(crate) fn generic_params_query( + db: &impl HirDatabase, + def: GenericDef, + ) -> Arc { let mut generics = GenericParams::default(); - if let Some(type_param_list) = node.children().find_map(TypeParamList::cast) { - for (idx, type_param) in type_param_list.type_params().enumerate() { - let name = type_param - .name() - .map(AsName::as_name) - .unwrap_or_else(Name::missing); - let param = GenericParam { - idx: idx as u32, - name, - }; - generics.params.push(param); - } + match def { + GenericDef::Function(it) => generics.fill(&*it.source(db).1), + GenericDef::Struct(it) => generics.fill(&*it.source(db).1), + GenericDef::Enum(it) => generics.fill(&*it.source(db).1), + GenericDef::Trait(it) => generics.fill(&*it.source(db).1), + GenericDef::Type(it) => generics.fill(&*it.source(db).1), } + Arc::new(generics) } + fn fill(&mut self, node: &impl TypeParamsOwner) { + if let Some(params) = node.type_param_list() { + self.fill_params(params) + } + } + + fn fill_params(&mut self, params: &ast::TypeParamList) { + for (idx, type_param) in params.type_params().enumerate() { + let name = type_param + .name() + .map(AsName::as_name) + .unwrap_or_else(Name::missing); + let param = GenericParam { + idx: idx as u32, + name, + }; + self.params.push(param); + } + } + pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { self.params.iter().find(|p| &p.name == name) } diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index 43f0e81f9f..b125a15184 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -1,22 +1,41 @@ -use ra_db::{SourceRootId, LocationIntener, FileId}; +use std::{ + marker::PhantomData, + hash::{Hash, Hasher}, +}; + +use ra_db::{LocationIntener, FileId}; use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; -use ra_arena::{Arena, RawId, impl_arena_id}; +use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; use crate::{ - HirDatabase, Def, Function, Struct, Enum, EnumVariant, ImplBlock, Crate, - Module, Trait, Type, Static, Const, - module_tree::ModuleId, + HirDatabase, + Module, }; #[derive(Debug, Default)] pub struct HirInterner { - defs: LocationIntener, macros: LocationIntener, + fns: LocationIntener, FunctionId>, + structs: LocationIntener, StructId>, + enums: LocationIntener, EnumId>, + enum_variants: LocationIntener, EnumVariantId>, + consts: LocationIntener, ConstId>, + statics: LocationIntener, StaticId>, + traits: LocationIntener, TraitId>, + types: LocationIntener, TypeId>, } impl HirInterner { pub fn len(&self) -> usize { - self.defs.len() + self.macros.len() + self.macros.len() + + self.fns.len() + + self.structs.len() + + self.enums.len() + + self.enum_variants.len() + + self.consts.len() + + self.statics.len() + + self.traits.len() + + self.types.len() } } @@ -110,10 +129,9 @@ impl From for HirFileId { pub struct MacroCallId(RawId); impl_arena_id!(MacroCallId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct MacroCallLoc { - pub(crate) source_root_id: SourceRootId, - pub(crate) module_id: ModuleId, + pub(crate) module: Module, pub(crate) source_item_id: SourceItemId, } @@ -130,117 +148,161 @@ impl MacroCallLoc { } } -/// Def's are a core concept of hir. A `Def` is an Item (function, module, etc) -/// in a specific module. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct DefId(RawId); -impl_arena_id!(DefId); - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct DefLoc { - pub(crate) kind: DefKind, - pub(crate) source_root_id: SourceRootId, - pub(crate) module_id: ModuleId, - pub(crate) source_item_id: SourceItemId, +#[derive(Debug)] +pub struct ItemLoc { + pub(crate) module: Module, + raw: SourceItemId, + _ty: PhantomData, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub(crate) enum DefKind { - Module, - Function, - Struct, - Enum, - EnumVariant, - Const, - Static, - Trait, - Type, - Item, - - /// The constructor of a struct. E.g. if we have `struct Foo(usize)`, the - /// name `Foo` needs to resolve to different types depending on whether we - /// are in the types or values namespace: As a type, `Foo` of course refers - /// to the struct `Foo`; as a value, `Foo` is a callable type with signature - /// `(usize) -> Foo`. The cleanest approach to handle this seems to be to - /// have different defs in the two namespaces. - /// - /// rustc does the same; note that it even creates a struct constructor if - /// the struct isn't a tuple struct (see `CtorKind::Fictive` in rustc). - StructCtor, -} - -impl DefId { - pub(crate) fn loc(self, db: &impl AsRef) -> DefLoc { - db.as_ref().defs.id2loc(self) +impl PartialEq for ItemLoc { + fn eq(&self, other: &Self) -> bool { + self.module == other.module && self.raw == other.raw } +} +impl Eq for ItemLoc {} +impl Hash for ItemLoc { + fn hash(&self, hasher: &mut H) { + self.module.hash(hasher); + self.raw.hash(hasher); + } +} - pub fn resolve(self, db: &impl HirDatabase) -> Def { - let loc = self.loc(db); - match loc.kind { - DefKind::Module => { - let module = Module::from_module_id(db, loc.source_root_id, loc.module_id); - Def::Module(module) - } - DefKind::Function => { - let function = Function::new(self); - Def::Function(function) - } - DefKind::Struct => { - let struct_def = Struct::new(self); - Def::Struct(struct_def) - } - DefKind::Enum => Def::Enum(Enum::new(self)), - DefKind::EnumVariant => Def::EnumVariant(EnumVariant::new(self)), - DefKind::Const => { - let def = Const::new(self); - Def::Const(def) - } - DefKind::Static => { - let def = Static::new(self); - Def::Static(def) - } - DefKind::Trait => { - let def = Trait::new(self); - Def::Trait(def) - } - DefKind::Type => { - let def = Type::new(self); - Def::Type(def) - } - - DefKind::StructCtor => Def::Item, - DefKind::Item => Def::Item, +impl Clone for ItemLoc { + fn clone(&self) -> ItemLoc { + ItemLoc { + module: self.module, + raw: self.raw, + _ty: PhantomData, } } +} - pub(crate) fn source(self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - let loc = self.loc(db); - let syntax = db.file_item(loc.source_item_id); - (loc.source_item_id.file_id, syntax) +#[derive(Clone, Copy)] +pub(crate) struct LocationCtx { + db: DB, + module: Module, + file_id: HirFileId, +} + +impl<'a, DB: HirDatabase> LocationCtx<&'a DB> { + pub(crate) fn new(db: &'a DB, module: Module, file_id: HirFileId) -> LocationCtx<&'a DB> { + LocationCtx { + db, + module, + file_id, + } } - - /// For a module, returns that module; for any other def, returns the containing module. - pub fn module(self, db: &impl HirDatabase) -> Module { - let loc = self.loc(db); - Module::from_module_id(db, loc.source_root_id, loc.module_id) - } - - /// Returns the containing crate. - pub fn krate(&self, db: &impl HirDatabase) -> Option { - self.module(db).krate(db) - } - - /// Returns the containing impl block, if this is an impl item. - pub fn impl_block(self, db: &impl HirDatabase) -> Option { - let loc = self.loc(db); - let module_impls = db.impls_in_module(loc.source_root_id, loc.module_id); - ImplBlock::containing(module_impls, self) + pub(crate) fn to_def(self, ast: &N) -> DEF + where + N: AstNode, + DEF: AstItemDef, + { + DEF::from_ast(self, ast) } } -impl DefLoc { - pub(crate) fn id(&self, db: &impl AsRef) -> DefId { - db.as_ref().defs.loc2id(&self) +pub(crate) trait AstItemDef: ArenaId + Clone { + fn interner(interner: &HirInterner) -> &LocationIntener, Self>; + fn from_ast(ctx: LocationCtx<&impl HirDatabase>, ast: &N) -> Self { + let items = ctx.db.file_items(ctx.file_id); + let raw = SourceItemId { + file_id: ctx.file_id, + item_id: Some(items.id_of(ctx.file_id, ast.syntax())), + }; + let loc = ItemLoc { + module: ctx.module, + raw, + _ty: PhantomData, + }; + + Self::interner(ctx.db.as_ref()).loc2id(&loc) + } + fn source(self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { + let int = Self::interner(db.as_ref()); + let loc = int.id2loc(self); + let syntax = db.file_item(loc.raw); + let ast = N::cast(&syntax) + .unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)) + .to_owned(); + (loc.raw.file_id, ast) + } + fn module(self, db: &impl HirDatabase) -> Module { + let int = Self::interner(db.as_ref()); + let loc = int.id2loc(self); + loc.module + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct FunctionId(RawId); +impl_arena_id!(FunctionId); +impl AstItemDef for FunctionId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.fns + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct StructId(RawId); +impl_arena_id!(StructId); +impl AstItemDef for StructId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.structs + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EnumId(RawId); +impl_arena_id!(EnumId); +impl AstItemDef for EnumId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.enums + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct EnumVariantId(RawId); +impl_arena_id!(EnumVariantId); +impl AstItemDef for EnumVariantId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.enum_variants + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ConstId(RawId); +impl_arena_id!(ConstId); +impl AstItemDef for ConstId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.consts + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct StaticId(RawId); +impl_arena_id!(StaticId); +impl AstItemDef for StaticId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.statics + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TraitId(RawId); +impl_arena_id!(TraitId); +impl AstItemDef for TraitId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.traits + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct TypeId(RawId); +impl_arena_id!(TypeId); +impl AstItemDef for TypeId { + fn interner(interner: &HirInterner) -> &LocationIntener, Self> { + &interner.types } } diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index 551d0d149d..222e473491 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -3,14 +3,13 @@ use rustc_hash::FxHashMap; use ra_arena::{Arena, RawId, impl_arena_id}; use ra_syntax::ast::{self, AstNode}; -use ra_db::{SourceRootId}; use crate::{ - DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, - Function, HirInterner, + Const, Type, + Function, HirFileId, db::HirDatabase, type_ref::TypeRef, - module_tree::ModuleId, + ids::LocationCtx, }; use crate::code_model_api::{Module, ModuleSource}; @@ -24,9 +23,9 @@ pub struct ImplBlock { impl ImplBlock { pub(crate) fn containing( module_impl_blocks: Arc, - def_id: DefId, + item: ImplItem, ) -> Option { - let impl_id = *module_impl_blocks.impls_by_def.get(&def_id)?; + let impl_id = *module_impl_blocks.impls_by_def.get(&item)?; Some(ImplBlock { module_impl_blocks, impl_id, @@ -66,39 +65,25 @@ pub struct ImplData { impl ImplData { pub(crate) fn from_ast( - db: &impl AsRef, - file_items: &SourceFileItems, - module: &Module, + db: &impl HirDatabase, + file_id: HirFileId, + module: Module, node: &ast::ImplBlock, ) -> Self { let target_trait = node.target_trait().map(TypeRef::from_ast); let target_type = TypeRef::from_ast_opt(node.target_type()); - let module_loc = module.def_id.loc(db); + let ctx = LocationCtx::new(db, module, file_id); let items = if let Some(item_list) = node.item_list() { item_list .impl_items() - .map(|item_node| { - let kind = match item_node.kind() { - ast::ImplItemKind::FnDef(..) => DefKind::Function, - ast::ImplItemKind::ConstDef(..) => DefKind::Item, - ast::ImplItemKind::TypeDef(..) => DefKind::Item, - }; - let item_id = file_items.id_of_unchecked(item_node.syntax()); - let source_item_id = SourceItemId { - file_id: module_loc.source_item_id.file_id, - item_id: Some(item_id), - }; - let def_loc = DefLoc { - kind, - source_item_id, - ..module_loc - }; - let def_id = def_loc.id(db); - match item_node.kind() { - ast::ImplItemKind::FnDef(..) => ImplItem::Method(Function::new(def_id)), - ast::ImplItemKind::ConstDef(..) => ImplItem::Const(def_id), - ast::ImplItemKind::TypeDef(..) => ImplItem::Type(def_id), + .map(|item_node| match item_node.kind() { + ast::ImplItemKind::FnDef(it) => { + ImplItem::Method(Function { id: ctx.to_def(it) }) } + ast::ImplItemKind::ConstDef(it) => { + ImplItem::Const(Const { id: ctx.to_def(it) }) + } + ast::ImplItemKind::TypeDef(it) => ImplItem::Type(Type { id: ctx.to_def(it) }), }) .collect() } else { @@ -124,22 +109,19 @@ impl ImplData { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +//TODO: rename to ImplDef? pub enum ImplItem { Method(Function), - // these don't have their own types yet - Const(DefId), - Type(DefId), + Const(Const), + Type(Type), // Existential } +impl_froms!(ImplItem: Const, Type); -impl ImplItem { - pub fn def_id(&self) -> DefId { - match self { - ImplItem::Method(f) => f.def_id(), - ImplItem::Const(def_id) => *def_id, - ImplItem::Type(def_id) => *def_id, - } +impl From for ImplItem { + fn from(func: Function) -> ImplItem { + ImplItem::Method(func) } } @@ -155,7 +137,7 @@ impl_arena_id!(ImplId); #[derive(Debug, PartialEq, Eq)] pub struct ModuleImplBlocks { pub(crate) impls: Arena, - impls_by_def: FxHashMap, + impls_by_def: FxHashMap, } impl ModuleImplBlocks { @@ -168,6 +150,7 @@ impl ModuleImplBlocks { fn collect(&mut self, db: &impl HirDatabase, module: Module) { let (file_id, module_source) = module.definition_source(db); + let file_id: HirFileId = file_id.into(); let node = match &module_source { ModuleSource::SourceFile(node) => node.syntax(), ModuleSource::Module(node) => node @@ -176,25 +159,18 @@ impl ModuleImplBlocks { .syntax(), }; - let source_file_items = db.file_items(file_id.into()); - for impl_block_ast in node.children().filter_map(ast::ImplBlock::cast) { - let impl_block = ImplData::from_ast(db, &source_file_items, &module, impl_block_ast); + let impl_block = ImplData::from_ast(db, file_id, module, impl_block_ast); let id = self.impls.alloc(impl_block); - for impl_item in &self.impls[id].items { - self.impls_by_def.insert(impl_item.def_id(), id); + for &impl_item in &self.impls[id].items { + self.impls_by_def.insert(impl_item, id); } } } } -pub(crate) fn impls_in_module( - db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, -) -> Arc { +pub(crate) fn impls_in_module(db: &impl HirDatabase, module: Module) -> Arc { let mut result = ModuleImplBlocks::new(); - let module = Module::from_module_id(db, source_root_id, module_id); result.collect(db, module); Arc::new(result) } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 87b5a8b8a0..596f9c38c3 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -5,6 +5,18 @@ //! to a particular crate instance. That is, it has cfg flags and features //! applied. So, the relation between syntax and HIR is many-to-one. +macro_rules! impl_froms { + ($e:ident: $($v:ident), *) => { + $( + impl From<$v> for $e { + fn from(it: $v) -> $e { + $e::$v(it) + } + } + )* + } +} + pub mod db; #[cfg(test)] mod mock; @@ -34,25 +46,26 @@ mod marks; use crate::{ db::HirDatabase, name::{AsName, KnownName}, - ids::{DefKind, SourceItemId, SourceFileItems}, + ids::{SourceItemId, SourceFileItems}, }; pub use self::{ path::{Path, PathKind}, name::Name, - ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc, HirInterner}, + ids::{HirFileId, MacroCallId, MacroCallLoc, HirInterner}, macros::{MacroDef, MacroInput, MacroExpansion}, nameres::{ItemMap, PerNs, Namespace, Resolution}, ty::Ty, impl_block::{ImplBlock, ImplItem}, code_model_impl::function::{FnScopes, ScopesWithSyntaxMapping}, - docs::{Docs, Documentation} + docs::{Docs, Documentation}, + adt::AdtDef, }; pub use self::code_model_api::{ Crate, CrateDependency, Def, - Module, ModuleSource, Problem, + Module, ModuleDef, ModuleSource, Problem, Struct, Enum, EnumVariant, Function, FnSignature, ScopeEntryWithSyntax, StructField, diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 4145c80487..361366f6a1 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -35,10 +35,6 @@ impl MockDatabase { let file_id = db.add_file(WORKSPACE, &mut source_root, "/main.rs", text); db.query_mut(ra_db::SourceRootQuery) .set(WORKSPACE, Arc::new(source_root.clone())); - - let mut crate_graph = CrateGraph::default(); - crate_graph.add_crate_root(file_id); - db.set_crate_graph(crate_graph); (db, source_root, file_id) } @@ -97,6 +93,8 @@ impl MockDatabase { text: &str, ) -> FileId { assert!(path.starts_with('/')); + let is_crate_root = path == "/lib.rs" || path == "/main.rs"; + let path = RelativePathBuf::from_path(&path[1..]).unwrap(); let file_id = FileId(self.file_counter); self.file_counter += 1; @@ -107,6 +105,12 @@ impl MockDatabase { self.query_mut(ra_db::FileSourceRootQuery) .set(file_id, source_root_id); source_root.files.insert(path, file_id); + + if is_crate_root { + let mut crate_graph = CrateGraph::default(); + crate_graph.add_crate_root(file_id); + self.set_crate_graph(crate_graph); + } file_id } @@ -202,6 +206,7 @@ salsa::database_storage! { fn file_relative_path() for ra_db::FileRelativePathQuery; fn file_source_root() for ra_db::FileSourceRootQuery; fn source_root() for ra_db::SourceRootQuery; + fn source_root_crates() for ra_db::SourceRootCratesQuery; fn local_roots() for ra_db::LocalRootsQuery; fn library_roots() for ra_db::LibraryRootsQuery; fn crate_graph() for ra_db::CrateGraphQuery; diff --git a/crates/ra_hir/src/module_tree.rs b/crates/ra_hir/src/module_tree.rs index b201bf69bf..c00834c4c1 100644 --- a/crates/ra_hir/src/module_tree.rs +++ b/crates/ra_hir/src/module_tree.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use rustc_hash::{FxHashMap, FxHashSet}; use arrayvec::ArrayVec; use relative_path::RelativePathBuf; -use ra_db::{FileId, SourceRootId, SourceRoot}; +use ra_db::{FileId, SourceRoot, CrateId}; use ra_syntax::{ SyntaxNode, TreeArc, algo::generate, @@ -126,13 +126,10 @@ struct LinkData { } impl ModuleTree { - pub(crate) fn module_tree_query( - db: &impl HirDatabase, - source_root: SourceRootId, - ) -> Arc { + pub(crate) fn module_tree_query(db: &impl HirDatabase, crate_id: CrateId) -> Arc { db.check_canceled(); let mut res = ModuleTree::default(); - res.init(db, source_root); + res.init_crate(db, crate_id); Arc::new(res) } @@ -145,24 +142,21 @@ impl ModuleTree { Some(res) } - fn init(&mut self, db: &impl HirDatabase, source_root: SourceRootId) { + fn init_crate(&mut self, db: &impl HirDatabase, crate_id: CrateId) { + let crate_graph = db.crate_graph(); + let file_id = crate_graph.crate_root(crate_id); + let source_root_id = db.file_source_root(file_id); + let mut roots = FxHashMap::default(); let mut visited = FxHashSet::default(); - let source_root = db.source_root(source_root); - for &file_id in source_root.files.values() { - let source = SourceItemId { - file_id: file_id.into(), - item_id: None, - }; - if visited.contains(&source) { - continue; // TODO: use explicit crate_roots here - } - assert!(!roots.contains_key(&file_id)); - let module_id = - self.init_subtree(db, &source_root, &mut visited, &mut roots, None, source); - roots.insert(file_id, module_id); - } + let source_root = db.source_root(source_root_id); + let source = SourceItemId { + file_id: file_id.into(), + item_id: None, + }; + let module_id = self.init_subtree(db, &source_root, &mut visited, &mut roots, None, source); + roots.insert(file_id, module_id); } fn init_subtree( diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 1d163edf7d..a3bc989580 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -16,19 +16,19 @@ //! structure itself is modified. pub(crate) mod lower; -use crate::nameres::lower::*; - use std::sync::Arc; +use ra_db::CrateId; use rustc_hash::{FxHashMap, FxHashSet}; -use ra_db::SourceRootId; use crate::{ - DefId, DefLoc, DefKind, + Module, ModuleDef, Path, PathKind, HirDatabase, Crate, Name, module_tree::{ModuleId, ModuleTree}, +//FIXME: deglobify + nameres::lower::*, }; /// `ItemMap` is the result of name resolution. It contains, for each @@ -58,7 +58,7 @@ impl ModuleScope { #[derive(Debug, Clone, PartialEq, Eq)] pub struct Resolution { /// None for unresolved - pub def_id: PerNs, + pub def_id: PerNs, /// ident by which this is imported into local scope. pub import: Option, } @@ -152,7 +152,7 @@ impl PerNs { pub(crate) struct Resolver<'a, DB> { db: &'a DB, input: &'a FxHashMap>, - source_root: SourceRootId, + krate: CrateId, module_tree: Arc, processed_imports: FxHashSet<(ModuleId, ImportId)>, result: ItemMap, @@ -165,13 +165,13 @@ where pub(crate) fn new( db: &'a DB, input: &'a FxHashMap>, - source_root: SourceRootId, - module_tree: Arc, + krate: CrateId, ) -> Resolver<'a, DB> { + let module_tree = db.module_tree(krate); Resolver { db, input, - source_root, + krate, module_tree, processed_imports: FxHashSet::default(), result: ItemMap::default(), @@ -210,7 +210,7 @@ where let krate = Crate::new(crate_id); for dep in krate.dependencies(self.db) { if let Some(module) = dep.krate.root_module(self.db) { - let def_id = module.def_id; + let def_id = module.into(); self.add_module_item( &mut module_items, dep.name.clone(), @@ -244,20 +244,22 @@ where // Populate modules for (name, module_id) in module_id.children(&self.module_tree) { - let def_loc = DefLoc { - kind: DefKind::Module, - source_root_id: self.source_root, + let module = Module { module_id, - source_item_id: module_id.source(&self.module_tree), + krate: self.krate, }; - let def_id = def_loc.id(self.db); - self.add_module_item(&mut module_items, name, PerNs::types(def_id)); + self.add_module_item(&mut module_items, name, PerNs::types(module.into())); } self.result.per_module.insert(module_id, module_items); } - fn add_module_item(&self, module_items: &mut ModuleScope, name: Name, def_id: PerNs) { + fn add_module_item( + &self, + module_items: &mut ModuleScope, + name: Name, + def_id: PerNs, + ) { let resolution = Resolution { def_id, import: None, @@ -329,17 +331,11 @@ where ); return false; }; - curr = match type_def_id.loc(self.db) { - DefLoc { - kind: DefKind::Module, - module_id: target_module_id, - source_root_id, - .. - } => { - if source_root_id == self.source_root { - target_module_id + curr = match type_def_id { + ModuleDef::Module(module) => { + if module.krate == self.krate { + module.module_id } else { - let module = crate::code_model_api::Module::new(type_def_id); let path = Path { segments: import.path.segments[i + 1..].iter().cloned().collect(), kind: PathKind::Crate, @@ -359,7 +355,7 @@ where "resolved import {:?} ({:?}) cross-source root to {:?}", last_segment.name, import, - def_id.map(|did| did.loc(self.db)) + def_id, ); return true; } else { @@ -372,7 +368,7 @@ where log::debug!( "path segment {:?} resolved to non-module {:?}, but is not last", segment.name, - type_def_id.loc(self.db) + type_def_id, ); return true; // this resolved to a non-module, so the path won't ever resolve } @@ -382,7 +378,7 @@ where "resolved import {:?} ({:?}) within source root to {:?}", segment.name, import, - def_id.map(|did| did.loc(self.db)) + def_id, ); self.update(module_id, |items| { let res = Resolution { diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 4eea6ff1de..b4fe99ea70 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs @@ -1,17 +1,17 @@ use std::sync::Arc; use ra_syntax::{ - SyntaxKind, AstNode, SourceFile, TreeArc, AstPtr, + AstNode, SourceFile, TreeArc, AstPtr, ast::{self, ModuleItemOwner, NameOwner}, }; -use ra_db::SourceRootId; use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap}; use rustc_hash::FxHashMap; use crate::{ - SourceItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, - HirFileId, MacroCallLoc, AsName, PerNs, DefId, DefKind, DefLoc, - module_tree::ModuleId + SourceItemId, Path, ModuleSource, HirDatabase, Name, + HirFileId, MacroCallLoc, AsName, PerNs, Function, + ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type, + ids::LocationCtx, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -32,7 +32,7 @@ pub(super) struct ImportData { /// can avoid redoing name resolution. #[derive(Debug, Default, PartialEq, Eq)] pub struct LoweredModule { - pub(crate) declarations: FxHashMap>, + pub(crate) declarations: FxHashMap>, pub(super) imports: Arena, } @@ -59,37 +59,31 @@ impl ImportSourceMap { impl LoweredModule { pub(crate) fn lower_module_module_query( db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, + module: Module, ) -> Arc { - db.lower_module(source_root_id, module_id).0 + db.lower_module(module).0 } pub(crate) fn lower_module_source_map_query( db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, + module: Module, ) -> Arc { - db.lower_module(source_root_id, module_id).1 + db.lower_module(module).1 } pub(crate) fn lower_module_query( db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, + module: Module, ) -> (Arc, Arc) { - let module_tree = db.module_tree(source_root_id); - let source = module_id.source(&module_tree); - let file_id = source.file_id; - let source = ModuleSource::from_source_item_id(db, source); + let (file_id, source) = module.definition_source(db); + let file_id: HirFileId = file_id.into(); let mut source_map = ImportSourceMap::default(); let mut res = LoweredModule::default(); match source { ModuleSource::SourceFile(it) => res.fill( &mut source_map, db, - source_root_id, - module_id, + module, file_id, &mut it.items_with_macros(), ), @@ -98,8 +92,7 @@ impl LoweredModule { res.fill( &mut source_map, db, - source_root_id, - module_id, + module, file_id, &mut item_list.items_with_macros(), ) @@ -113,8 +106,7 @@ impl LoweredModule { &mut self, source_map: &mut ImportSourceMap, db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, + module: Module, file_id: HirFileId, items: &mut Iterator, ) { @@ -123,21 +115,12 @@ impl LoweredModule { for item in items { match item { ast::ItemOrMacro::Item(it) => { - self.add_def_id( - source_map, - db, - source_root_id, - module_id, - file_id, - &file_items, - it, - ); + self.add_def_id(source_map, db, module, file_id, it); } ast::ItemOrMacro::Macro(macro_call) => { let item_id = file_items.id_of_unchecked(macro_call.syntax()); let loc = MacroCallLoc { - source_root_id, - module_id, + module, source_item_id: SourceItemId { file_id, item_id: Some(item_id), @@ -145,18 +128,9 @@ impl LoweredModule { }; let id = loc.id(db); let file_id = HirFileId::from(id); - let file_items = db.file_items(file_id); //FIXME: expand recursively for item in db.hir_source_file(file_id).items() { - self.add_def_id( - source_map, - db, - source_root_id, - module_id, - file_id, - &file_items, - item, - ); + self.add_def_id(source_map, db, module, file_id, item); } } } @@ -167,41 +141,74 @@ impl LoweredModule { &mut self, source_map: &mut ImportSourceMap, db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, + module: Module, file_id: HirFileId, - file_items: &SourceFileItems, item: &ast::ModuleItem, ) { - let name = match item.kind() { - ast::ModuleItemKind::StructDef(it) => it.name(), - ast::ModuleItemKind::EnumDef(it) => it.name(), - ast::ModuleItemKind::FnDef(it) => it.name(), - ast::ModuleItemKind::TraitDef(it) => it.name(), - ast::ModuleItemKind::TypeDef(it) => it.name(), + let ctx = LocationCtx::new(db, module, file_id); + match item.kind() { + ast::ModuleItemKind::StructDef(it) => { + if let Some(name) = it.name() { + let s = Struct { id: ctx.to_def(it) }; + let s: ModuleDef = s.into(); + self.declarations.insert(name.as_name(), PerNs::both(s, s)); + } + } + ast::ModuleItemKind::EnumDef(it) => { + if let Some(name) = it.name() { + let e = Enum { id: ctx.to_def(it) }; + let e: ModuleDef = e.into(); + self.declarations.insert(name.as_name(), PerNs::types(e)); + } + } + ast::ModuleItemKind::FnDef(it) => { + if let Some(name) = it.name() { + let func = Function { id: ctx.to_def(it) }; + self.declarations + .insert(name.as_name(), PerNs::values(func.into())); + } + } + ast::ModuleItemKind::TraitDef(it) => { + if let Some(name) = it.name() { + let t = Trait { id: ctx.to_def(it) }; + self.declarations + .insert(name.as_name(), PerNs::types(t.into())); + } + } + ast::ModuleItemKind::TypeDef(it) => { + if let Some(name) = it.name() { + let t = Type { id: ctx.to_def(it) }; + self.declarations + .insert(name.as_name(), PerNs::types(t.into())); + } + } ast::ModuleItemKind::ImplBlock(_) => { // impls don't define items - return; } ast::ModuleItemKind::UseItem(it) => { self.add_use_item(source_map, it); - return; } ast::ModuleItemKind::ExternCrateItem(_) => { // TODO - return; } - ast::ModuleItemKind::ConstDef(it) => it.name(), - ast::ModuleItemKind::StaticDef(it) => it.name(), + ast::ModuleItemKind::ConstDef(it) => { + if let Some(name) = it.name() { + let c = Const { id: ctx.to_def(it) }; + self.declarations + .insert(name.as_name(), PerNs::values(c.into())); + } + } + ast::ModuleItemKind::StaticDef(it) => { + if let Some(name) = it.name() { + let s = Static { id: ctx.to_def(it) }; + self.declarations + .insert(name.as_name(), PerNs::values(s.into())); + } + } ast::ModuleItemKind::Module(_) => { // modules are handled separately direclty by nameres - return; } }; - if let Some(name) = name { - let def_id = assign_def_id(db, source_root_id, module_id, file_id, file_items, item); - self.declarations.insert(name.as_name(), def_id); - } } fn add_use_item(&mut self, source_map: &mut ImportSourceMap, item: &ast::UseItem) { @@ -216,46 +223,3 @@ impl LoweredModule { }) } } - -fn assign_def_id( - db: &impl HirDatabase, - source_root_id: SourceRootId, - module_id: ModuleId, - file_id: HirFileId, - file_items: &SourceFileItems, - item: &ast::ModuleItem, -) -> PerNs { - // depending on the item kind, the location can define something in - // the values namespace, the types namespace, or both - let kind = DefKind::for_syntax_kind(item.syntax().kind()); - let def_id = kind.map(|k| { - let item_id = file_items.id_of_unchecked(item.syntax()); - let def_loc = DefLoc { - kind: k, - source_root_id, - module_id, - source_item_id: SourceItemId { - file_id, - item_id: Some(item_id), - }, - }; - def_loc.id(db) - }); - def_id -} - -impl DefKind { - fn for_syntax_kind(kind: SyntaxKind) -> PerNs { - match kind { - SyntaxKind::FN_DEF => PerNs::values(DefKind::Function), - SyntaxKind::MODULE => PerNs::types(DefKind::Module), - SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor), - SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum), - SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Trait), - SyntaxKind::TYPE_DEF => PerNs::types(DefKind::Type), - SyntaxKind::CONST_DEF => PerNs::values(DefKind::Const), - SyntaxKind::STATIC_DEF => PerNs::values(DefKind::Static), - _ => PerNs::none(), - } - } -} diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index e920074533..9322bf08ce 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use ra_db::{FilesDatabase, CrateGraph, SourceRootId, salsa::Database}; +use ra_db::{CrateGraph, SourceRootId, salsa::Database}; use relative_path::RelativePath; use test_utils::{assert_eq_text, covers}; @@ -13,10 +13,10 @@ use crate::{ fn item_map(fixture: &str) -> (Arc, ModuleId) { let (db, pos) = MockDatabase::with_position(fixture); - let source_root = db.file_source_root(pos.file_id); let module = crate::source_binder::module_from_position(&db, pos).unwrap(); - let module_id = module.def_id.loc(&db).module_id; - (db.item_map(source_root), module_id) + let krate = module.krate(&db).unwrap(); + let module_id = module.module_id; + (db.item_map(krate.crate_id), module_id) } fn check_module_item_map(map: &ItemMap, module_id: ModuleId, expected: &str) { @@ -238,14 +238,13 @@ fn item_map_across_crates() { db.set_crate_graph(crate_graph); - let source_root = db.file_source_root(main_id); let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); - let module_id = module.def_id.loc(&db).module_id; - let item_map = db.item_map(source_root); + let krate = module.krate(&db).unwrap(); + let item_map = db.item_map(krate.crate_id); check_module_item_map( &item_map, - module_id, + module.module_id, " Baz: t v test_crate: t @@ -292,12 +291,12 @@ fn import_across_source_roots() { db.set_crate_graph(crate_graph); let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); - let module_id = module.def_id.loc(&db).module_id; - let item_map = db.item_map(source_root); + let krate = module.krate(&db).unwrap(); + let item_map = db.item_map(krate.crate_id); check_module_item_map( &item_map, - module_id, + module.module_id, " C: t v test_crate: t @@ -333,14 +332,13 @@ fn reexport_across_crates() { db.set_crate_graph(crate_graph); - let source_root = db.file_source_root(main_id); let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap(); - let module_id = module.def_id.loc(&db).module_id; - let item_map = db.item_map(source_root); + let krate = module.krate(&db).unwrap(); + let item_map = db.item_map(krate.crate_id); check_module_item_map( &item_map, - module_id, + module.module_id, " Baz: t v test_crate: t @@ -350,10 +348,11 @@ fn reexport_across_crates() { fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) { let (mut db, pos) = MockDatabase::with_position(initial); - let source_root = db.file_source_root(pos.file_id); + let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap(); + let krate = module.krate(&db).unwrap(); { let events = db.log_executed(|| { - db.item_map(source_root); + db.item_map(krate.crate_id); }); assert!(format!("{:?}", events).contains("item_map")) } @@ -362,7 +361,7 @@ fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) { { let events = db.log_executed(|| { - db.item_map(source_root); + db.item_map(krate.crate_id); }); assert!( !format!("{:?}", events).contains("item_map"), diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index 0741538626..cf8c7e4354 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs @@ -7,17 +7,17 @@ use rustc_hash::FxHashMap; use ra_syntax::{ AstNode, SyntaxNode, TreeArc, }; -use ra_db::SourceRootId; +use ra_db::{CrateId}; use crate::{ - SourceFileItems, SourceItemId, DefId, HirFileId, - FnScopes, + SourceFileItems, SourceItemId, HirFileId, + Function, FnScopes, Module, db::HirDatabase, nameres::{ItemMap, Resolver}, }; -pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc { - let body = db.body_hir(def_id); +pub(super) fn fn_scopes(db: &impl HirDatabase, func: Function) -> Arc { + let body = db.body_hir(func); let res = FnScopes::new(body); Arc::new(res) } @@ -41,15 +41,23 @@ pub(super) fn file_item( } } -pub(super) fn item_map(db: &impl HirDatabase, source_root: SourceRootId) -> Arc { +pub(super) fn item_map(db: &impl HirDatabase, crate_id: CrateId) -> Arc { let start = Instant::now(); - let module_tree = db.module_tree(source_root); + let module_tree = db.module_tree(crate_id); let input = module_tree .modules() - .map(|id| (id, db.lower_module_module(source_root, id))) + .map(|module_id| { + ( + module_id, + db.lower_module_module(Module { + krate: crate_id, + module_id, + }), + ) + }) .collect::>(); - let resolver = Resolver::new(db, &input, source_root, module_tree); + let resolver = Resolver::new(db, &input, crate_id); let res = resolver.resolve(); let elapsed = start.elapsed(); log::info!("item_map: {:?}", elapsed); diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index bde0be37b6..dbe040805e 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -13,8 +13,9 @@ use ra_syntax::{ }; use crate::{ - HirDatabase, Function, SourceItemId, - DefKind, DefLoc, AsName, Module, + HirDatabase, Function, SourceItemId, ModuleDef, + AsName, Module, + ids::LocationCtx, }; /// Locates the module by `FileId`. Picks topmost module in the file. @@ -84,9 +85,13 @@ pub fn module_from_child_node( fn module_from_source(db: &impl HirDatabase, source: SourceItemId) -> Option { let source_root_id = db.file_source_root(source.file_id.as_original_file()); - let module_tree = db.module_tree(source_root_id); - let module_id = module_tree.find_module_by_source(source)?; - Some(Module::from_module_id(db, source_root_id, module_id)) + db.source_root_crates(source_root_id) + .iter() + .find_map(|&krate| { + let module_tree = db.module_tree(krate); + let module_id = module_tree.find_module_by_source(source)?; + Some(Module { krate, module_id }) + }) } pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option { @@ -101,30 +106,21 @@ pub fn function_from_source( fn_def: &ast::FnDef, ) -> Option { let module = module_from_child_node(db, file_id, fn_def.syntax())?; - let res = function_from_module(db, &module, fn_def); + let res = function_from_module(db, module, fn_def); Some(res) } pub fn function_from_module( db: &impl HirDatabase, - module: &Module, + module: Module, fn_def: &ast::FnDef, ) -> Function { - let loc = module.def_id.loc(db); - let file_id = loc.source_item_id.file_id; - let file_items = db.file_items(file_id); - let item_id = file_items.id_of(file_id, fn_def.syntax()); - let source_item_id = SourceItemId { - file_id, - item_id: Some(item_id), - }; - let def_loc = DefLoc { - kind: DefKind::Function, - source_root_id: loc.source_root_id, - module_id: loc.module_id, - source_item_id, - }; - Function::new(def_loc.id(db)) + let (file_id, _) = module.definition_source(db); + let file_id = file_id.into(); + let ctx = LocationCtx::new(db, module, file_id); + Function { + id: ctx.to_def(fn_def), + } } pub fn function_from_child_node( @@ -141,15 +137,18 @@ pub fn macro_symbols(db: &impl HirDatabase, file_id: FileId) -> Vec<(SmolStr, Te Some(it) => it, None => return Vec::new(), }; - let loc = module.def_id.loc(db); - let items = db.lower_module_module(loc.source_root_id, loc.module_id); + let items = db.lower_module_module(module); let mut res = Vec::new(); for macro_call_id in items .declarations .iter() - .filter_map(|(_, it)| it.take_types()) - .filter_map(|it| it.loc(db).source_item_id.file_id.as_macro_call_id()) + .filter_map(|(_, it)| it.clone().take_types()) + .filter_map(|it| match it { + ModuleDef::Trait(it) => Some(it), + _ => None, + }) + .filter_map(|it| it.source(db).0.as_macro_call_id()) { if let Some(exp) = db.expand_macro_invocation(macro_call_id) { let loc = macro_call_id.loc(db); diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index e690ae1582..c7f77e7a39 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -24,15 +24,14 @@ use std::ops::Index; use std::sync::Arc; use std::{fmt, mem}; -use log; use ena::unify::{InPlaceUnificationTable, UnifyKey, UnifyValue, NoError}; use ra_arena::map::ArenaMap; use join_to_string::join; use rustc_hash::FxHashMap; use crate::{ - Def, DefId, Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, - FnSignature, FnScopes, + Module, Function, Struct, StructField, Enum, EnumVariant, Path, Name, ImplBlock, + FnSignature, FnScopes, ModuleDef, AdtDef, db::HirDatabase, type_ref::{TypeRef, Mutability}, name::KnownName, @@ -184,7 +183,7 @@ pub enum Ty { /// Structures, enumerations and unions. Adt { /// The DefId of the struct/enum. - def_id: DefId, + def_id: AdtDef, /// The name, for displaying. name: Name, /// Substitutions for the generic parameters of the type. @@ -381,12 +380,16 @@ impl Ty { } // Resolve in module (in type namespace) - let resolved = match module.resolve_path(db, path).take_types() { - Some(r) => r, + let typable: TypableDef = match module + .resolve_path(db, path) + .take_types() + .and_then(|it| it.into()) + { None => return Ty::Unknown, + Some(it) => it, }; - let ty = db.type_for_def(resolved); - let substs = Ty::substs_from_path(db, module, impl_block, generics, path, resolved); + let ty = db.type_for_def(typable); + let substs = Ty::substs_from_path(db, module, impl_block, generics, path, typable); ty.apply_substs(substs) } @@ -399,20 +402,18 @@ impl Ty { impl_block: Option<&ImplBlock>, outer_generics: &GenericParams, path: &Path, - resolved: DefId, + resolved: TypableDef, ) -> Substs { let mut substs = Vec::new(); - let def = resolved.resolve(db); let last = path .segments .last() .expect("path should have at least one segment"); - let (def_generics, segment) = match def { - Def::Struct(s) => (s.generic_params(db), last), - Def::Enum(e) => (e.generic_params(db), last), - Def::Function(f) => (f.generic_params(db), last), - Def::Trait(t) => (t.generic_params(db), last), - Def::EnumVariant(ev) => { + let (def_generics, segment) = match resolved { + TypableDef::Function(func) => (func.generic_params(db), last), + TypableDef::Struct(s) => (s.generic_params(db), last), + TypableDef::Enum(e) => (e.generic_params(db), last), + TypableDef::EnumVariant(var) => { // the generic args for an enum variant may be either specified // on the segment referring to the enum, or on the segment // referring to the variant. So `Option::::None` and @@ -426,9 +427,8 @@ impl Ty { // Option::None:: last }; - (ev.parent_enum(db).generic_params(db), segment) + (var.parent_enum(db).generic_params(db), segment) } - _ => return Substs::empty(), }; // substs_from_path if let Some(generic_args) = &segment.args_and_bindings { @@ -639,7 +639,7 @@ fn make_substs(generics: &GenericParams) -> Substs { fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { let generics = s.generic_params(db); Ty::Adt { - def_id: s.def_id(), + def_id: s.into(), name: s.name(db).unwrap_or_else(Name::missing), substs: make_substs(&generics), } @@ -648,7 +648,7 @@ fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { pub(crate) fn type_for_enum(db: &impl HirDatabase, s: Enum) -> Ty { let generics = s.generic_params(db); Ty::Adt { - def_id: s.def_id(), + def_id: s.into(), name: s.name(db).unwrap_or_else(Name::missing), substs: make_substs(&generics), } @@ -660,66 +660,74 @@ pub(crate) fn type_for_enum_variant(db: &impl HirDatabase, ev: EnumVariant) -> T type_for_enum(db, enum_parent) } -pub(super) fn type_for_def(db: &impl HirDatabase, def_id: DefId) -> Ty { - let def = def_id.resolve(db); - match def { - Def::Module(..) => { - log::debug!("trying to get type for module {:?}", def_id); - Ty::Unknown - } - Def::Function(f) => type_for_fn(db, f), - Def::Struct(s) => type_for_struct(db, s), - Def::Enum(e) => type_for_enum(db, e), - Def::EnumVariant(ev) => type_for_enum_variant(db, ev), - _ => { - log::debug!( - "trying to get type for item of unknown type {:?} {:?}", - def_id, - def - ); - Ty::Unknown - } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum TypableDef { + Function(Function), + Struct(Struct), + Enum(Enum), + EnumVariant(EnumVariant), +} +impl_froms!(TypableDef: Function, Struct, Enum, EnumVariant); + +impl From for Option { + fn from(def: ModuleDef) -> Option { + let res = match def { + ModuleDef::Function(f) => f.into(), + ModuleDef::Struct(s) => s.into(), + ModuleDef::Enum(e) => e.into(), + ModuleDef::EnumVariant(v) => v.into(), + ModuleDef::Const(_) + | ModuleDef::Static(_) + | ModuleDef::Module(_) + | ModuleDef::Trait(_) + | ModuleDef::Type(_) => return None, + }; + Some(res) } } -pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) -> Option { - let def = def_id.resolve(db); - let (variant_data, generics) = match def { - Def::Struct(s) => (s.variant_data(db), s.generic_params(db)), - Def::EnumVariant(ev) => (ev.variant_data(db), ev.parent_enum(db).generic_params(db)), - // TODO: unions - Def::Enum(_) => { - // this can happen in (invalid) code, but enums don't have fields themselves - return None; - } - _ => panic!( - "trying to get type for field {:?} in non-struct/variant {:?}", - field, def_id +pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty { + match def { + TypableDef::Function(f) => type_for_fn(db, f), + TypableDef::Struct(s) => type_for_struct(db, s), + TypableDef::Enum(e) => type_for_enum(db, e), + TypableDef::EnumVariant(v) => type_for_enum_variant(db, v), + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum VariantDef { + Struct(Struct), + EnumVariant(EnumVariant), +} +impl_froms!(VariantDef: Struct, EnumVariant); + +pub(super) fn type_for_field(db: &impl HirDatabase, def: VariantDef, field: Name) -> Option { + let (variant_data, generics, module) = match def { + VariantDef::Struct(s) => (s.variant_data(db), s.generic_params(db), s.module(db)), + VariantDef::EnumVariant(var) => ( + var.variant_data(db), + var.parent_enum(db).generic_params(db), + var.module(db), ), }; - let module = def_id.module(db); - let impl_block = def_id.impl_block(db); + // We can't have an impl block ere, right? + // let impl_block = def_id.impl_block(db); let type_ref = variant_data.get_field_type_ref(&field)?; - Some(Ty::from_hir( - db, - &module, - impl_block.as_ref(), - &generics, - &type_ref, - )) + Some(Ty::from_hir(db, &module, None, &generics, &type_ref)) } /// The result of type inference: A mapping from expressions and patterns to types. #[derive(Clone, PartialEq, Eq, Debug)] pub struct InferenceResult { /// For each method call expr, record the function it resolved to. - method_resolutions: FxHashMap, + method_resolutions: FxHashMap, type_of_expr: ArenaMap, type_of_pat: ArenaMap, } impl InferenceResult { - pub fn method_resolution(&self, expr: ExprId) -> Option { + pub fn method_resolution(&self, expr: ExprId) -> Option { self.method_resolutions.get(&expr).map(|it| *it) } } @@ -749,7 +757,7 @@ struct InferenceContext<'a, D: HirDatabase> { module: Module, impl_block: Option, var_unification_table: InPlaceUnificationTable, - method_resolutions: FxHashMap, + method_resolutions: FxHashMap, type_of_expr: ArenaMap, type_of_pat: ArenaMap, /// The return type of the function being inferred. @@ -875,8 +883,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.type_of_expr.insert(expr, ty); } - fn write_method_resolution(&mut self, expr: ExprId, def_id: DefId) { - self.method_resolutions.insert(expr, def_id); + fn write_method_resolution(&mut self, expr: ExprId, func: Function) { + self.method_resolutions.insert(expr, func); } fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { @@ -1063,20 +1071,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { }; // resolve in module - let resolved = self.module.resolve_path(self.db, &path).take_values()?; - let ty = self.db.type_for_def(resolved); + let typable: Option = self + .module + .resolve_path(self.db, &path) + .take_values()? + .into(); + let typable = typable?; + let ty = self.db.type_for_def(typable); let ty = self.insert_type_vars(ty); Some(ty) } - fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option) { + fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option) { let path = match path { Some(path) => path, None => return (Ty::Unknown, None), }; - let def_id = match self.module.resolve_path(self.db, &path).take_types() { - Some(def_id) => def_id, - _ => return (Ty::Unknown, None), + let typable: Option = self + .module + .resolve_path(self.db, &path) + .take_types() + .and_then(|it| it.into()); + let def = match typable { + None => return (Ty::Unknown, None), + Some(it) => it, }; // TODO remove the duplication between here and `Ty::from_path`? // TODO provide generics of function @@ -1087,38 +1105,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { self.impl_block.as_ref(), &generics, path, - def_id, + def, ); - match def_id.resolve(self.db) { - Def::Struct(s) => { + match def { + TypableDef::Struct(s) => { let ty = type_for_struct(self.db, s); let ty = self.insert_type_vars(ty.apply_substs(substs)); - (ty, Some(def_id)) + (ty, Some(s.into())) } - Def::EnumVariant(ev) => { - let ty = type_for_enum_variant(self.db, ev); + TypableDef::EnumVariant(var) => { + let ty = type_for_enum_variant(self.db, var); let ty = self.insert_type_vars(ty.apply_substs(substs)); - (ty, Some(def_id)) + (ty, Some(var.into())) } - _ => (Ty::Unknown, None), + TypableDef::Enum(_) | TypableDef::Function(_) => (Ty::Unknown, None), } } fn resolve_fields(&mut self, path: Option<&Path>) -> Option<(Ty, Vec)> { - let (ty, def_id) = self.resolve_variant(path); - let def_id = def_id?; - let def = def_id.resolve(self.db); - - match def { - Def::Struct(s) => { + let (ty, def) = self.resolve_variant(path); + match def? { + VariantDef::Struct(s) => { let fields = s.fields(self.db); Some((ty, fields)) } - Def::EnumVariant(ev) => { - let fields = ev.fields(self.db); + VariantDef::EnumVariant(var) => { + let fields = var.fields(self.db); Some((ty, fields)) } - _ => None, } } @@ -1216,6 +1230,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .module .resolve_path(self.db, &path) .take_values() + .and_then(|module_def| module_def.into()) .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)), Pat::Bind { mode, @@ -1336,9 +1351,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); let resolved = receiver_ty.clone().lookup_method(self.db, method_name); let method_ty = match resolved { - Some(def_id) => { - self.write_method_resolution(expr, def_id); - self.db.type_for_def(def_id) + Some(func) => { + self.write_method_resolution(expr, func); + self.db.type_for_def(func.into()) } None => Ty::Unknown, }; @@ -1407,7 +1422,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { for field in fields { let field_ty = if let Some(def_id) = def_id { self.db - .type_for_field(def_id, field.name.clone()) + .type_for_field(def_id.into(), field.name.clone()) .unwrap_or(Ty::Unknown) .subst(&substs) } else { @@ -1431,10 +1446,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { i.and_then(|i| fields.get(i).cloned()) } Ty::Adt { - def_id, ref substs, .. + def_id: AdtDef::Struct(s), + ref substs, + .. } => self .db - .type_for_field(def_id, name.clone()) + .type_for_field(s.into(), name.clone()) .map(|ty| ty.subst(substs)), _ => None, }) @@ -1607,16 +1624,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { } } -pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Arc { +pub fn infer(db: &impl HirDatabase, func: Function) -> Arc { db.check_canceled(); - let function = Function::new(def_id); // TODO: consts also need inference - let body = function.body(db); - let scopes = db.fn_scopes(def_id); - let module = function.module(db); - let impl_block = function.impl_block(db); + let body = func.body(db); + let scopes = db.fn_scopes(func); + let module = func.module(db); + let impl_block = func.impl_block(db); let mut ctx = InferenceContext::new(db, body, scopes, module, impl_block); - let signature = function.signature(db); + let signature = func.signature(db); ctx.collect_fn_signature(&signature); ctx.infer_body(); diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 9f65c5fe1d..9a571c2aaf 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -6,19 +6,17 @@ use std::sync::Arc; use rustc_hash::FxHashMap; -use ra_db::SourceRootId; - use crate::{ - HirDatabase, DefId, module_tree::ModuleId, Module, Crate, Name, Function, + HirDatabase, module_tree::ModuleId, Module, Crate, Name, Function, impl_block::{ImplId, ImplBlock, ImplItem}, - generics::GenericParams + generics::GenericParams, + ty::{AdtDef, Ty} }; -use super::Ty; /// This is used as a key for indexing impls. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum TyFingerprint { - Adt(DefId), + Adt(AdtDef), // we'll also want to index impls for primitive types etc. } @@ -37,7 +35,7 @@ impl TyFingerprint { #[derive(Debug, PartialEq, Eq)] pub struct CrateImplBlocks { /// To make sense of the ModuleIds, we need the source root. - source_root_id: SourceRootId, + krate: Crate, impls: FxHashMap>, } @@ -53,14 +51,17 @@ impl CrateImplBlocks { .into_iter() .flat_map(|i| i.iter()) .map(move |(module_id, impl_id)| { - let module_impl_blocks = db.impls_in_module(self.source_root_id, *module_id); + let module = Module { + krate: self.krate.crate_id, + module_id: *module_id, + }; + let module_impl_blocks = db.impls_in_module(module); ImplBlock::from_id(module_impl_blocks, *impl_id) }) } - fn collect_recursive(&mut self, db: &impl HirDatabase, module: Module) { - let module_id = module.def_id.loc(db).module_id; - let module_impl_blocks = db.impls_in_module(self.source_root_id, module_id); + fn collect_recursive(&mut self, db: &impl HirDatabase, module: &Module) { + let module_impl_blocks = db.impls_in_module(module.clone()); for (impl_id, impl_data) in module_impl_blocks.impls.iter() { let impl_block = ImplBlock::from_id(Arc::clone(&module_impl_blocks), impl_id); @@ -81,13 +82,13 @@ impl CrateImplBlocks { self.impls .entry(target_ty_fp) .or_insert_with(Vec::new) - .push((module_id, impl_id)); + .push((module.module_id, impl_id)); } } } for child in module.children(db) { - self.collect_recursive(db, child); + self.collect_recursive(db, &child); } } @@ -95,15 +96,12 @@ impl CrateImplBlocks { db: &impl HirDatabase, krate: Crate, ) -> Arc { - let crate_graph = db.crate_graph(); - let file_id = crate_graph.crate_root(krate.crate_id); - let source_root_id = db.file_source_root(file_id); let mut crate_impl_blocks = CrateImplBlocks { - source_root_id, + krate: krate.clone(), impls: FxHashMap::default(), }; if let Some(module) = krate.root_module(db) { - crate_impl_blocks.collect_recursive(db, module); + crate_impl_blocks.collect_recursive(db, &module); } Arc::new(crate_impl_blocks) } @@ -120,11 +118,11 @@ impl Ty { // TODO: cache this as a query? // - if so, what signature? (TyFingerprint, Name)? // - or maybe cache all names and def_ids of methods per fingerprint? - pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option { + pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option { self.iterate_methods(db, |f| { let sig = f.signature(db); if sig.name() == name && sig.has_self_param() { - Some(f.def_id()) + Some(f) } else { None } diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap index c4a2d5cf8b..8747fae181 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_struct.snap @@ -1,19 +1,19 @@ --- -created: "2019-01-22T14:45:00.058678600+00:00" -creator: insta@0.4.0 +created: "2019-01-24T14:51:32.808861856+00:00" +creator: insta@0.5.2 expression: "&result" -source: "crates\\ra_hir\\src\\ty\\tests.rs" +source: crates/ra_hir/src/ty/tests.rs --- [72; 154) '{ ...a.c; }': () [82; 83) 'c': [unknown] -[86; 87) 'C': [unknown] +[86; 87) 'C': C [86; 90) 'C(1)': [unknown] [88; 89) '1': i32 -[96; 97) 'B': [unknown] +[96; 97) 'B': B [107; 108) 'a': A [114; 133) 'A { b:...C(1) }': A [121; 122) 'B': B -[127; 128) 'C': [unknown] +[127; 128) 'C': C [127; 131) 'C(1)': C [129; 130) '1': i32 [139; 140) 'a': A diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 07007d03fc..6a9358d333 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -1,4 +1,4 @@ -use hir::{Ty, Def}; +use hir::{Ty, AdtDef}; use crate::completion::{CompletionContext, Completions, CompletionItem, CompletionItemKind}; use crate::completion::completion_item::CompletionKind; @@ -28,8 +28,8 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) Ty::Adt { def_id, ref substs, .. } => { - match def_id.resolve(ctx.db) { - Def::Struct(s) => { + match def_id { + AdtDef::Struct(s) => { for field in s.fields(ctx.db) { CompletionItem::new( CompletionKind::Reference, @@ -41,8 +41,9 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) .add_to(acc); } } + // TODO unions - _ => {} + AdtDef::Enum(_) => (), } } Ty::Tuple(fields) => { diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index e44b76c4a9..e72586e2e5 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -13,8 +13,8 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { Some(it) => it, None => return, }; - match def_id.resolve(ctx.db) { - hir::Def::Module(module) => { + match def_id { + hir::ModuleDef::Module(module) => { let module_scope = module.scope(ctx.db); for (name, res) in module_scope.entries() { CompletionItem::new( @@ -26,7 +26,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { .add_to(acc); } } - hir::Def::Enum(e) => { + hir::ModuleDef::Enum(e) => { e.variants(ctx.db) .into_iter() .for_each(|(variant_name, variant)| { diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs index ca2069e2a7..578af6e5b3 100644 --- a/crates/ra_ide_api/src/completion/completion_context.rs +++ b/crates/ra_ide_api/src/completion/completion_context.rs @@ -127,7 +127,7 @@ impl<'a> CompletionContext<'a> { .ancestors() .take_while(|it| it.kind() != SOURCE_FILE && it.kind() != MODULE) .find_map(ast::FnDef::cast); - match (&self.module, self.function_syntax) { + match (self.module, self.function_syntax) { (Some(module), Some(fn_def)) => { let function = source_binder::function_from_module(self.db, module, fn_def); self.function = Some(function); diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index 18c151932a..3ba6c33ee6 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -1,6 +1,4 @@ -use hir::{Docs, Documentation, PerNs}; - -use crate::completion::completion_context::CompletionContext; +use hir::{Docs, Documentation}; use ra_syntax::{ ast::{self, AstNode}, TextRange, @@ -8,6 +6,8 @@ use ra_syntax::{ use ra_text_edit::TextEdit; use test_utils::tested_by; +use crate::completion::completion_context::CompletionContext; + /// `CompletionItem` describes a single completion variant in the editor pop-up. /// It is basically a POD with various properties. To construct a /// `CompletionItem`, use `new` method and the `Builder` struct. @@ -209,41 +209,24 @@ impl Builder { ctx: &CompletionContext, resolution: &hir::Resolution, ) -> Builder { - let resolved = resolution.def_id.map(|d| d.resolve(ctx.db)); - let (kind, docs) = match resolved { - PerNs { - types: Some(hir::Def::Module(..)), - .. - } => (CompletionItemKind::Module, None), - PerNs { - types: Some(hir::Def::Struct(s)), - .. - } => (CompletionItemKind::Struct, s.docs(ctx.db)), - PerNs { - types: Some(hir::Def::Enum(e)), - .. - } => (CompletionItemKind::Enum, e.docs(ctx.db)), - PerNs { - types: Some(hir::Def::Trait(t)), - .. - } => (CompletionItemKind::Trait, t.docs(ctx.db)), - PerNs { - types: Some(hir::Def::Type(t)), - .. - } => (CompletionItemKind::TypeAlias, t.docs(ctx.db)), - PerNs { - values: Some(hir::Def::Const(c)), - .. - } => (CompletionItemKind::Const, c.docs(ctx.db)), - PerNs { - values: Some(hir::Def::Static(s)), - .. - } => (CompletionItemKind::Static, s.docs(ctx.db)), - PerNs { - values: Some(hir::Def::Function(function)), - .. - } => return self.from_function(ctx, function), - _ => return self, + let def = resolution + .def_id + .take_types() + .or(resolution.def_id.take_values()); + let def = match def { + None => return self, + Some(it) => it, + }; + let (kind, docs) = match def { + hir::ModuleDef::Module(_) => (CompletionItemKind::Module, None), + hir::ModuleDef::Function(func) => return self.from_function(ctx, func), + hir::ModuleDef::Struct(it) => (CompletionItemKind::Struct, it.docs(ctx.db)), + hir::ModuleDef::Enum(it) => (CompletionItemKind::Enum, it.docs(ctx.db)), + hir::ModuleDef::EnumVariant(it) => (CompletionItemKind::EnumVariant, it.docs(ctx.db)), + hir::ModuleDef::Const(it) => (CompletionItemKind::Const, it.docs(ctx.db)), + hir::ModuleDef::Static(it) => (CompletionItemKind::Static, it.docs(ctx.db)), + hir::ModuleDef::Trait(it) => (CompletionItemKind::Trait, it.docs(ctx.db)), + hir::ModuleDef::Type(it) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)), }; self.kind = Some(kind); self.documentation = docs; diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs index ba0eb1cb8a..bff6b7237a 100644 --- a/crates/ra_ide_api/src/db.rs +++ b/crates/ra_ide_api/src/db.rs @@ -72,6 +72,7 @@ salsa::database_storage! { fn file_relative_path() for ra_db::FileRelativePathQuery; fn file_source_root() for ra_db::FileSourceRootQuery; fn source_root() for ra_db::SourceRootQuery; + fn source_root_crates() for ra_db::SourceRootCratesQuery; fn local_roots() for ra_db::LocalRootsQuery; fn library_roots() for ra_db::LibraryRootsQuery; fn crate_graph() for ra_db::CrateGraphQuery; diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs index b1becca031..46bdde00d7 100644 --- a/crates/ra_ide_api/src/goto_definition.rs +++ b/crates/ra_ide_api/src/goto_definition.rs @@ -63,13 +63,11 @@ pub(crate) fn reference_definition( let infer_result = function.infer(db); let syntax_mapping = function.body_syntax_mapping(db); let expr = ast::Expr::cast(method_call.syntax()).unwrap(); - if let Some(def_id) = syntax_mapping + if let Some(func) = syntax_mapping .node_expr(expr) .and_then(|it| infer_result.method_resolution(it)) { - if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)) { - return Exact(target); - } + return Exact(NavigationTarget::from_function(db, func)); }; } } @@ -84,7 +82,7 @@ pub(crate) fn reference_definition( { let resolved = module.resolve_path(db, &path); if let Some(def_id) = resolved.take_types().or(resolved.take_values()) { - if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)) { + if let Some(target) = NavigationTarget::from_def(db, def_id) { return Exact(target); } } diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs index 21c15c0c00..c5be8e01be 100644 --- a/crates/ra_ide_api/src/navigation_target.rs +++ b/crates/ra_ide_api/src/navigation_target.rs @@ -3,7 +3,7 @@ use ra_syntax::{ SyntaxNode, AstNode, SmolStr, TextRange, ast, SyntaxKind::{self, NAME}, }; -use hir::{Def, ModuleSource}; +use hir::{ModuleSource}; use crate::{FileSymbol, db::RootDatabase}; @@ -96,45 +96,69 @@ impl NavigationTarget { NavigationTarget::from_module(db, module) } + pub(crate) fn from_function(db: &RootDatabase, func: hir::Function) -> NavigationTarget { + let (file_id, fn_def) = func.source(db); + NavigationTarget::from_named(file_id.original_file(db), &*fn_def) + } + // TODO once Def::Item is gone, this should be able to always return a NavigationTarget - pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Option { - let res = match def { - Def::Struct(s) => { + pub(crate) fn from_def( + db: &RootDatabase, + module_def: hir::ModuleDef, + ) -> Option { + match module_def { + hir::ModuleDef::Module(module) => Some(NavigationTarget::from_module(db, module)), + hir::ModuleDef::Function(func) => Some(NavigationTarget::from_function(db, func)), + hir::ModuleDef::Struct(s) => { let (file_id, node) = s.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) } - Def::Enum(e) => { + hir::ModuleDef::Const(s) => { + let (file_id, node) = s.source(db); + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) + } + hir::ModuleDef::Static(s) => { + let (file_id, node) = s.source(db); + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) + } + hir::ModuleDef::Enum(e) => { let (file_id, node) = e.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) } - Def::EnumVariant(ev) => { - let (file_id, node) = ev.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) + hir::ModuleDef::EnumVariant(var) => { + let (file_id, node) = var.source(db); + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) } - Def::Function(f) => { - let (file_id, node) = f.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) + hir::ModuleDef::Trait(e) => { + let (file_id, node) = e.source(db); + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) } - Def::Trait(f) => { - let (file_id, node) = f.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) + hir::ModuleDef::Type(e) => { + let (file_id, node) = e.source(db); + Some(NavigationTarget::from_named( + file_id.original_file(db), + &*node, + )) } - Def::Type(f) => { - let (file_id, node) = f.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - Def::Static(f) => { - let (file_id, node) = f.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - Def::Const(f) => { - let (file_id, node) = f.source(db); - NavigationTarget::from_named(file_id.original_file(db), &*node) - } - Def::Module(m) => NavigationTarget::from_module(db, m), - Def::Item => return None, - }; - Some(res) + } } #[cfg(test)] diff --git a/crates/ra_ide_api/src/rename.rs b/crates/ra_ide_api/src/rename.rs index 53dc273c63..5b767addd3 100644 --- a/crates/ra_ide_api/src/rename.rs +++ b/crates/ra_ide_api/src/rename.rs @@ -57,7 +57,6 @@ fn rename_mod( ) -> Option { let mut source_file_edits = Vec::new(); let mut file_system_edits = Vec::new(); - if let Some(module) = module_from_declaration(db, position.file_id, &ast_module) { let (file_id, module_source) = module.definition_source(db); match module_source { @@ -223,11 +222,15 @@ mod tests { fn test_rename_mod() { let (analysis, position) = analysis_and_position( " - //- /bar.rs - mod fo<|>o; - //- /bar/foo.rs - // emtpy - ", + //- /lib.rs + mod bar; + + //- /bar.rs + mod foo<|>; + + //- /bar/foo.rs + // emtpy + ", ); let new_name = "foo2"; let source_change = analysis.rename(position, new_name).unwrap(); @@ -238,11 +241,11 @@ mod tests { fn test_rename_mod_in_dir() { let (analysis, position) = analysis_and_position( " - //- /lib.rs - mod fo<|>o; - //- /foo/mod.rs - // emtpy - ", + //- /lib.rs + mod fo<|>o; + //- /foo/mod.rs + // emtpy + ", ); let new_name = "foo2"; let source_change = analysis.rename(position, new_name).unwrap(); diff --git a/crates/ra_ide_api/src/snapshots/tests__rename_mod.snap b/crates/ra_ide_api/src/snapshots/tests__rename_mod.snap index 3267d1ac5a..890426db77 100644 --- a/crates/ra_ide_api/src/snapshots/tests__rename_mod.snap +++ b/crates/ra_ide_api/src/snapshots/tests__rename_mod.snap @@ -1,8 +1,8 @@ --- -created: "2019-01-22T14:45:00.975229300+00:00" -creator: insta@0.4.0 +created: "2019-01-24T08:39:53.759318522+00:00" +creator: insta@0.5.2 expression: "&source_change" -source: "crates\\ra_ide_api\\src\\rename.rs" +source: crates/ra_ide_api/src/rename.rs --- Some( SourceChange { @@ -10,7 +10,7 @@ Some( source_file_edits: [ SourceFileEdit { file_id: FileId( - 1 + 2 ), edit: TextEdit { atoms: [ @@ -25,7 +25,7 @@ Some( file_system_edits: [ MoveFile { src: FileId( - 2 + 3 ), dst_source_root: SourceRootId( 0 diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs index bcbd4c60c7..fd65264b27 100644 --- a/crates/ra_syntax/src/ast.rs +++ b/crates/ra_syntax/src/ast.rs @@ -430,6 +430,13 @@ impl StructDef { } impl EnumVariant { + pub fn parent_enum(&self) -> &EnumDef { + self.syntax() + .parent() + .and_then(|it| it.parent()) + .and_then(EnumDef::cast) + .expect("EnumVariants are always nested in Enums") + } pub fn flavor(&self) -> StructFlavor { StructFlavor::from_node(self) } diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index ac6c8a8359..a207f8429f 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -3229,6 +3229,7 @@ impl ast::VisibilityOwner for TraitDef {} impl ast::NameOwner for TraitDef {} impl ast::AttrsOwner for TraitDef {} impl ast::DocCommentsOwner for TraitDef {} +impl ast::TypeParamsOwner for TraitDef {} impl TraitDef {} // TrueKw diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index c5297e46dd..dedefea591 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -280,7 +280,7 @@ Grammar( ], options: [["variant_list", "EnumVariantList"]] ), "EnumVariantList": ( collections: [["variants", "EnumVariant"]] ), "EnumVariant": ( traits: ["NameOwner", "DocCommentsOwner"], options: ["Expr"] ), - "TraitDef": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner"] ), + "TraitDef": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner", "TypeParamsOwner"] ), "Module": ( traits: ["VisibilityOwner", "NameOwner", "AttrsOwner", "DocCommentsOwner" ], options: [ "ItemList" ] @@ -489,7 +489,7 @@ Grammar( ), "RefPat": ( options: [ "Pat" ]), - "BindPat": ( + "BindPat": ( options: [ "Pat" ], traits: ["NameOwner"] ),