aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/ty/infer.rs73
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs29
-rw-r--r--crates/ra_ide_api/src/hover.rs22
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs16
4 files changed, 116 insertions, 24 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 5e4d49ffb..268d2c110 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -29,6 +29,7 @@ use crate::{
29 Function, StructField, Path, Name, 29 Function, StructField, Path, Name,
30 FnSignature, AdtDef, 30 FnSignature, AdtDef,
31 HirDatabase, 31 HirDatabase,
32 ImplItem,
32 type_ref::{TypeRef, Mutability}, 33 type_ref::{TypeRef, Mutability},
33 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, 34 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
34 generics::GenericParams, 35 generics::GenericParams,
@@ -54,6 +55,14 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
54 Arc::new(ctx.resolve_all()) 55 Arc::new(ctx.resolve_all())
55} 56}
56 57
58#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
59enum ExprOrPatId {
60 ExprId(ExprId),
61 PatId(PatId),
62}
63
64impl_froms!(ExprOrPatId: ExprId, PatId);
65
57/// The result of type inference: A mapping from expressions and patterns to types. 66/// The result of type inference: A mapping from expressions and patterns to types.
58#[derive(Clone, PartialEq, Eq, Debug)] 67#[derive(Clone, PartialEq, Eq, Debug)]
59pub struct InferenceResult { 68pub struct InferenceResult {
@@ -61,6 +70,8 @@ pub struct InferenceResult {
61 method_resolutions: FxHashMap<ExprId, Function>, 70 method_resolutions: FxHashMap<ExprId, Function>,
62 /// For each field access expr, records the field it resolves to. 71 /// For each field access expr, records the field it resolves to.
63 field_resolutions: FxHashMap<ExprId, StructField>, 72 field_resolutions: FxHashMap<ExprId, StructField>,
73 /// For each associated item record what it resolves to
74 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
64 pub(super) type_of_expr: ArenaMap<ExprId, Ty>, 75 pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
65 pub(super) type_of_pat: ArenaMap<PatId, Ty>, 76 pub(super) type_of_pat: ArenaMap<PatId, Ty>,
66} 77}
@@ -72,6 +83,12 @@ impl InferenceResult {
72 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { 83 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
73 self.field_resolutions.get(&expr).map(|it| *it) 84 self.field_resolutions.get(&expr).map(|it| *it)
74 } 85 }
86 pub fn assoc_resolutions_for_expr(&self, id: ExprId) -> Option<ImplItem> {
87 self.assoc_resolutions.get(&id.into()).map(|it| *it)
88 }
89 pub fn assoc_resolutions_for_pat(&self, id: PatId) -> Option<ImplItem> {
90 self.assoc_resolutions.get(&id.into()).map(|it| *it)
91 }
75} 92}
76 93
77impl Index<ExprId> for InferenceResult { 94impl Index<ExprId> for InferenceResult {
@@ -99,6 +116,7 @@ struct InferenceContext<'a, D: HirDatabase> {
99 var_unification_table: InPlaceUnificationTable<TypeVarId>, 116 var_unification_table: InPlaceUnificationTable<TypeVarId>,
100 method_resolutions: FxHashMap<ExprId, Function>, 117 method_resolutions: FxHashMap<ExprId, Function>,
101 field_resolutions: FxHashMap<ExprId, StructField>, 118 field_resolutions: FxHashMap<ExprId, StructField>,
119 assoc_resolutions: FxHashMap<ExprOrPatId, ImplItem>,
102 type_of_expr: ArenaMap<ExprId, Ty>, 120 type_of_expr: ArenaMap<ExprId, Ty>,
103 type_of_pat: ArenaMap<PatId, Ty>, 121 type_of_pat: ArenaMap<PatId, Ty>,
104 /// The return type of the function being inferred. 122 /// The return type of the function being inferred.
@@ -110,6 +128,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
110 InferenceContext { 128 InferenceContext {
111 method_resolutions: FxHashMap::default(), 129 method_resolutions: FxHashMap::default(),
112 field_resolutions: FxHashMap::default(), 130 field_resolutions: FxHashMap::default(),
131 assoc_resolutions: FxHashMap::default(),
113 type_of_expr: ArenaMap::default(), 132 type_of_expr: ArenaMap::default(),
114 type_of_pat: ArenaMap::default(), 133 type_of_pat: ArenaMap::default(),
115 var_unification_table: InPlaceUnificationTable::new(), 134 var_unification_table: InPlaceUnificationTable::new(),
@@ -135,6 +154,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
135 InferenceResult { 154 InferenceResult {
136 method_resolutions: self.method_resolutions, 155 method_resolutions: self.method_resolutions,
137 field_resolutions: self.field_resolutions, 156 field_resolutions: self.field_resolutions,
157 assoc_resolutions: self.assoc_resolutions,
138 type_of_expr: expr_types, 158 type_of_expr: expr_types,
139 type_of_pat: pat_types, 159 type_of_pat: pat_types,
140 } 160 }
@@ -152,6 +172,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
152 self.field_resolutions.insert(expr, field); 172 self.field_resolutions.insert(expr, field);
153 } 173 }
154 174
175 fn write_assoc_resolution(&mut self, id: ExprOrPatId, item: ImplItem) {
176 self.assoc_resolutions.insert(id, item);
177 }
178
155 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { 179 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
156 self.type_of_pat.insert(pat, ty); 180 self.type_of_pat.insert(pat, ty);
157 } 181 }
@@ -341,7 +365,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
341 }) 365 })
342 } 366 }
343 367
344 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { 368 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
345 let resolved = resolver.resolve_path_segments(self.db, &path); 369 let resolved = resolver.resolve_path_segments(self.db, &path);
346 370
347 let (def, remaining_index) = resolved.into_inner(); 371 let (def, remaining_index) = resolved.into_inner();
@@ -393,26 +417,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
393 // Attempt to find an impl_item for the type which has a name matching 417 // Attempt to find an impl_item for the type which has a name matching
394 // the current segment 418 // the current segment
395 log::debug!("looking for path segment: {:?}", segment); 419 log::debug!("looking for path segment: {:?}", segment);
396 let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| match item { 420 let item: crate::ModuleDef = ty.iterate_impl_items(self.db, |item| {
397 crate::ImplItem::Method(func) => { 421 let matching_def: Option<crate::ModuleDef> = match item {
398 let sig = func.signature(self.db); 422 crate::ImplItem::Method(func) => {
399 if segment.name == *sig.name() { 423 let sig = func.signature(self.db);
400 return Some(func.into()); 424 if segment.name == *sig.name() {
425 Some(func.into())
426 } else {
427 None
428 }
401 } 429 }
402 None
403 }
404 430
405 crate::ImplItem::Const(konst) => { 431 crate::ImplItem::Const(konst) => {
406 let sig = konst.signature(self.db); 432 let sig = konst.signature(self.db);
407 if segment.name == *sig.name() { 433 if segment.name == *sig.name() {
408 return Some(konst.into()); 434 Some(konst.into())
435 } else {
436 None
437 }
409 } 438 }
410 None
411 }
412 439
413 // TODO: Resolve associated types 440 // TODO: Resolve associated types
414 crate::ImplItem::TypeAlias(_) => None, 441 crate::ImplItem::TypeAlias(_) => None,
442 };
443 match matching_def {
444 Some(_) => {
445 self.write_assoc_resolution(id, item);
446 return matching_def;
447 }
448 None => None,
449 }
415 })?; 450 })?;
451
416 resolved = Resolution::Def(item.into()); 452 resolved = Resolution::Def(item.into());
417 } 453 }
418 454
@@ -420,7 +456,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
420 Resolution::Def(def) => { 456 Resolution::Def(def) => {
421 let typable: Option<TypableDef> = def.into(); 457 let typable: Option<TypableDef> = def.into();
422 let typable = typable?; 458 let typable = typable?;
423
424 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); 459 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
425 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); 460 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
426 let ty = self.insert_type_vars(ty); 461 let ty = self.insert_type_vars(ty);
@@ -572,7 +607,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
572 Pat::Path(path) => { 607 Pat::Path(path) => {
573 // TODO use correct resolver for the surrounding expression 608 // TODO use correct resolver for the surrounding expression
574 let resolver = self.resolver.clone(); 609 let resolver = self.resolver.clone();
575 self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) 610 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
576 } 611 }
577 Pat::Bind { mode, name: _name, subpat } => { 612 Pat::Bind { mode, name: _name, subpat } => {
578 let inner_ty = if let Some(subpat) = subpat { 613 let inner_ty = if let Some(subpat) = subpat {
@@ -782,7 +817,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
782 Expr::Path(p) => { 817 Expr::Path(p) => {
783 // TODO this could be more efficient... 818 // TODO this could be more efficient...
784 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); 819 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
785 self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown) 820 self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
786 } 821 }
787 Expr::Continue => Ty::Never, 822 Expr::Continue => Ty::Never,
788 Expr::Break { expr } => { 823 Expr::Break { expr } => {
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 9ec179593..364263d9b 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -47,9 +47,10 @@ pub(crate) fn reference_definition(
47 name_ref: &ast::NameRef, 47 name_ref: &ast::NameRef,
48) -> ReferenceResult { 48) -> ReferenceResult {
49 use self::ReferenceResult::*; 49 use self::ReferenceResult::*;
50 if let Some(function) = 50
51 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax()) 51 let function = hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax());
52 { 52
53 if let Some(function) = function {
53 // Check if it is a method 54 // Check if it is a method
54 if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) { 55 if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) {
55 tested_by!(goto_definition_works_for_methods); 56 tested_by!(goto_definition_works_for_methods);
@@ -122,9 +123,29 @@ pub(crate) fn reference_definition(
122 Some(Resolution::SelfType(_impl_block)) => { 123 Some(Resolution::SelfType(_impl_block)) => {
123 // TODO: go to the implemented type 124 // TODO: go to the implemented type
124 } 125 }
125 None => {} 126 None => {
127 // If we failed to resolve then check associated items
128 if let Some(function) = function {
129 // Should we do this above and then grab path from the PathExpr?
130 if let Some(path_expr) =
131 name_ref.syntax().ancestors().find_map(ast::PathExpr::cast)
132 {
133 let infer_result = function.infer(db);
134 let source_map = function.body_source_map(db);
135 let expr = ast::Expr::cast(path_expr.syntax()).unwrap();
136
137 if let Some(res) = source_map
138 .node_expr(expr)
139 .and_then(|it| infer_result.assoc_resolutions_for_expr(it.into()))
140 {
141 return Exact(NavigationTarget::from_impl_item(db, res));
142 }
143 }
144 }
145 }
126 } 146 }
127 } 147 }
148
128 // If that fails try the index based approach. 149 // If that fails try the index based approach.
129 let navs = crate::symbol_index::index_resolve(db, name_ref) 150 let navs = crate::symbol_index::index_resolve(db, name_ref)
130 .into_iter() 151 .into_iter()
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 8ec60090d..bcd052c8b 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -512,4 +512,26 @@ mod tests {
512 let hover = analysis.hover(position).unwrap().unwrap(); 512 let hover = analysis.hover(position).unwrap().unwrap();
513 assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing")); 513 assert_eq!(trim_markup_opt(hover.info.first()), Some("Thing"));
514 } 514 }
515
516 #[test]
517 fn test_hover_infer_associated_method_exact() {
518 let (analysis, position) = single_file_with_position(
519 "
520 struct Thing { x: u32 }
521
522 impl Thing {
523 fn new() -> Thing {
524 Thing { x: 0 }
525 }
526 }
527
528 fn main() {
529 let foo_test = Thing::new<|>();
530 }
531 ",
532 );
533 let hover = analysis.hover(position).unwrap().unwrap();
534 assert_eq!(trim_markup_opt(hover.info.first()), Some("fn new() -> Thing"));
535 assert_eq!(hover.info.is_exact(), true);
536 }
515} 537}
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index 6538081ac..d806cb368 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::{
3 SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, 3 SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast,
4 SyntaxKind::{self, NAME}, 4 SyntaxKind::{self, NAME},
5}; 5};
6use hir::{ModuleSource, FieldSource, Name}; 6use hir::{ModuleSource, FieldSource, Name, ImplItem};
7 7
8use crate::{FileSymbol, db::RootDatabase}; 8use crate::{FileSymbol, db::RootDatabase};
9 9
@@ -174,6 +174,20 @@ impl NavigationTarget {
174 ) 174 )
175 } 175 }
176 176
177 pub(crate) fn from_impl_item(db: &RootDatabase, impl_item: hir::ImplItem) -> NavigationTarget {
178 match impl_item {
179 ImplItem::Method(f) => NavigationTarget::from_function(db, f),
180 ImplItem::Const(c) => {
181 let (file_id, node) = c.source(db);
182 NavigationTarget::from_named(file_id.original_file(db), &*node)
183 }
184 ImplItem::TypeAlias(a) => {
185 let (file_id, node) = a.source(db);
186 NavigationTarget::from_named(file_id.original_file(db), &*node)
187 }
188 }
189 }
190
177 #[cfg(test)] 191 #[cfg(test)]
178 pub(crate) fn assert_match(&self, expected: &str) { 192 pub(crate) fn assert_match(&self, expected: &str) {
179 let actual = self.debug_render(); 193 let actual = self.debug_render();