aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVille Penttinen <[email protected]>2019-02-21 10:04:14 +0000
committerVille Penttinen <[email protected]>2019-02-21 10:25:55 +0000
commit816971ebc9207c5fb5779d448613dd171c27f398 (patch)
treefe49d209a852bb1b4a51eea9d40449dcf2845209
parentc84561bb624280b84eb2fe6c6b2a6b9fe3f1dbf7 (diff)
Implement basic support for Associated Methods and Constants
This is done in `infer_path_expr`. When `Resolver::resolve_path` returns `PartiallyResolved`, we use the returned `Resolution` together with the given `segment_index` to check if we can find something matching the segment at segment_index in the impls for that particular type.
-rw-r--r--crates/ra_hir/src/impl_block.rs2
-rw-r--r--crates/ra_hir/src/nameres.rs78
-rw-r--r--crates/ra_hir/src/resolve.rs46
-rw-r--r--crates/ra_hir/src/ty.rs108
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap14
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_enum.snap20
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap16
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_struct.snap16
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_with_modules.snap23
-rw-r--r--crates/ra_hir/src/ty/tests.rs133
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs2
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs2
-rw-r--r--crates/ra_ide_api/src/hover.rs20
13 files changed, 430 insertions, 50 deletions
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 7ecf8c368..f4dccf165 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -88,7 +88,7 @@ impl ImplBlock {
88 if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) { 88 if let Some(TypeRef::Path(path)) = self.target_trait_ref(db) {
89 let resolver = self.resolver(db); 89 let resolver = self.resolver(db);
90 if let Some(Resolution::Def(ModuleDef::Trait(tr))) = 90 if let Some(Resolution::Def(ModuleDef::Trait(tr))) =
91 resolver.resolve_path(db, &path).take_types() 91 resolver.resolve_path(db, &path).into_per_ns().take_types()
92 { 92 {
93 return Some(tr); 93 return Some(tr);
94 } 94 }
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index bd920bfea..b78a178c1 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -119,6 +119,10 @@ impl<T> PerNs<T> {
119 self.types.is_some() && self.values.is_some() 119 self.types.is_some() && self.values.is_some()
120 } 120 }
121 121
122 pub fn is_values(&self) -> bool {
123 self.values.is_some() && self.types.is_none()
124 }
125
122 pub fn take(self, namespace: Namespace) -> Option<T> { 126 pub fn take(self, namespace: Namespace) -> Option<T> {
123 match namespace { 127 match namespace {
124 Namespace::Types => self.types, 128 Namespace::Types => self.types,
@@ -297,7 +301,14 @@ where
297 ); 301 );
298 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes }) 302 (res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
299 } else { 303 } else {
300 self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path) 304 let res = self.result.resolve_path_fp(
305 self.db,
306 ResolveMode::Import,
307 original_module,
308 &import.path,
309 );
310
311 (res.module, res.reached_fixedpoint)
301 }; 312 };
302 313
303 if reached_fixedpoint != ReachedFixedPoint::Yes { 314 if reached_fixedpoint != ReachedFixedPoint::Yes {
@@ -435,6 +446,27 @@ where
435 } 446 }
436} 447}
437 448
449#[derive(Debug, Clone)]
450pub struct ResolvePathResult {
451 pub(crate) module: PerNs<ModuleDef>,
452 pub(crate) segment_index: Option<usize>,
453 reached_fixedpoint: ReachedFixedPoint,
454}
455
456impl ResolvePathResult {
457 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
458 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None)
459 }
460
461 fn with(
462 module: PerNs<ModuleDef>,
463 reached_fixedpoint: ReachedFixedPoint,
464 segment_index: Option<usize>,
465 ) -> ResolvePathResult {
466 ResolvePathResult { module, reached_fixedpoint, segment_index }
467 }
468}
469
438#[derive(Debug, Clone, Copy, PartialEq, Eq)] 470#[derive(Debug, Clone, Copy, PartialEq, Eq)]
439enum ResolveMode { 471enum ResolveMode {
440 Import, 472 Import,
@@ -468,8 +500,9 @@ impl ItemMap {
468 db: &impl PersistentHirDatabase, 500 db: &impl PersistentHirDatabase,
469 original_module: Module, 501 original_module: Module,
470 path: &Path, 502 path: &Path,
471 ) -> PerNs<ModuleDef> { 503 ) -> (PerNs<ModuleDef>, Option<usize>) {
472 self.resolve_path_fp(db, ResolveMode::Other, original_module, path).0 504 let res = self.resolve_path_fp(db, ResolveMode::Other, original_module, path);
505 (res.module, res.segment_index)
473 } 506 }
474 507
475 fn resolve_in_prelude( 508 fn resolve_in_prelude(
@@ -534,7 +567,7 @@ impl ItemMap {
534 mode: ResolveMode, 567 mode: ResolveMode,
535 original_module: Module, 568 original_module: Module,
536 path: &Path, 569 path: &Path,
537 ) -> (PerNs<ModuleDef>, ReachedFixedPoint) { 570 ) -> ResolvePathResult {
538 let mut segments = path.segments.iter().enumerate(); 571 let mut segments = path.segments.iter().enumerate();
539 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind { 572 let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
540 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()), 573 PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
@@ -549,7 +582,7 @@ impl ItemMap {
549 { 582 {
550 let segment = match segments.next() { 583 let segment = match segments.next() {
551 Some((_, segment)) => segment, 584 Some((_, segment)) => segment,
552 None => return (PerNs::none(), ReachedFixedPoint::Yes), 585 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
553 }; 586 };
554 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 587 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
555 self.resolve_name_in_crate_root_or_extern_prelude( 588 self.resolve_name_in_crate_root_or_extern_prelude(
@@ -561,7 +594,7 @@ impl ItemMap {
561 PathKind::Plain => { 594 PathKind::Plain => {
562 let segment = match segments.next() { 595 let segment = match segments.next() {
563 Some((_, segment)) => segment, 596 Some((_, segment)) => segment,
564 None => return (PerNs::none(), ReachedFixedPoint::Yes), 597 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
565 }; 598 };
566 log::debug!("resolving {:?} in module", segment); 599 log::debug!("resolving {:?} in module", segment);
567 self.resolve_name_in_module(db, original_module, &segment.name) 600 self.resolve_name_in_module(db, original_module, &segment.name)
@@ -571,20 +604,20 @@ impl ItemMap {
571 PerNs::types(p.into()) 604 PerNs::types(p.into())
572 } else { 605 } else {
573 log::debug!("super path in root module"); 606 log::debug!("super path in root module");
574 return (PerNs::none(), ReachedFixedPoint::Yes); 607 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
575 } 608 }
576 } 609 }
577 PathKind::Abs => { 610 PathKind::Abs => {
578 // 2018-style absolute path -- only extern prelude 611 // 2018-style absolute path -- only extern prelude
579 let segment = match segments.next() { 612 let segment = match segments.next() {
580 Some((_, segment)) => segment, 613 Some((_, segment)) => segment,
581 None => return (PerNs::none(), ReachedFixedPoint::Yes), 614 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
582 }; 615 };
583 if let Some(def) = self.extern_prelude.get(&segment.name) { 616 if let Some(def) = self.extern_prelude.get(&segment.name) {
584 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 617 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
585 PerNs::types(*def) 618 PerNs::types(*def)
586 } else { 619 } else {
587 return (PerNs::none(), ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 620 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
588 } 621 }
589 } 622 }
590 }; 623 };
@@ -598,7 +631,7 @@ impl ItemMap {
598 // (don't break here because `curr_per_ns` might contain 631 // (don't break here because `curr_per_ns` might contain
599 // something in the value namespace, and it would be wrong 632 // something in the value namespace, and it would be wrong
600 // to return that) 633 // to return that)
601 return (PerNs::none(), ReachedFixedPoint::No); 634 return ResolvePathResult::empty(ReachedFixedPoint::No);
602 } 635 }
603 }; 636 };
604 // resolve segment in curr 637 // resolve segment in curr
@@ -612,15 +645,15 @@ impl ItemMap {
612 }; 645 };
613 log::debug!("resolving {:?} in other crate", path); 646 log::debug!("resolving {:?} in other crate", path);
614 let item_map = db.item_map(module.krate); 647 let item_map = db.item_map(module.krate);
615 let def = item_map.resolve_path(db, *module, &path); 648 let (def, s) = item_map.resolve_path(db, *module, &path);
616 return (def, ReachedFixedPoint::Yes); 649 return ResolvePathResult::with(def, ReachedFixedPoint::Yes, s);
617 } 650 }
618 651
619 match self[module.module_id].items.get(&segment.name) { 652 match self[module.module_id].items.get(&segment.name) {
620 Some(res) if !res.def.is_none() => res.def, 653 Some(res) if !res.def.is_none() => res.def,
621 _ => { 654 _ => {
622 log::debug!("path segment {:?} not found", segment.name); 655 log::debug!("path segment {:?} not found", segment.name);
623 return (PerNs::none(), ReachedFixedPoint::No); 656 return ResolvePathResult::empty(ReachedFixedPoint::No);
624 } 657 }
625 } 658 }
626 } 659 }
@@ -629,9 +662,22 @@ impl ItemMap {
629 tested_by!(item_map_enum_importing); 662 tested_by!(item_map_enum_importing);
630 match e.variant(db, &segment.name) { 663 match e.variant(db, &segment.name) {
631 Some(variant) => PerNs::both(variant.into(), variant.into()), 664 Some(variant) => PerNs::both(variant.into(), variant.into()),
632 None => PerNs::none(), 665 None => {
666 return ResolvePathResult::with(
667 PerNs::types((*e).into()),
668 ReachedFixedPoint::Yes,
669 Some(i),
670 );
671 }
633 } 672 }
634 } 673 }
674 ModuleDef::Struct(s) => {
675 return ResolvePathResult::with(
676 PerNs::types((*s).into()),
677 ReachedFixedPoint::Yes,
678 Some(i),
679 );
680 }
635 _ => { 681 _ => {
636 // could be an inherent method call in UFCS form 682 // could be an inherent method call in UFCS form
637 // (`Struct::method`), or some other kind of associated 683 // (`Struct::method`), or some other kind of associated
@@ -641,11 +687,11 @@ impl ItemMap {
641 segment.name, 687 segment.name,
642 curr, 688 curr,
643 ); 689 );
644 return (PerNs::none(), ReachedFixedPoint::Yes); 690 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
645 } 691 }
646 }; 692 };
647 } 693 }
648 (curr_per_ns, ReachedFixedPoint::Yes) 694 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None)
649 } 695 }
650} 696}
651 697
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 91a531801..00b55eae9 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -33,6 +33,32 @@ pub(crate) struct ExprScope {
33} 33}
34 34
35#[derive(Debug, Clone)] 35#[derive(Debug, Clone)]
36pub enum PathResult {
37 /// Path was fully resolved
38 FullyResolved(PerNs<Resolution>),
39 /// Path was partially resolved, first element contains the resolution
40 /// second contains the index in the Path.segments which we were unable to resolve
41 PartiallyResolved(PerNs<Resolution>, usize),
42}
43
44impl PathResult {
45 pub fn segment_index(&self) -> Option<usize> {
46 match self {
47 PathResult::FullyResolved(_) => None,
48 PathResult::PartiallyResolved(_, ref i) => Some(*i),
49 }
50 }
51
52 /// Consumes `PathResult` and returns the contained `PerNs<Resolution>`
53 pub fn into_per_ns(self) -> PerNs<Resolution> {
54 match self {
55 PathResult::FullyResolved(def) => def,
56 PathResult::PartiallyResolved(def, _) => def,
57 }
58 }
59}
60
61#[derive(Debug, Clone)]
36pub(crate) enum Scope { 62pub(crate) enum Scope {
37 /// All the items and imported names of a module 63 /// All the items and imported names of a module
38 ModuleScope(ModuleItemMap), 64 ModuleScope(ModuleItemMap),
@@ -67,18 +93,26 @@ impl Resolver {
67 resolution 93 resolution
68 } 94 }
69 95
70 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PerNs<Resolution> { 96 pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PathResult {
97 use self::PathResult::*;
71 if let Some(name) = path.as_ident() { 98 if let Some(name) = path.as_ident() {
72 self.resolve_name(db, name) 99 FullyResolved(self.resolve_name(db, name))
73 } else if path.is_self() { 100 } else if path.is_self() {
74 self.resolve_name(db, &Name::self_param()) 101 FullyResolved(self.resolve_name(db, &Name::self_param()))
75 } else { 102 } else {
76 let (item_map, module) = match self.module() { 103 let (item_map, module) = match self.module() {
77 Some(m) => m, 104 Some(m) => m,
78 _ => return PerNs::none(), 105 _ => return FullyResolved(PerNs::none()),
79 }; 106 };
80 let module_res = item_map.resolve_path(db, module, path); 107 let (module_res, segment_index) = item_map.resolve_path(db, module, path);
81 module_res.map(Resolution::Def) 108
109 let def = module_res.map(Resolution::Def);
110
111 if let Some(index) = segment_index {
112 PartiallyResolved(def, index)
113 } else {
114 FullyResolved(def)
115 }
82 } 116 }
83 } 117 }
84 118
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d4d896673..2751ab3ab 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -32,17 +32,20 @@ use rustc_hash::FxHashMap;
32 32
33use test_utils::tested_by; 33use test_utils::tested_by;
34 34
35use ra_syntax::ast::NameOwner;
36
35use crate::{ 37use crate::{
36 Function, Struct, StructField, Enum, EnumVariant, Path, Name, 38 Function, Struct, StructField, Enum, EnumVariant, Path, Name,
39 Const,
37 FnSignature, ModuleDef, AdtDef, 40 FnSignature, ModuleDef, AdtDef,
38 HirDatabase, 41 HirDatabase,
39 type_ref::{TypeRef, Mutability}, 42 type_ref::{TypeRef, Mutability},
40 name::KnownName, 43 name::{KnownName, AsName},
41 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, 44 expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self},
42 generics::GenericParams, 45 generics::GenericParams,
43 path::GenericArg, 46 path::GenericArg,
44 adt::VariantDef, 47 adt::VariantDef,
45 resolve::{Resolver, Resolution}, nameres::Namespace 48 resolve::{Resolver, Resolution, PathResult}, nameres::Namespace
46}; 49};
47 50
48/// The ID of a type variable. 51/// The ID of a type variable.
@@ -370,7 +373,7 @@ impl Ty {
370 } 373 }
371 374
372 // Resolve the path (in type namespace) 375 // Resolve the path (in type namespace)
373 let resolution = resolver.resolve_path(db, path).take_types(); 376 let resolution = resolver.resolve_path(db, path).into_per_ns().take_types();
374 377
375 let def = match resolution { 378 let def = match resolution {
376 Some(Resolution::Def(def)) => def, 379 Some(Resolution::Def(def)) => def,
@@ -678,6 +681,19 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
678 Ty::FnDef { def: def.into(), sig, name, substs } 681 Ty::FnDef { def: def.into(), sig, name, substs }
679} 682}
680 683
684fn type_for_const(db: &impl HirDatabase, resolver: &Resolver, def: Const) -> Ty {
685 let node = def.source(db).1;
686
687 let tr = node
688 .type_ref()
689 .map(TypeRef::from_ast)
690 .as_ref()
691 .map(|tr| Ty::from_hir(db, resolver, tr))
692 .unwrap_or_else(|| Ty::Unknown);
693
694 tr
695}
696
681/// Compute the type of a tuple struct constructor. 697/// Compute the type of a tuple struct constructor.
682fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { 698fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
683 let var_data = def.variant_data(db); 699 let var_data = def.variant_data(db);
@@ -1172,15 +1188,56 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1172 } 1188 }
1173 1189
1174 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { 1190 fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> {
1175 let resolved = resolver.resolve_path(self.db, &path).take_values()?; 1191 let resolved = resolver.resolve_path(self.db, &path);
1192
1193 let (resolved, segment_index) = match resolved {
1194 PathResult::FullyResolved(def) => (def.take_values()?, None),
1195 PathResult::PartiallyResolved(def, index) => (def.take_types()?, Some(index)),
1196 };
1197
1176 match resolved { 1198 match resolved {
1177 Resolution::Def(def) => { 1199 Resolution::Def(def) => {
1178 let typable: Option<TypableDef> = def.into(); 1200 let typable: Option<TypableDef> = def.into();
1179 let typable = typable?; 1201 let typable = typable?;
1180 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); 1202
1181 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs); 1203 if let Some(segment_index) = segment_index {
1182 let ty = self.insert_type_vars(ty); 1204 let ty = self.db.type_for_def(typable, Namespace::Types);
1183 Some(ty) 1205 // TODO: What to do if segment_index is not the last segment
1206 // in the path
1207 let segment = &path.segments[segment_index];
1208
1209 // Attempt to find an impl_item for the type which has a name matching
1210 // the current segment
1211 let ty = ty.iterate_impl_items(self.db, |item| match item {
1212 crate::ImplItem::Method(func) => {
1213 let sig = func.signature(self.db);
1214 if segment.name == *sig.name() {
1215 return Some(type_for_fn(self.db, func));
1216 }
1217 None
1218 }
1219 crate::ImplItem::Const(c) => {
1220 let node = c.source(self.db).1;
1221
1222 if let Some(name) = node.name().map(|n| n.as_name()) {
1223 if segment.name == name {
1224 return Some(type_for_const(self.db, resolver, c));
1225 }
1226 }
1227
1228 None
1229 }
1230
1231 // TODO: Resolve associated types
1232 crate::ImplItem::Type(_) => None,
1233 });
1234 ty
1235 } else {
1236 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable);
1237 let ty = self.db.type_for_def(typable, Namespace::Values).apply_substs(substs);
1238 let ty = self.insert_type_vars(ty);
1239 Some(ty)
1240 }
1184 } 1241 }
1185 Resolution::LocalBinding(pat) => { 1242 Resolution::LocalBinding(pat) => {
1186 let ty = self.type_of_pat.get(pat)?; 1243 let ty = self.type_of_pat.get(pat)?;
@@ -1204,23 +1261,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1204 None => return (Ty::Unknown, None), 1261 None => return (Ty::Unknown, None),
1205 }; 1262 };
1206 let resolver = &self.resolver; 1263 let resolver = &self.resolver;
1207 let typable: Option<TypableDef> = match resolver.resolve_path(self.db, &path).take_types() { 1264 let typable: Option<TypableDef> =
1208 Some(Resolution::Def(def)) => def.into(), 1265 match resolver.resolve_path(self.db, &path).into_per_ns().take_types() {
1209 Some(Resolution::LocalBinding(..)) => { 1266 Some(Resolution::Def(def)) => def.into(),
1210 // this cannot happen 1267 Some(Resolution::LocalBinding(..)) => {
1211 log::error!("path resolved to local binding in type ns"); 1268 // this cannot happen
1212 return (Ty::Unknown, None); 1269 log::error!("path resolved to local binding in type ns");
1213 } 1270 return (Ty::Unknown, None);
1214 Some(Resolution::GenericParam(..)) => { 1271 }
1215 // generic params can't be used in struct literals 1272 Some(Resolution::GenericParam(..)) => {
1216 return (Ty::Unknown, None); 1273 // generic params can't be used in struct literals
1217 } 1274 return (Ty::Unknown, None);
1218 Some(Resolution::SelfType(..)) => { 1275 }
1219 // TODO this is allowed in an impl for a struct, handle this 1276 Some(Resolution::SelfType(..)) => {
1220 return (Ty::Unknown, None); 1277 // TODO this is allowed in an impl for a struct, handle this
1221 } 1278 return (Ty::Unknown, None);
1222 None => return (Ty::Unknown, None), 1279 }
1223 }; 1280 None => return (Ty::Unknown, None),
1281 };
1224 let def = match typable { 1282 let def = match typable {
1225 None => return (Ty::Unknown, None), 1283 None => return (Ty::Unknown, None),
1226 Some(it) => it, 1284 Some(it) => it,
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap
new file mode 100644
index 000000000..14ab8ba96
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap
@@ -0,0 +1,14 @@
1---
2created: "2019-02-20T11:04:56.553382800Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[227; 305) '{ ...:ID; }': ()
8[237; 238) 'x': u32
9[241; 252) 'Struct::FOO': u32
10[262; 263) 'y': u32
11[266; 275) 'Enum::BAR': u32
12[285; 286) 'z': u32
13[289; 302) 'TraitTest::ID': u32
14
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_enum.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_enum.snap
new file mode 100644
index 000000000..8f27af88c
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_enum.snap
@@ -0,0 +1,20 @@
1---
2created: "2019-02-20T11:04:56.553382800Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[48; 68) '{ ... }': A
8[58; 62) 'A::B': A
9[89; 109) '{ ... }': A
10[99; 103) 'A::C': A
11[122; 179) '{ ... c; }': ()
12[132; 133) 'a': A
13[136; 140) 'A::b': fn b() -> A
14[136; 142) 'A::b()': A
15[148; 149) 'a': A
16[159; 160) 'c': A
17[163; 167) 'A::c': fn c() -> A
18[163; 169) 'A::c()': A
19[175; 176) 'c': A
20
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap
new file mode 100644
index 000000000..fe5d6590e
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_generics.snap
@@ -0,0 +1,16 @@
1---
2created: "2019-02-21T10:25:18.568887300Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[64; 67) 'val': T
8[82; 109) '{ ... }': Gen<T>
9[92; 103) 'Gen { val }': Gen<T>
10[98; 101) 'val': T
11[123; 155) '{ ...32); }': ()
12[133; 134) 'a': Gen<[unknown]>
13[137; 146) 'Gen::make': fn make<[unknown]>(T) -> Gen<T>
14[137; 152) 'Gen::make(0u32)': Gen<[unknown]>
15[147; 151) '0u32': u32
16
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_struct.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_struct.snap
new file mode 100644
index 000000000..29ca9b0ea
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_struct.snap
@@ -0,0 +1,16 @@
1---
2created: "2019-02-20T11:04:56.553382800Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[50; 76) '{ ... }': A
8[60; 70) 'A { x: 0 }': A
9[67; 68) '0': u32
10[89; 123) '{ ...a.x; }': ()
11[99; 100) 'a': A
12[103; 109) 'A::new': fn new() -> A
13[103; 111) 'A::new()': A
14[117; 118) 'a': A
15[117; 120) 'a.x': u32
16
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_with_modules.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_with_modules.snap
new file mode 100644
index 000000000..6584bef39
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_method_with_modules.snap
@@ -0,0 +1,23 @@
1---
2created: "2019-02-21T08:55:53.926725400Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[56; 64) '{ A {} }': A
8[58; 62) 'A {}': A
9[126; 132) '{ 99 }': u32
10[128; 130) '99': u32
11[202; 210) '{ C {} }': C
12[204; 208) 'C {}': C
13[241; 325) '{ ...g(); }': ()
14[251; 252) 'x': A
15[255; 266) 'a::A::thing': fn thing() -> A
16[255; 268) 'a::A::thing()': A
17[278; 279) 'y': u32
18[282; 293) 'b::B::thing': fn thing() -> u32
19[282; 295) 'b::B::thing()': u32
20[305; 306) 'z': C
21[309; 320) 'c::C::thing': fn thing() -> C
22[309; 322) 'c::C::thing()': C
23
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 4ab442b8a..c4b452ba4 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -587,6 +587,139 @@ fn test() -> i128 {
587} 587}
588 588
589#[test] 589#[test]
590fn infer_associated_const() {
591 check_inference(
592 "infer_associated_const",
593 r#"
594struct Struct;
595
596impl Struct {
597 const FOO: u32 = 1;
598}
599
600enum Enum;
601
602impl Enum {
603 const BAR: u32 = 2;
604}
605
606trait Trait {
607 const ID: u32;
608}
609
610struct TraitTest;
611
612impl Trait for TraitTest {
613 const ID: u32 = 5;
614}
615
616fn test() {
617 let x = Struct::FOO;
618 let y = Enum::BAR;
619 let z = TraitTest::ID;
620}
621"#,
622 );
623}
624
625#[test]
626fn infer_associated_method_struct() {
627 check_inference(
628 "infer_associated_method_struct",
629 r#"
630struct A { x: u32 };
631
632impl A {
633 fn new() -> A {
634 A { x: 0 }
635 }
636}
637fn test() {
638 let a = A::new();
639 a.x;
640}
641"#,
642 );
643}
644
645#[test]
646fn infer_associated_method_enum() {
647 check_inference(
648 "infer_associated_method_enum",
649 r#"
650enum A { B, C };
651
652impl A {
653 pub fn b() -> A {
654 A::B
655 }
656 pub fn c() -> A {
657 A::C
658 }
659}
660fn test() {
661 let a = A::b();
662 a;
663 let c = A::c();
664 c;
665}
666"#,
667 );
668}
669
670#[test]
671fn infer_associated_method_with_modules() {
672 check_inference(
673 "infer_associated_method_with_modules",
674 r#"
675mod a {
676 struct A;
677 impl A { pub fn thing() -> A { A {} }}
678}
679
680mod b {
681 struct B;
682 impl B { pub fn thing() -> u32 { 99 }}
683
684 mod c {
685 struct C;
686 impl C { pub fn thing() -> C { C {} }}
687 }
688}
689use b::c;
690
691fn test() {
692 let x = a::A::thing();
693 let y = b::B::thing();
694 let z = c::C::thing();
695}
696"#,
697 );
698}
699
700#[test]
701fn infer_associated_method_generics() {
702 check_inference(
703 "infer_associated_method_generics",
704 r#"
705struct Gen<T> {
706 val: T
707}
708
709impl<T> Gen<T> {
710 pub fn make(val: T) -> Gen<T> {
711 Gen { val }
712 }
713}
714
715fn test() {
716 let a = Gen::make(0u32);
717}
718"#,
719 );
720}
721
722#[test]
590fn no_panic_on_field_of_enum() { 723fn no_panic_on_field_of_enum() {
591 check_inference( 724 check_inference(
592 "no_panic_on_field_of_enum", 725 "no_panic_on_field_of_enum",
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index d337fe970..a0c5572d5 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -10,7 +10,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
10 Some(path) => path.clone(), 10 Some(path) => path.clone(),
11 _ => return, 11 _ => return,
12 }; 12 };
13 let def = match ctx.resolver.resolve_path(ctx.db, &path).take_types() { 13 let def = match ctx.resolver.resolve_path(ctx.db, &path).into_per_ns().take_types() {
14 Some(Resolution::Def(def)) => def, 14 Some(Resolution::Def(def)) => def,
15 _ => return, 15 _ => return,
16 }; 16 };
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 96ed8c8e9..76aaebd52 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -79,7 +79,7 @@ pub(crate) fn reference_definition(
79 if let Some(path) = 79 if let Some(path) =
80 name_ref.syntax().ancestors().find_map(ast::Path::cast).and_then(hir::Path::from_ast) 80 name_ref.syntax().ancestors().find_map(ast::Path::cast).and_then(hir::Path::from_ast)
81 { 81 {
82 let resolved = resolver.resolve_path(db, &path); 82 let resolved = resolver.resolve_path(db, &path).into_per_ns();
83 match resolved.clone().take_types().or_else(|| resolved.take_values()) { 83 match resolved.clone().take_types().or_else(|| resolved.take_values()) {
84 Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)), 84 Some(Resolution::Def(def)) => return Exact(NavigationTarget::from_def(db, def)),
85 Some(Resolution::LocalBinding(pat)) => { 85 Some(Resolution::LocalBinding(pat)) => {
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 0888ab6de..38671b394 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -223,4 +223,24 @@ mod tests {
223 assert_eq!("usize", &type_name); 223 assert_eq!("usize", &type_name);
224 } 224 }
225 225
226 #[test]
227 fn test_hover_infer_associated_method_result() {
228 let (analysis, position) = single_file_with_position(
229 "
230 struct Thing { x: u32 };
231
232 impl Thing {
233 fn new() -> Thing {
234 Thing { x: 0 }
235 }
236 }
237
238 fn main() {
239 let foo_<|>test = Thing::new();
240 }
241 ",
242 );
243 let hover = analysis.hover(position).unwrap().unwrap();
244 assert_eq!(hover.info, "Thing");
245 }
226} 246}