Move FunctionData to hir_def

This commit is contained in:
Aleksey Kladov 2019-11-22 17:10:51 +03:00
parent a132cc715e
commit 78f3b0627c
14 changed files with 114 additions and 116 deletions

View file

@ -13,7 +13,7 @@ use hir_def::{
nameres::per_ns::PerNs, nameres::per_ns::PerNs,
resolver::{HasResolver, TypeNs}, resolver::{HasResolver, TypeNs},
traits::TraitData, traits::TraitData,
type_ref::{Mutability, TypeRef}, type_ref::TypeRef,
ContainerId, CrateModuleId, HasModule, ImplId, LocalEnumVariantId, LocalStructFieldId, Lookup, ContainerId, CrateModuleId, HasModule, ImplId, LocalEnumVariantId, LocalStructFieldId, Lookup,
ModuleId, UnionId, ModuleId, UnionId,
}; };
@ -561,77 +561,6 @@ pub struct Function {
pub(crate) id: FunctionId, pub(crate) id: FunctionId,
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FnData {
pub(crate) name: Name,
pub(crate) params: Vec<TypeRef>,
pub(crate) ret_type: TypeRef,
/// True if the first param is `self`. This is relevant to decide whether this
/// can be called as a method.
pub(crate) has_self_param: bool,
}
impl FnData {
pub(crate) fn fn_data_query(
db: &(impl DefDatabase + AstDatabase),
func: Function,
) -> Arc<FnData> {
let src = func.source(db);
let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
let mut params = Vec::new();
let mut has_self_param = false;
if let Some(param_list) = src.value.param_list() {
if let Some(self_param) = param_list.self_param() {
let self_type = if let Some(type_ref) = self_param.ascribed_type() {
TypeRef::from_ast(type_ref)
} else {
let self_type = TypeRef::Path(name::SELF_TYPE.into());
match self_param.kind() {
ast::SelfParamKind::Owned => self_type,
ast::SelfParamKind::Ref => {
TypeRef::Reference(Box::new(self_type), Mutability::Shared)
}
ast::SelfParamKind::MutRef => {
TypeRef::Reference(Box::new(self_type), Mutability::Mut)
}
}
};
params.push(self_type);
has_self_param = true;
}
for param in param_list.params() {
let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
params.push(type_ref);
}
}
let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
TypeRef::from_ast(type_ref)
} else {
TypeRef::unit()
};
let sig = FnData { name, params, ret_type, has_self_param };
Arc::new(sig)
}
pub fn name(&self) -> &Name {
&self.name
}
pub fn params(&self) -> &[TypeRef] {
&self.params
}
pub fn ret_type(&self) -> &TypeRef {
&self.ret_type
}
/// True if the first arg is `self`. This is relevant to decide whether this
/// can be called as a method.
pub fn has_self_param(&self) -> bool {
self.has_self_param
}
}
impl Function { impl Function {
pub fn module(self, db: &impl DefDatabase) -> Module { pub fn module(self, db: &impl DefDatabase) -> Module {
self.id.lookup(db).module(db).into() self.id.lookup(db).module(db).into()
@ -642,7 +571,15 @@ impl Function {
} }
pub fn name(self, db: &impl HirDatabase) -> Name { pub fn name(self, db: &impl HirDatabase) -> Name {
self.data(db).name.clone() db.function_data(self.id).name.clone()
}
pub fn has_self_param(self, db: &impl HirDatabase) -> bool {
db.function_data(self.id).has_self_param
}
pub fn params(self, db: &impl HirDatabase) -> Vec<TypeRef> {
db.function_data(self.id).params.clone()
} }
pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> { pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
@ -657,10 +594,6 @@ impl Function {
db.type_for_def(self.into(), Namespace::Values) db.type_for_def(self.into(), Namespace::Values)
} }
pub fn data(self, db: &impl HirDatabase) -> Arc<FnData> {
db.fn_data(self)
}
pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> { pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
db.infer(self.into()) db.infer(self.into())
} }

View file

@ -16,15 +16,15 @@ use crate::{
CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef, CallableDef, FnSig, GenericPredicate, InferenceResult, Namespace, Substs, Ty, TypableDef,
TypeCtor, TypeCtor,
}, },
Const, ConstData, Crate, DefWithBody, FnData, Function, GenericDef, ImplBlock, Module, Static, Const, ConstData, Crate, DefWithBody, GenericDef, ImplBlock, Module, Static, StructField,
StructField, Trait, Trait,
}; };
pub use hir_def::db::{ pub use hir_def::db::{
BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage,
EnumDataQuery, ExprScopesQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, EnumDataQuery, ExprScopesQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery,
InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery,
TraitDataQuery, TypeAliasDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery,
}; };
pub use hir_expand::db::{ pub use hir_expand::db::{
AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
@ -35,9 +35,6 @@ pub use hir_expand::db::{
#[salsa::query_group(DefDatabaseStorage)] #[salsa::query_group(DefDatabaseStorage)]
#[salsa::requires(AstDatabase)] #[salsa::requires(AstDatabase)]
pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { pub trait DefDatabase: HirDebugDatabase + DefDatabase2 {
#[salsa::invoke(FnData::fn_data_query)]
fn fn_data(&self, func: Function) -> Arc<FnData>;
#[salsa::invoke(ConstData::const_data_query)] #[salsa::invoke(ConstData::const_data_query)]
fn const_data(&self, konst: Const) -> Arc<ConstData>; fn const_data(&self, konst: Const) -> Arc<ConstData>;

View file

@ -55,9 +55,9 @@ pub use crate::{
docs::{DocDef, Docs, Documentation}, docs::{DocDef, Docs, Documentation},
src::{HasBodySource, HasSource}, src::{HasBodySource, HasSource},
Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum,
EnumVariant, FieldSource, FnData, Function, GenericDef, GenericParam, HasBody, ImplBlock, EnumVariant, FieldSource, Function, GenericDef, GenericParam, HasBody, ImplBlock, Local,
Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, Static, Struct, StructField, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, Static, Struct, StructField, Trait,
Trait, TypeAlias, Union, VariantDef, TypeAlias, Union, VariantDef,
}, },
expr::ExprScopes, expr::ExprScopes,
from_source::FromSource, from_source::FromSource,

View file

@ -22,6 +22,7 @@ use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use hir_def::{ use hir_def::{
function::FunctionData,
path::known, path::known,
resolver::{HasResolver, Resolver, TypeNs}, resolver::{HasResolver, Resolver, TypeNs},
type_ref::{Mutability, TypeRef}, type_ref::{Mutability, TypeRef},
@ -43,8 +44,8 @@ use crate::{
db::HirDatabase, db::HirDatabase,
expr::{BindingAnnotation, Body, ExprId, PatId}, expr::{BindingAnnotation, Body, ExprId, PatId},
ty::infer::diagnostics::InferenceDiagnostic, ty::infer::diagnostics::InferenceDiagnostic,
Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, HasBody, IntTy, Path, Adt, AssocItem, ConstData, DefWithBody, FloatTy, Function, HasBody, IntTy, Path, StructField,
StructField, Trait, VariantDef, Trait, VariantDef,
}; };
macro_rules! ty_app { macro_rules! ty_app {
@ -70,7 +71,7 @@ pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResu
match def { match def {
DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)), DefWithBody::Const(ref c) => ctx.collect_const(&c.data(db)),
DefWithBody::Function(ref f) => ctx.collect_fn(&f.data(db)), DefWithBody::Function(ref f) => ctx.collect_fn(&db.function_data(f.id)),
DefWithBody::Static(ref s) => ctx.collect_const(&s.data(db)), DefWithBody::Static(ref s) => ctx.collect_const(&s.data(db)),
} }
@ -562,14 +563,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.return_ty = self.make_ty(data.type_ref()); self.return_ty = self.make_ty(data.type_ref());
} }
fn collect_fn(&mut self, data: &FnData) { fn collect_fn(&mut self, data: &FunctionData) {
let body = Arc::clone(&self.body); // avoid borrow checker problem let body = Arc::clone(&self.body); // avoid borrow checker problem
for (type_ref, pat) in data.params().iter().zip(body.params()) { for (type_ref, pat) in data.params.iter().zip(body.params()) {
let ty = self.make_ty(type_ref); let ty = self.make_ty(type_ref);
self.infer_pat(*pat, &ty, BindingMode::default()); self.infer_pat(*pat, &ty, BindingMode::default());
} }
self.return_ty = self.make_ty(data.ret_type()); self.return_ty = self.make_ty(&data.ret_type);
} }
fn infer_body(&mut self) { fn infer_body(&mut self) {

View file

@ -622,10 +622,10 @@ pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDef) ->
} }
fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
let data = def.data(db); let data = db.function_data(def.id);
let resolver = def.id.resolver(db); let resolver = def.id.resolver(db);
let params = data.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>(); let params = data.params.iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
let ret = Ty::from_hir(db, &resolver, data.ret_type()); let ret = Ty::from_hir(db, &resolver, &data.ret_type);
FnSig::from_params_and_return(params, ret) FnSig::from_params_and_return(params, ret)
} }

