aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkjeremy <[email protected]>2019-03-01 23:26:49 +0000
committerJeremy Kolb <[email protected]>2019-03-04 13:27:08 +0000
commit49da9a3e814a42a2f4dea0cd79dbdae86bea5ce4 (patch)
tree27710b8c6c7f63e2ddb25d178988f4dd6cbc2540
parentdc8bcc1e42b573a8c315dd42a43c0fc4d5bfa8f8 (diff)
Make goto definition/hover resolve constructors
-rw-r--r--crates/ra_hir/src/ty/infer.rs43
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs29
-rw-r--r--crates/ra_ide_api/src/hover.rs22
3 files changed, 87 insertions, 7 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 5e4d49ffb..f7a35f05b 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -54,6 +54,24 @@ pub fn infer(db: &impl HirDatabase, func: Function) -> Arc<InferenceResult> {
54 Arc::new(ctx.resolve_all()) 54 Arc::new(ctx.resolve_all())
55} 55}
56 56
57#[derive(Debug, Copy, Clone)]
58enum ExprOrPatId {
59 Expr(ExprId),
60 Pat(PatId),
61}
62
63impl From<ExprId> for ExprOrPatId {
64 fn from(id: ExprId) -> Self {
65 ExprOrPatId::Expr(id)
66 }
67}
68
69impl From<PatId> for ExprOrPatId {
70 fn from(id: PatId) -> Self {
71 ExprOrPatId::Pat(id)
72 }
73}
74
57/// The result of type inference: A mapping from expressions and patterns to types. 75/// The result of type inference: A mapping from expressions and patterns to types.
58#[derive(Clone, PartialEq, Eq, Debug)] 76#[derive(Clone, PartialEq, Eq, Debug)]
59pub struct InferenceResult { 77pub struct InferenceResult {
@@ -61,6 +79,8 @@ pub struct InferenceResult {
61 method_resolutions: FxHashMap<ExprId, Function>, 79 method_resolutions: FxHashMap<ExprId, Function>,
62 /// For each field access expr, records the field it resolves to. 80 /// For each field access expr, records the field it resolves to.
63 field_resolutions: FxHashMap<ExprId, StructField>, 81 field_resolutions: FxHashMap<ExprId, StructField>,
82 /// For each associated function call expr, records the function it resolves to
83 assoc_fn_resolutions: FxHashMap<ExprId, Function>,
64 pub(super) type_of_expr: ArenaMap<ExprId, Ty>, 84 pub(super) type_of_expr: ArenaMap<ExprId, Ty>,
65 pub(super) type_of_pat: ArenaMap<PatId, Ty>, 85 pub(super) type_of_pat: ArenaMap<PatId, Ty>,
66} 86}
@@ -72,6 +92,9 @@ impl InferenceResult {
72 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> { 92 pub fn field_resolution(&self, expr: ExprId) -> Option<StructField> {
73 self.field_resolutions.get(&expr).map(|it| *it) 93 self.field_resolutions.get(&expr).map(|it| *it)
74 } 94 }
95 pub fn assoc_fn_resolutions(&self, expr: ExprId) -> Option<Function> {
96 self.assoc_fn_resolutions.get(&expr).map(|it| *it)
97 }
75} 98}
76 99
77impl Index<ExprId> for InferenceResult { 100impl Index<ExprId> for InferenceResult {
@@ -99,6 +122,7 @@ struct InferenceContext<'a, D: HirDatabase> {
99 var_unification_table: InPlaceUnificationTable<TypeVarId>, 122 var_unification_table: InPlaceUnificationTable<TypeVarId>,
100 method_resolutions: FxHashMap<ExprId, Function>, 123 method_resolutions: FxHashMap<ExprId, Function>,
101 field_resolutions: FxHashMap<ExprId, StructField>, 124 field_resolutions: FxHashMap<ExprId, StructField>,
125 assoc_fn_resolutions: FxHashMap<ExprId, Function>,
102 type_of_expr: ArenaMap<ExprId, Ty>, 126 type_of_expr: ArenaMap<ExprId, Ty>,
103 type_of_pat: ArenaMap<PatId, Ty>, 127 type_of_pat: ArenaMap<PatId, Ty>,
104 /// The return type of the function being inferred. 128 /// The return type of the function being inferred.
@@ -110,6 +134,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
110 InferenceContext { 134 InferenceContext {
111 method_resolutions: FxHashMap::default(), 135 method_resolutions: FxHashMap::default(),
112 field_resolutions: FxHashMap::default(), 136 field_resolutions: FxHashMap::default(),
137 assoc_fn_resolutions: FxHashMap::default(),
113 type_of_expr: ArenaMap::default(), 138 type_of_expr: ArenaMap::default(),
114 type_of_pat: ArenaMap::default(), 139 type_of_pat: ArenaMap::default(),
115 var_unification_table: InPlaceUnificationTable::new(), 140 var_unification_table: InPlaceUnificationTable::new(),
@@ -135,6 +160,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
135 InferenceResult { 160 InferenceResult {
136 method_resolutions: self.method_resolutions, 161 method_resolutions: self.method_resolutions,
137 field_resolutions: self.field_resolutions, 162 field_resolutions: self.field_resolutions,
163 assoc_fn_resolutions: self.assoc_fn_resolutions,
138 type_of_expr: expr_types, 164 type_of_expr: expr_types,
139 type_of_pat: pat_types, 165 type_of_pat: pat_types,
140 } 166 }
@@ -152,6 +178,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
152 self.field_resolutions.insert(expr, field); 178 self.field_resolutions.insert(expr, field);
153 } 179 }
154 180
181 fn write_assoc_fn_resolution(&mut self, expr: ExprId, func: Function) {
182 self.assoc_fn_resolutions.insert(expr, func);
183 }
184
155 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) { 185 fn write_pat_ty(&mut self, pat: PatId, ty: Ty) {
156 self.type_of_pat.insert(pat, ty); 186 self.type_of_pat.insert(pat, ty);
157 } 187 }
@@ -341,7 +371,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
341 }) 371 })
342 } 372 }
343 373
344 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { 374 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> {
345 let resolved = resolver.resolve_path_segments(self.db, &path); 375 let resolved = resolver.resolve_path_segments(self.db, &path);
346 376
347 let (def, remaining_index) = resolved.into_inner(); 377 let (def, remaining_index) = resolved.into_inner();
@@ -421,6 +451,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
421 let typable: Option<TypableDef> = def.into(); 451 let typable: Option<TypableDef> = def.into();
422 let typable = typable?; 452 let typable = typable?;
423 453
454 if let ExprOrPatId::Expr(expr) = id {
455 match typable {
456 TypableDef::Function(func) => self.write_assoc_fn_resolution(expr, func),
457 _ => {}
458 };
459 }
460
424 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); 461 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); 462 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
426 let ty = self.insert_type_vars(ty); 463 let ty = self.insert_type_vars(ty);
@@ -572,7 +609,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
572 Pat::Path(path) => { 609 Pat::Path(path) => {
573 // TODO use correct resolver for the surrounding expression 610 // TODO use correct resolver for the surrounding expression
574 let resolver = self.resolver.clone(); 611 let resolver = self.resolver.clone();
575 self.infer_path_expr(&resolver, &path).unwrap_or(Ty::Unknown) 612 self.infer_path_expr(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
576 } 613 }
577 Pat::Bind { mode, name: _name, subpat } => { 614 Pat::Bind { mode, name: _name, subpat } => {
578 let inner_ty = if let Some(subpat) = subpat { 615 let inner_ty = if let Some(subpat) = subpat {
@@ -782,7 +819,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
782 Expr::Path(p) => { 819 Expr::Path(p) => {
783 // TODO this could be more efficient... 820 // TODO this could be more efficient...
784 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr); 821 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
785 self.infer_path_expr(&resolver, p).unwrap_or(Ty::Unknown) 822 self.infer_path_expr(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
786 } 823 }
787 Expr::Continue => Ty::Never, 824 Expr::Continue => Ty::Never,
788 Expr::Break { expr } => { 825 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..e4febe8cc 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 syntax_mapping = function.body_syntax_mapping(db);
135 let expr = ast::Expr::cast(path_expr.syntax()).unwrap();
136
137 if let Some(func) = syntax_mapping
138 .node_expr(expr)
139 .and_then(|it| infer_result.assoc_fn_resolutions(it))
140 {
141 return Exact(NavigationTarget::from_function(db, func));
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..0f13777d7 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!(hover.info.first(), Some("```rust\nfn new() -> Thing\n```"));
535 assert_eq!(hover.info.is_exact(), true);
536 }
515} 537}