Use ImplItems instead of just Function

This commit is contained in:
Jeremy Kolb 2019-03-02 14:05:37 -05:00
parent 49da9a3e81
commit 3d8d880c59
3 changed files with 65 additions and 40 deletions

View file

@ -29,6 +29,7 @@ use crate::{
Function, StructField, Path, Name, Function, StructField, Path, Name,
FnSignature, AdtDef, FnSignature, AdtDef,
HirDatabase, HirDatabase,
ImplItem,
type_ref::{TypeRef, Mutability}, type_ref::{TypeRef, Mutability},
expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
generics::GenericParams, generics::GenericParams,
@ -54,8 +55,8 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
Arc::new(ctx.resolve_all()) Arc::new(ctx.resolve_all())
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
enum ExprOrPatId { pub enum ExprOrPatId {
Expr(ExprId), Expr(ExprId),
Pat(PatId), Pat(PatId),
} }
@ -79,8 +80,8 @@ pub struct InferenceResult {
method_resolutions: FxHashMap<ExprId, Function>, method_resolutions: FxHashMap<ExprId, Function>,
/// For each field access expr, records the field it resolves to. /// For each field access expr, records the field it resolves to.
field_resolutions: FxHashMap<ExprId, StructField>, field_resolutions: FxHashMap<ExprId, StructField>,
/// For each associated function call expr, records the function it resolves to /// For each associated item record what it resolves to
assoc_fn_resolutions: FxHashMap<ExprId, Function>, assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
pub(super) type_of_expr: ArenaMap<ExprId, Ty>, pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
pub(super) type_of_pat: ArenaMap<PatId, Ty>, pub(super) type_of_pat: ArenaMap<PatId, Ty>,
} }
@ -92,8 +93,8 @@ impl InferenceResult {
pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
self.field_resolutions.get(&expr).map(|it| *it) self.field_resolutions.get(&expr).map(|it| *it)
} }
pub fn assoc_fn_resolutions(&self, expr: ExprId) -> Option<Function> { pub fn assoc_resolutions(&self, id: ExprOrPatId) -> Option<ImplItem> {
self.assoc_fn_resolutions.get(&expr).map(|it| *it) self.assoc_resolutions.get(&id).map(|it| *it)
} }
} }
@ -122,7 +123,7 @@ struct InferenceContext<'a, D: HirDatabase> {
var_unification_table: InPlaceUnificationTable<TypeVarId>, var_unification_table: InPlaceUnificationTable<TypeVarId>,
method_resolutions: FxHashMap<ExprId, Function>, method_resolutions: FxHashMap<ExprId, Function>,
field_resolutions: FxHashMap<ExprId, StructField>, field_resolutions: FxHashMap<ExprId, StructField>,
assoc_fn_resolutions: FxHashMap<ExprId, Function>, assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
type_of_expr: ArenaMap<ExprId, Ty>, type_of_expr: ArenaMap<ExprId, Ty>,
type_of_pat: ArenaMap<PatId, Ty>, type_of_pat: ArenaMap<PatId, Ty>,
/// The return type of the function being inferred. /// The return type of the function being inferred.
@ -134,7 +135,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
InferenceContext { InferenceContext {
method_resolutions: FxHashMap::default(), method_resolutions: FxHashMap::default(),
field_resolutions: FxHashMap::default(), field_resolutions: FxHashMap::default(),
assoc_fn_resolutions: FxHashMap::default(), assoc_resolutions: FxHashMap::default(),
type_of_expr: ArenaMap::default(), type_of_expr: ArenaMap::default(),
type_of_pat: ArenaMap::default(), type_of_pat: ArenaMap::default(),
var_unification_table: InPlaceUnificationTable::new(), var_unification_table: InPlaceUnificationTable::new(),
@ -160,7 +161,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
InferenceResult { InferenceResult {
method_resolutions: self.method_resolutions, method_resolutions: self.method_resolutions,
field_resolutions: self.field_resolutions, field_resolutions: self.field_resolutions,
assoc_fn_resolutions: self.assoc_fn_resolutions, assoc_resolutions: self.assoc_resolutions,
type_of_expr: expr_types, type_of_expr: expr_types,
type_of_pat: pat_types, type_of_pat: pat_types,
} }
@ -178,8 +179,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
self.field_resolutions.insert(expr, field); self.field_resolutions.insert(expr, field);
} }
fn write_assoc_fn_resolution(&mut self, expr: ExprId, func: Function) { fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) {
self.assoc_fn_resolutions.insert(expr, func); self.assoc_resolutions.insert(id, item);
} }
fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
@ -423,26 +424,47 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
// Attempt to find an impl_item for the type which has a name matching // Attempt to find an impl_item for the type which has a name matching
// the current segment // the current segment
log::debug!("looking for path segment: {:?}", segment); log::debug!("looking for path segment: {:?}", segment);
let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| match item { let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| {
crate::ImplItem::Method(func) => { let matching_def: Option<crate::ModuleDef> = match item {
let sig = func.signature(self.db); crate::ImplItem::Method(func) => {
if segment.name == *sig.name() { let sig = func.signature(self.db);
return Some(func.into()); if segment.name == *sig.name() {
Some(func.into())
} else {
None
}
} }
None
}
crate::ImplItem::Const(konst) => { crate::ImplItem::Const(konst) => {
let sig = konst.signature(self.db); let sig = konst.signature(self.db);
if segment.name == *sig.name() { if segment.name == *sig.name() {
return Some(konst.into()); Some(konst.into())
} else {
None
}
} }
None
}
// TODO: Resolve associated types // TODO: Resolve associated types
crate::ImplItem::TypeAlias(_) => None, crate::ImplItem::TypeAlias(_) => None,
};
match matching_def {
Some(_) => {
self.write_assoc_resolution(id, item);
return matching_def;
}
None => None,
}
})?; })?;
/*
if let ExprOrPatId::Expr(expr) = id {
match typable {
TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func),
_ => {}
};
}
*/
resolved = Resolution::Def(item.into()); resolved = Resolution::Def(item.into());
} }
@ -450,14 +472,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Resolution::Def(def) => { Resolution::Def(def) => {
let typable: Option<TypableDef> = def.into(); let typable: Option<TypableDef> = def.into();
let typable = typable?; let typable = typable?;
if let ExprOrPatId::Expr(expr) = id {
match typable {
TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func),
_ => {}
};
}
let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
let ty = self.insert_type_vars(ty); let ty = self.insert_type_vars(ty);

View file

@ -5,7 +5,7 @@ use ra_syntax::{
SyntaxNode, SyntaxNode,
}; };
use test_utils::tested_by; use test_utils::tested_by;
use hir::Resolution; use hir::{ImplItem, Resolution};
use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo}; use crate::{FilePosition, NavigationTarget, db::RootDatabase, RangeInfo};
@ -131,14 +131,25 @@ pub(crate) fn reference_definition(
name_ref.syntax().ancestors().find_map(ast::PathExpr::cast) name_ref.syntax().ancestors().find_map(ast::PathExpr::cast)
{ {
let infer_result = function.infer(db); let infer_result = function.infer(db);
let syntax_mapping = function.body_syntax_mapping(db); let source_map = function.body_source_map(db);
let expr = ast::Expr::cast(path_expr.syntax()).unwrap(); let expr = ast::Expr::cast(path_expr.syntax()).unwrap();
if let Some(func) = syntax_mapping if let Some(res) = source_map
.node_expr(expr) .node_expr(expr)
.and_then(|it| infer_result.assoc_fn_resolutions(it)) .and_then(|it| infer_result.assoc_resolutions(it.into()))
{ {
return Exact(NavigationTarget::from_function(db, func)); match res {
ImplItem::Method(f) => {
return Exact(NavigationTarget::from_function(db, f));
}
ImplItem::Const(c) => {
let (file, node) = c.source(db);
let file = file.original_file(db);
let node = &*node;
return Exact(NavigationTarget::from_named(file, node));
}
_ => {}
}
} }
} }
} }

View file

@ -531,7 +531,7 @@ mod tests {
", ",
); );
let hover = analysis.hover(position).unwrap().unwrap(); let hover = analysis.hover(position).unwrap().unwrap();
assert_eq!(hover.info.first(), Some("```rust\nfn new() -> Thing\n```")); assert_eq!(trim_markup_opt(hover.info.first()), Some("fn new() -> Thing"));
assert_eq!(hover.info.is_exact(), true); assert_eq!(hover.info.is_exact(), true);
} }
} }