From ec7ed054e06cb2e23fd3911932766b32014c8fa1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 24 Jan 2019 15:28:50 +0300 Subject: Functions use new id scheme --- crates/ra_hir/src/code_model_api.rs | 39 +++--- crates/ra_hir/src/code_model_impl/function.rs | 29 +++-- crates/ra_hir/src/code_model_impl/module.rs | 1 + crates/ra_hir/src/db.rs | 20 +-- crates/ra_hir/src/expr.rs | 22 ++-- crates/ra_hir/src/generics.rs | 66 +++++++--- crates/ra_hir/src/ids.rs | 66 +++++++--- crates/ra_hir/src/impl_block.rs | 31 +++-- crates/ra_hir/src/nameres/lower.rs | 13 +- crates/ra_hir/src/query_definitions.rs | 8 +- crates/ra_hir/src/source_binder.rs | 19 +-- crates/ra_hir/src/ty.rs | 180 +++++++++++++++----------- crates/ra_hir/src/ty/method_resolution.rs | 4 +- 13 files changed, 297 insertions(+), 201 deletions(-) (limited to 'crates/ra_hir/src') diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs index f59a60c07..905615127 100644 --- a/crates/ra_hir/src/code_model_api.rs +++ b/crates/ra_hir/src/code_model_api.rs @@ -16,6 +16,7 @@ use crate::{ code_model_impl::def_id_to_ast, docs::{Documentation, Docs, docs_from_ast}, module_tree::ModuleId, + ids::FunctionId, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -49,7 +50,6 @@ pub enum Def { Struct(Struct), Enum(Enum), EnumVariant(EnumVariant), - Function(Function), Const(Const), Static(Static), Trait(Trait), @@ -67,6 +67,7 @@ pub struct Module { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ModuleDef { Module(Module), + Function(Function), Def(DefId), } @@ -76,6 +77,12 @@ impl Into for Module { } } +impl Into for Function { + fn into(self) -> ModuleDef { + ModuleDef::Function(self) + } +} + impl Into for DefId { fn into(self) -> ModuleDef { ModuleDef::Def(self) @@ -225,7 +232,7 @@ impl Struct { } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params(self.def_id.into()) } } @@ -262,7 +269,7 @@ impl Enum { } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params(self.def_id.into()) } } @@ -320,9 +327,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; @@ -359,21 +366,17 @@ impl FnSignature { } impl Function { - pub fn def_id(&self) -> DefId { - self.def_id - } - pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { - def_id_to_ast(db, self.def_id) + self.id.loc(db).source(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, @@ -381,15 +384,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()) } } @@ -456,7 +459,7 @@ impl Trait { } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params(self.def_id.into()) } } @@ -481,7 +484,7 @@ impl Type { } pub fn generic_params(&self, db: &impl HirDatabase) -> Arc { - db.generic_params(self.def_id) + db.generic_params(self.def_id.into()) } } diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs index c68c6bfbf..d8dafb10e 100644 --- a/crates/ra_hir/src/code_model_impl/function.rs +++ b/crates/ra_hir/src/code_model_impl/function.rs @@ -2,41 +2,48 @@ 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, Module, HirFileId, type_ref::{TypeRef, Mutability}, expr::Body, impl_block::ImplBlock, - code_model_impl::def_id_to_ast, + ids::FunctionLoc, }; pub use self::scope::{FnScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax}; impl Function { - pub(crate) fn new(def_id: DefId) -> Function { - Function { def_id } + pub(crate) fn from_ast( + db: &impl HirDatabase, + module: Module, + file_id: HirFileId, + ast: &ast::FnDef, + ) -> Function { + let loc: FunctionLoc = FunctionLoc::from_ast(db, module, file_id, ast); + let id = loc.id(db); + Function { id } } pub(crate) fn body(&self, db: &impl HirDatabase) -> Arc { - db.body_hir(self.def_id) + db.body_hir(*self) } pub(crate) fn module(&self, db: &impl HirDatabase) -> Module { - self.def_id.module(db) + self.id.loc(db).module } /// 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/module.rs b/crates/ra_hir/src/code_model_impl/module.rs index 5d00e905b..b2828c7be 100644 --- a/crates/ra_hir/src/code_model_impl/module.rs +++ b/crates/ra_hir/src/code_model_impl/module.rs @@ -135,6 +135,7 @@ impl Module { None => PerNs::none(), } } + ModuleDef::Function(_) => PerNs::none(), ModuleDef::Def(def) => { match def.resolve(db) { Def::Enum(e) => { diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 0898daa3c..97de7da31 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -7,14 +7,14 @@ use crate::{ DefId, MacroCallId, Name, HirFileId, SourceFileItems, SourceItemId, Crate, Module, HirInterner, query_definitions, - FnSignature, FnScopes, + Function, FnSignature, FnScopes, macros::MacroExpansion, module_tree::ModuleTree, nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}}, - ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks}, + ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef}, adt::{StructData, EnumData, EnumVariantData}, impl_block::ModuleImplBlocks, - generics::GenericParams, + generics::{GenericParams, GenericDef}, }; #[salsa::query_group] @@ -26,7 +26,7 @@ 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; @@ -38,10 +38,10 @@ pub trait HirDatabase: SyntaxDatabase + AsRef { fn enum_variant_data(&self, def_id: DefId) -> 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; @@ -77,14 +77,14 @@ pub trait HirDatabase: SyntaxDatabase + AsRef { 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 1a3821692..29469af2c 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 d8248ad49..88c53705f 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, AstNode, NameOwner, TypeParamsOwner}; -use crate::{db::HirDatabase, DefId, Name, AsName}; +use crate::{db::HirDatabase, DefId, Name, AsName, Function}; /// Data about a generic parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug)] @@ -22,26 +22,62 @@ pub struct GenericParams { pub(crate) params: Vec, } +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum GenericDef { + Function(Function), + Def(DefId), +} + +impl From for GenericDef { + fn from(func: Function) -> GenericDef { + GenericDef::Function(func) + } +} + +impl From for GenericDef { + fn from(def_id: DefId) -> GenericDef { + GenericDef::Def(def_id) + } +} + 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(func) => { + let (_, fn_def) = func.source(db); + if let Some(type_param_list) = fn_def.type_param_list() { + generics.fill(type_param_list) + } + } + GenericDef::Def(def_id) => { + let (_file_id, node) = def_id.source(db); + if let Some(type_param_list) = node.children().find_map(ast::TypeParamList::cast) { + generics.fill(type_param_list) + } } } + Arc::new(generics) } + fn fill(&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 73f1379f1..913341bd5 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -1,9 +1,11 @@ +use std::marker::PhantomData; + use ra_db::{LocationIntener, FileId}; use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, ast}; use ra_arena::{Arena, RawId, impl_arena_id}; use crate::{ - HirDatabase, Def, Function, Struct, Enum, EnumVariant, ImplBlock, Crate, + HirDatabase, Def, Struct, Enum, EnumVariant, Crate, Module, Trait, Type, Static, Const, }; @@ -129,15 +131,56 @@ impl MacroCallLoc { } } +#[derive(Debug, PartialEq, Eq, Hash)] +pub struct ItemLoc { + pub(crate) module: Module, + raw: SourceItemId, + _ty: PhantomData, +} + +impl ItemLoc { + pub(crate) fn from_ast( + db: &impl HirDatabase, + module: Module, + file_id: HirFileId, + ast: &N, + ) -> ItemLoc { + let items = db.file_items(file_id); + let raw = SourceItemId { + file_id, + item_id: Some(items.id_of(file_id, ast.syntax())), + }; + ItemLoc { + module, + raw, + _ty: PhantomData, + } + } + + pub(crate) fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc) { + let syntax = db.file_item(self.raw); + let ast = N::cast(&syntax) + .unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", self.raw)) + .to_owned(); + (self.raw.file_id, ast) + } +} + +impl Clone for ItemLoc { + fn clone(&self) -> ItemLoc { + ItemLoc { + module: self.module, + raw: self.raw, + _ty: PhantomData, + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct FunctionId(RawId); impl_arena_id!(FunctionId); -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct FunctionLoc { - pub(crate) module: Module, - pub(crate) source_item_id: SourceItemId, -} +pub(crate) type FunctionLoc = ItemLoc; impl FunctionId { pub(crate) fn loc(self, db: &impl AsRef) -> FunctionLoc { @@ -196,10 +239,7 @@ impl DefId { pub fn resolve(self, db: &impl HirDatabase) -> Def { let loc = self.loc(db); match loc.kind { - DefKind::Function => { - let function = Function::new(self); - Def::Function(function) - } + DefKind::Function => unreachable!(), DefKind::Struct => { let struct_def = Struct::new(self); Def::Struct(struct_def) @@ -243,12 +283,6 @@ impl DefId { 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 module_impls = db.impls_in_module(self.loc(db).module); - ImplBlock::containing(module_impls, self) - } } impl DefLoc { diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs index ba8b84da2..29becd317 100644 --- a/crates/ra_hir/src/impl_block.rs +++ b/crates/ra_hir/src/impl_block.rs @@ -6,7 +6,7 @@ use ra_syntax::ast::{self, AstNode}; use crate::{ DefId, DefLoc, DefKind, SourceItemId, SourceFileItems, - Function, HirFileId, HirInterner, + Function, HirFileId, db::HirDatabase, type_ref::TypeRef, }; @@ -22,9 +22,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, @@ -64,7 +64,7 @@ pub struct ImplData { impl ImplData { pub(crate) fn from_ast( - db: &impl AsRef, + db: &impl HirDatabase, file_id: HirFileId, file_items: &SourceFileItems, module: Module, @@ -93,7 +93,9 @@ impl ImplData { }; let def_id = def_loc.id(db); match item_node.kind() { - ast::ImplItemKind::FnDef(..) => ImplItem::Method(Function::new(def_id)), + ast::ImplItemKind::FnDef(it) => { + ImplItem::Method(Function::from_ast(db, module, file_id, it)) + } ast::ImplItemKind::ConstDef(..) => ImplItem::Const(def_id), ast::ImplItemKind::TypeDef(..) => ImplItem::Type(def_id), } @@ -122,7 +124,8 @@ 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 @@ -131,13 +134,9 @@ pub enum ImplItem { // Existential } -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) } } @@ -153,7 +152,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 { @@ -181,8 +180,8 @@ impl ModuleImplBlocks { let impl_block = ImplData::from_ast(db, file_id, &source_file_items, 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); } } } diff --git a/crates/ra_hir/src/nameres/lower.rs b/crates/ra_hir/src/nameres/lower.rs index 6f003bd66..1f8adc7eb 100644 --- a/crates/ra_hir/src/nameres/lower.rs +++ b/crates/ra_hir/src/nameres/lower.rs @@ -9,7 +9,7 @@ use rustc_hash::FxHashMap; use crate::{ SourceItemId, Path, ModuleSource, HirDatabase, Name, SourceFileItems, - HirFileId, MacroCallLoc, AsName, PerNs, DefKind, DefLoc, + HirFileId, MacroCallLoc, AsName, PerNs, DefKind, DefLoc, Function, ModuleDef, Module, }; @@ -149,7 +149,14 @@ impl LoweredModule { 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::FnDef(it) => { + if let Some(name) = it.name() { + let func = Function::from_ast(db, module, file_id, it); + self.declarations + .insert(name.as_name(), PerNs::values(func.into())); + } + return; + } ast::ModuleItemKind::TraitDef(it) => it.name(), ast::ModuleItemKind::TypeDef(it) => it.name(), ast::ModuleItemKind::ImplBlock(_) => { @@ -218,7 +225,7 @@ fn assign_def_id( impl DefKind { fn for_syntax_kind(kind: SyntaxKind) -> PerNs { match kind { - SyntaxKind::FN_DEF => PerNs::values(DefKind::Function), + SyntaxKind::FN_DEF => unreachable!(), SyntaxKind::STRUCT_DEF => PerNs::both(DefKind::Struct, DefKind::StructCtor), SyntaxKind::ENUM_DEF => PerNs::types(DefKind::Enum), SyntaxKind::TRAIT_DEF => PerNs::types(DefKind::Trait), diff --git a/crates/ra_hir/src/query_definitions.rs b/crates/ra_hir/src/query_definitions.rs index a8ed887b3..cf8c7e435 100644 --- a/crates/ra_hir/src/query_definitions.rs +++ b/crates/ra_hir/src/query_definitions.rs @@ -10,14 +10,14 @@ use ra_syntax::{ use ra_db::{CrateId}; use crate::{ - SourceFileItems, SourceItemId, DefId, HirFileId, - FnScopes, Module, + 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) } diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c3bd31d6b..d1bf163d1 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -14,7 +14,7 @@ use ra_syntax::{ use crate::{ HirDatabase, Function, SourceItemId, ModuleDef, - DefKind, DefLoc, AsName, Module, + AsName, Module, }; /// Locates the module by `FileId`. Picks topmost module in the file. @@ -105,29 +105,18 @@ 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 (file_id, _) = module.definition_source(db); let file_id = file_id.into(); - 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 { - module: module.clone(), - kind: DefKind::Function, - source_item_id, - }; - Function::new(def_loc.id(db)) + Function::from_ast(db, module, file_id, fn_def) } pub fn function_from_child_node( diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 4c96579ee..f9cdbcab3 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -382,7 +382,8 @@ impl Ty { // Resolve in module (in type namespace) let resolved = match module.resolve_path(db, path).take_types() { - Some(ModuleDef::Def(r)) => r, + Some(ModuleDef::Def(r)) => r.into(), + Some(ModuleDef::Function(f)) => f.into(), None | Some(ModuleDef::Module(_)) => return Ty::Unknown, }; let ty = db.type_for_def(resolved); @@ -399,36 +400,38 @@ 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) => { - // 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 - // `Option::None::` are both allowed (though the former is - // preferred). See also `def_ids_for_path_segments` in rustc. - let len = path.segments.len(); - let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { - // Option::::None - &path.segments[len - 2] - } else { - // Option::None:: - last - }; - (ev.parent_enum(db).generic_params(db), segment) - } - _ => return Substs::empty(), + let (def_generics, segment) = match resolved { + TypableDef::Function(func) => (func.generic_params(db), last), + TypableDef::Def(def_id) => match def_id.resolve(db) { + Def::Struct(s) => (s.generic_params(db), last), + Def::Enum(e) => (e.generic_params(db), last), + Def::Trait(t) => (t.generic_params(db), last), + Def::EnumVariant(ev) => { + // 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 + // `Option::None::` are both allowed (though the former is + // preferred). See also `def_ids_for_path_segments` in rustc. + let len = path.segments.len(); + let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() + { + // Option::::None + &path.segments[len - 2] + } else { + // Option::None:: + last + }; + (ev.parent_enum(db).generic_params(db), segment) + } + _ => return Substs::empty(), + }, }; // substs_from_path if let Some(generic_args) = &segment.args_and_bindings { @@ -660,21 +663,40 @@ 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); +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum TypableDef { + Function(Function), + Def(DefId), +} + +impl From for TypableDef { + fn from(func: Function) -> TypableDef { + TypableDef::Function(func) + } +} + +impl From for TypableDef { + fn from(func: DefId) -> TypableDef { + TypableDef::Def(func) + } +} + +pub(super) fn type_for_def(db: &impl HirDatabase, def: TypableDef) -> Ty { match def { - 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 - } + TypableDef::Function(f) => type_for_fn(db, f), + TypableDef::Def(def_id) => match def_id.resolve(db) { + 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 + } + }, } } @@ -694,28 +716,23 @@ pub(super) fn type_for_field(db: &impl HirDatabase, def_id: DefId, field: Name) ), }; 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) } } @@ -745,7 +762,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. @@ -871,8 +888,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) { @@ -1060,7 +1077,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { // resolve in module let resolved = match self.module.resolve_path(self.db, &path).take_values()? { - ModuleDef::Def(it) => it, + ModuleDef::Def(it) => it.into(), + ModuleDef::Function(func) => func.into(), ModuleDef::Module(_) => return None, }; let ty = self.db.type_for_def(resolved); @@ -1073,8 +1091,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Some(path) => path, None => return (Ty::Unknown, None), }; - let def_id = match self.module.resolve_path(self.db, &path).take_types() { - Some(ModuleDef::Def(def_id)) => def_id, + let def = match self.module.resolve_path(self.db, &path).take_types() { + Some(ModuleDef::Def(def_id)) => def_id.into(), + Some(ModuleDef::Function(func)) => func.into(), _ => return (Ty::Unknown, None), }; // TODO remove the duplication between here and `Ty::from_path`? @@ -1086,20 +1105,23 @@ 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) => { - let ty = type_for_struct(self.db, s); - let ty = self.insert_type_vars(ty.apply_substs(substs)); - (ty, Some(def_id)) - } - Def::EnumVariant(ev) => { - let ty = type_for_enum_variant(self.db, ev); - let ty = self.insert_type_vars(ty.apply_substs(substs)); - (ty, Some(def_id)) - } - _ => (Ty::Unknown, None), + match def { + TypableDef::Def(def_id) => match def_id.resolve(self.db) { + Def::Struct(s) => { + let ty = type_for_struct(self.db, s); + let ty = self.insert_type_vars(ty.apply_substs(substs)); + (ty, Some(def_id)) + } + Def::EnumVariant(ev) => { + let ty = type_for_enum_variant(self.db, ev); + let ty = self.insert_type_vars(ty.apply_substs(substs)); + (ty, Some(def_id)) + } + _ => (Ty::Unknown, None), + }, + TypableDef::Function(_) => (Ty::Unknown, None), } } @@ -1216,7 +1238,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { .resolve_path(self.db, &path) .take_values() .and_then(|module_def| match module_def { - ModuleDef::Def(it) => Some(it), + ModuleDef::Def(it) => Some(it.into()), + ModuleDef::Function(func) => Some(func.into()), ModuleDef::Module(_) => None, }) .map_or(Ty::Unknown, |resolved| self.db.type_for_def(resolved)), @@ -1339,9 +1362,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, }; @@ -1610,16 +1633,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 a5567a78f..0084b24dc 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -118,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 } -- cgit v1.2.3