View file

@ -291,9 +291,9 @@ fn is_valid_candidate(
) -> bool { ) -> bool {
match item { match item {
AssocItem::Function(m) => { AssocItem::Function(m) => {
let data = m.data(db); let data = db.function_data(m.id);
name.map_or(true, |name| data.name() == name) name.map_or(true, |name| data.name == *name)
&& (data.has_self_param() || mode == LookupMode::Path) && (data.has_self_param || mode == LookupMode::Path)
} }
AssocItem::Const(c) => { AssocItem::Const(c) => {
name.map_or(true, |name| Some(name) == c.name(db).as_ref()) name.map_or(true, |name| Some(name) == c.name(db).as_ref())

View file

@ -8,6 +8,7 @@ use ra_syntax::ast;
use crate::{ use crate::{
adt::{EnumData, StructData}, adt::{EnumData, StructData},
body::{scope::ExprScopes, Body, BodySourceMap}, body::{scope::ExprScopes, Body, BodySourceMap},
function::FunctionData,
generics::GenericParams, generics::GenericParams,
impls::ImplData, impls::ImplData,
nameres::{ nameres::{
@ -16,7 +17,8 @@ use crate::{
}, },
traits::TraitData, traits::TraitData,
type_alias::TypeAliasData, type_alias::TypeAliasData,
DefWithBodyId, EnumId, GenericDefId, ImplId, ItemLoc, StructOrUnionId, TraitId, TypeAliasId, DefWithBodyId, EnumId, FunctionId, GenericDefId, ImplId, ItemLoc, StructOrUnionId, TraitId,
TypeAliasId,
}; };
#[salsa::query_group(InternDatabaseStorage)] #[salsa::query_group(InternDatabaseStorage)]
@ -68,6 +70,9 @@ pub trait DefDatabase2: InternDatabase + AstDatabase {
#[salsa::invoke(TypeAliasData::type_alias_data_query)] #[salsa::invoke(TypeAliasData::type_alias_data_query)]
fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>; fn type_alias_data(&self, e: TypeAliasId) -> Arc<TypeAliasData>;
#[salsa::invoke(FunctionData::fn_data_query)]
fn function_data(&self, func: FunctionId) -> Arc<FunctionData>;
#[salsa::invoke(Body::body_with_source_map_query)] #[salsa::invoke(Body::body_with_source_map_query)]
fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>); fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc<Body>, Arc<BodySourceMap>);

View file

@ -0,0 +1,61 @@
use std::sync::Arc;
use hir_expand::name::{self, AsName, Name};
use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
use crate::{
db::DefDatabase2,
type_ref::{Mutability, TypeRef},
FunctionId, HasSource, Lookup,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FunctionData {
pub name: Name,
pub params: Vec<TypeRef>,
pub ret_type: TypeRef,
/// True if the first param is `self`. This is relevant to decide whether this
/// can be called as a method.
pub has_self_param: bool,
}
impl FunctionData {
pub(crate) fn fn_data_query(db: &impl DefDatabase2, func: FunctionId) -> Arc<FunctionData> {
let src = func.lookup(db).source(db);
let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing);
let mut params = Vec::new();
let mut has_self_param = false;
if let Some(param_list) = src.value.param_list() {
if let Some(self_param) = param_list.self_param() {
let self_type = if let Some(type_ref) = self_param.ascribed_type() {
TypeRef::from_ast(type_ref)
} else {
let self_type = TypeRef::Path(name::SELF_TYPE.into());
match self_param.kind() {
ast::SelfParamKind::Owned => self_type,
ast::SelfParamKind::Ref => {
TypeRef::Reference(Box::new(self_type), Mutability::Shared)
}
ast::SelfParamKind::MutRef => {
TypeRef::Reference(Box::new(self_type), Mutability::Mut)
}
}
};
params.push(self_type);
has_self_param = true;
}
for param in param_list.params() {
let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
params.push(type_ref);
}
}
let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) {
TypeRef::from_ast(type_ref)
} else {
TypeRef::unit()
};
let sig = FunctionData { name, params, ret_type, has_self_param };
Arc::new(sig)
}
}

View file

@ -21,6 +21,7 @@ pub mod generics;
pub mod traits; pub mod traits;
pub mod resolver; pub mod resolver;
pub mod type_alias; pub mod type_alias;
pub mod function;
#[cfg(test)] #[cfg(test)]
mod test_db; mod test_db;

View file

@ -30,7 +30,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?; let (callable_def, _subst) = analyzer.type_of(db, &expr.expr()?)?.as_callable()?;
match callable_def { match callable_def {
hir::CallableDef::Function(it) => { hir::CallableDef::Function(it) => {
(CallInfo::with_fn(db, it), it.data(db).has_self_param()) (CallInfo::with_fn(db, it), it.has_self_param(db))
} }
hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it)?, false), hir::CallableDef::Struct(it) => (CallInfo::with_struct(db, it)?, false),
hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it)?, false), hir::CallableDef::EnumVariant(it) => (CallInfo::with_enum_variant(db, it)?, false),
@ -38,7 +38,7 @@ pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<Cal
} }
FnCallNode::MethodCallExpr(expr) => { FnCallNode::MethodCallExpr(expr) => {
let function = analyzer.resolve_method_call(&expr)?; let function = analyzer.resolve_method_call(&expr)?;
(CallInfo::with_fn(db, function), function.data(db).has_self_param()) (CallInfo::with_fn(db, function), function.has_self_param(db))
} }
FnCallNode::MacroCallExpr(expr) => { FnCallNode::MacroCallExpr(expr) => {
let macro_def = analyzer.resolve_macro_call(db, &expr)?; let macro_def = analyzer.resolve_macro_call(db, &expr)?;

View file

@ -313,7 +313,7 @@ impl RootDatabase {
hir::db::RawItemsQuery hir::db::RawItemsQuery
hir::db::CrateDefMapQuery hir::db::CrateDefMapQuery
hir::db::GenericParamsQuery hir::db::GenericParamsQuery
hir::db::FnDataQuery hir::db::FunctionDataQuery
hir::db::TypeAliasDataQuery hir::db::TypeAliasDataQuery
hir::db::ConstDataQuery hir::db::ConstDataQuery
hir::db::StaticDataQuery hir::db::StaticDataQuery

View file

@ -59,8 +59,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
let mut seen_methods = FxHashSet::default(); let mut seen_methods = FxHashSet::default();
ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| { ctx.analyzer.iterate_method_candidates(ctx.db, receiver, None, |_ty, func| {
let data = func.data(ctx.db); if func.has_self_param(ctx.db) && seen_methods.insert(func.name(ctx.db)) {
if data.has_self_param() && seen_methods.insert(data.name().clone()) {
acc.add_function(ctx, func); acc.add_function(ctx, func);
} }
None::<()> None::<()>

View file

@ -53,8 +53,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
ctx.analyzer.iterate_path_candidates(ctx.db, ty.clone(), None, |_ty, item| { ctx.analyzer.iterate_path_candidates(ctx.db, ty.clone(), None, |_ty, item| {
match item { match item {
hir::AssocItem::Function(func) => { hir::AssocItem::Function(func) => {
let data = func.data(ctx.db); if !func.has_self_param(ctx.db) {
if !data.has_self_param() {
acc.add_function(ctx, func); acc.add_function(ctx, func);
} }
} }
@ -80,8 +79,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
for item in t.items(ctx.db) { for item in t.items(ctx.db) {
match item { match item {
hir::AssocItem::Function(func) => { hir::AssocItem::Function(func) => {
let data = func.data(ctx.db); if !func.has_self_param(ctx.db) {
if !data.has_self_param() {
acc.add_function(ctx, func); acc.add_function(ctx, func);
} }
} }

View file

@ -199,14 +199,17 @@ impl Completions {
name: Option<String>, name: Option<String>,
func: hir::Function, func: hir::Function,
) { ) {
let data = func.data(ctx.db); let func_name = func.name(ctx.db);
let name = name.unwrap_or_else(|| data.name().to_string()); let has_self_param = func.has_self_param(ctx.db);
let params = func.params(ctx.db);
let name = name.unwrap_or_else(|| func_name.to_string());
let ast_node = func.source(ctx.db).value; let ast_node = func.source(ctx.db).value;
let detail = function_label(&ast_node); let detail = function_label(&ast_node);
let mut builder = let mut builder =
CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
.kind(if data.has_self_param() { .kind(if has_self_param {
CompletionItemKind::Method CompletionItemKind::Method
} else { } else {
CompletionItemKind::Function CompletionItemKind::Function
@ -222,10 +225,10 @@ impl Completions {
{ {
tested_by!(inserts_parens_for_function_calls); tested_by!(inserts_parens_for_function_calls);
let (snippet, label) = let (snippet, label) =
if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 { if params.is_empty() || has_self_param && params.len() == 1 {
(format!("{}()$0", data.name()), format!("{}()", name)) (format!("{}()$0", func_name), format!("{}()", name))
} else { } else {
(format!("{}($0)", data.name()), format!("{}(…)", name)) (format!("{}($0)", func_name), format!("{}(…)", name))
}; };
builder = builder.lookup_by(name).label(label).insert_snippet(snippet); builder = builder.lookup_by(name).label(label).insert_snippet(snippet);
} }