diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 23 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 78 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 55 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap | 14 |
4 files changed, 93 insertions, 77 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index b78a178c1..b18721104 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -119,10 +119,6 @@ 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 | |||
126 | pub fn take(self, namespace: Namespace) -> Option<T> { | 122 | pub fn take(self, namespace: Namespace) -> Option<T> { |
127 | match namespace { | 123 | match namespace { |
128 | Namespace::Types => self.types, | 124 | Namespace::Types => self.types, |
@@ -671,23 +667,20 @@ impl ItemMap { | |||
671 | } | 667 | } |
672 | } | 668 | } |
673 | } | 669 | } |
674 | ModuleDef::Struct(s) => { | 670 | s => { |
675 | return ResolvePathResult::with( | ||
676 | PerNs::types((*s).into()), | ||
677 | ReachedFixedPoint::Yes, | ||
678 | Some(i), | ||
679 | ); | ||
680 | } | ||
681 | _ => { | ||
682 | // could be an inherent method call in UFCS form | 671 | // could be an inherent method call in UFCS form |
683 | // (`Struct::method`), or some other kind of associated | 672 | // (`Struct::method`), or some other kind of associated item |
684 | // item... Which we currently don't handle (TODO) | ||
685 | log::debug!( | 673 | log::debug!( |
686 | "path segment {:?} resolved to non-module {:?}, but is not last", | 674 | "path segment {:?} resolved to non-module {:?}, but is not last", |
687 | segment.name, | 675 | segment.name, |
688 | curr, | 676 | curr, |
689 | ); | 677 | ); |
690 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | 678 | |
679 | return ResolvePathResult::with( | ||
680 | PerNs::types((*s).into()), | ||
681 | ReachedFixedPoint::Yes, | ||
682 | Some(i), | ||
683 | ); | ||
691 | } | 684 | } |
692 | }; | 685 | }; |
693 | } | 686 | } |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 00b55eae9..9f4d4ab42 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -33,27 +33,68 @@ pub(crate) struct ExprScope { | |||
33 | } | 33 | } |
34 | 34 | ||
35 | #[derive(Debug, Clone)] | 35 | #[derive(Debug, Clone)] |
36 | pub enum PathResult { | 36 | pub struct PathResult { |
37 | /// Path was fully resolved | 37 | /// The actual path resolution |
38 | FullyResolved(PerNs<Resolution>), | 38 | resolution: PerNs<Resolution>, |
39 | /// Path was partially resolved, first element contains the resolution | 39 | /// The first index in the path that we |
40 | /// second contains the index in the Path.segments which we were unable to resolve | 40 | /// were unable to resolve. |
41 | PartiallyResolved(PerNs<Resolution>, usize), | 41 | /// When path is fully resolved, this is 0. |
42 | remaining_index: usize, | ||
42 | } | 43 | } |
43 | 44 | ||
44 | impl PathResult { | 45 | impl PathResult { |
45 | pub fn segment_index(&self) -> Option<usize> { | 46 | /// Returns the remaining index in the result |
46 | match self { | 47 | /// returns None if the path was fully resolved |
47 | PathResult::FullyResolved(_) => None, | 48 | pub fn remaining_index(&self) -> Option<usize> { |
48 | PathResult::PartiallyResolved(_, ref i) => Some(*i), | 49 | if self.remaining_index > 0 { |
50 | Some(self.remaining_index) | ||
51 | } else { | ||
52 | None | ||
49 | } | 53 | } |
50 | } | 54 | } |
51 | 55 | ||
52 | /// Consumes `PathResult` and returns the contained `PerNs<Resolution>` | 56 | /// Consumes `PathResult` and returns the contained `PerNs<Resolution>` |
57 | /// if the path was fully resolved, meaning we have no remaining items | ||
53 | pub fn into_per_ns(self) -> PerNs<Resolution> { | 58 | pub fn into_per_ns(self) -> PerNs<Resolution> { |
54 | match self { | 59 | if self.remaining_index().is_none() { |
55 | PathResult::FullyResolved(def) => def, | 60 | self.resolution |
56 | PathResult::PartiallyResolved(def, _) => def, | 61 | } else { |
62 | PerNs::none() | ||
63 | } | ||
64 | } | ||
65 | |||
66 | /// Consumes `PathResult` and returns the resolution and the | ||
67 | /// remaining_index as a tuple. | ||
68 | pub fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) { | ||
69 | let index = self.remaining_index(); | ||
70 | (self.resolution, index) | ||
71 | } | ||
72 | |||
73 | /// Path is fully resolved when `remaining_index` is none | ||
74 | /// and the resolution contains anything | ||
75 | pub fn is_fully_resolved(&self) -> bool { | ||
76 | !self.resolution.is_none() && self.remaining_index().is_none() | ||
77 | } | ||
78 | |||
79 | /// Empty path result is where the resolution is `none` | ||
80 | /// and the remaining index is 0 | ||
81 | pub fn is_empty(&self) -> bool { | ||
82 | self.resolution.is_none() && self.remaining_index().is_none() | ||
83 | } | ||
84 | |||
85 | fn empty() -> PathResult { | ||
86 | PathResult { resolution: PerNs::none(), remaining_index: 0 } | ||
87 | } | ||
88 | |||
89 | fn from_resolution(res: PerNs<Resolution>) -> PathResult { | ||
90 | PathResult::from_resolution_with_index(res, 0) | ||
91 | } | ||
92 | |||
93 | fn from_resolution_with_index(res: PerNs<Resolution>, remaining_index: usize) -> PathResult { | ||
94 | if res.is_none() { | ||
95 | PathResult::empty() | ||
96 | } else { | ||
97 | PathResult { resolution: res, remaining_index } | ||
57 | } | 98 | } |
58 | } | 99 | } |
59 | } | 100 | } |
@@ -94,24 +135,23 @@ impl Resolver { | |||
94 | } | 135 | } |
95 | 136 | ||
96 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PathResult { | 137 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &Path) -> PathResult { |
97 | use self::PathResult::*; | ||
98 | if let Some(name) = path.as_ident() { | 138 | if let Some(name) = path.as_ident() { |
99 | FullyResolved(self.resolve_name(db, name)) | 139 | PathResult::from_resolution(self.resolve_name(db, name)) |
100 | } else if path.is_self() { | 140 | } else if path.is_self() { |
101 | FullyResolved(self.resolve_name(db, &Name::self_param())) | 141 | PathResult::from_resolution(self.resolve_name(db, &Name::self_param())) |
102 | } else { | 142 | } else { |
103 | let (item_map, module) = match self.module() { | 143 | let (item_map, module) = match self.module() { |
104 | Some(m) => m, | 144 | Some(m) => m, |
105 | _ => return FullyResolved(PerNs::none()), | 145 | _ => return PathResult::empty(), |
106 | }; | 146 | }; |
107 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); | 147 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); |
108 | 148 | ||
109 | let def = module_res.map(Resolution::Def); | 149 | let def = module_res.map(Resolution::Def); |
110 | 150 | ||
111 | if let Some(index) = segment_index { | 151 | if let Some(index) = segment_index { |
112 | PartiallyResolved(def, index) | 152 | PathResult::from_resolution_with_index(def, index) |
113 | } else { | 153 | } else { |
114 | FullyResolved(def) | 154 | PathResult::from_resolution(def) |
115 | } | 155 | } |
116 | } | 156 | } |
117 | } | 157 | } |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 2751ab3ab..b1f35ab1f 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -32,20 +32,17 @@ use rustc_hash::FxHashMap; | |||
32 | 32 | ||
33 | use test_utils::tested_by; | 33 | use test_utils::tested_by; |
34 | 34 | ||
35 | use ra_syntax::ast::NameOwner; | ||
36 | |||
37 | use crate::{ | 35 | use crate::{ |
38 | Function, Struct, StructField, Enum, EnumVariant, Path, Name, | 36 | Function, Struct, StructField, Enum, EnumVariant, Path, Name, |
39 | Const, | ||
40 | FnSignature, ModuleDef, AdtDef, | 37 | FnSignature, ModuleDef, AdtDef, |
41 | HirDatabase, | 38 | HirDatabase, |
42 | type_ref::{TypeRef, Mutability}, | 39 | type_ref::{TypeRef, Mutability}, |
43 | name::{KnownName, AsName}, | 40 | name::{KnownName}, |
44 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, | 41 | expr::{Body, Expr, BindingAnnotation, Literal, ExprId, Pat, PatId, UnaryOp, BinaryOp, Statement, FieldPat, self}, |
45 | generics::GenericParams, | 42 | generics::GenericParams, |
46 | path::GenericArg, | 43 | path::GenericArg, |
47 | adt::VariantDef, | 44 | adt::VariantDef, |
48 | resolve::{Resolver, Resolution, PathResult}, nameres::Namespace | 45 | resolve::{Resolver, Resolution}, nameres::Namespace |
49 | }; | 46 | }; |
50 | 47 | ||
51 | /// The ID of a type variable. | 48 | /// The ID of a type variable. |
@@ -681,19 +678,6 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { | |||
681 | Ty::FnDef { def: def.into(), sig, name, substs } | 678 | Ty::FnDef { def: def.into(), sig, name, substs } |
682 | } | 679 | } |
683 | 680 | ||
684 | fn 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 | |||
697 | /// Compute the type of a tuple struct constructor. | 681 | /// Compute the type of a tuple struct constructor. |
698 | fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { | 682 | fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty { |
699 | let var_data = def.variant_data(db); | 683 | let var_data = def.variant_data(db); |
@@ -1190,21 +1174,28 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1190 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { | 1174 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path) -> Option<Ty> { |
1191 | let resolved = resolver.resolve_path(self.db, &path); | 1175 | let resolved = resolver.resolve_path(self.db, &path); |
1192 | 1176 | ||
1193 | let (resolved, segment_index) = match resolved { | 1177 | let (def, remaining_index) = resolved.into_inner(); |
1194 | PathResult::FullyResolved(def) => (def.take_values()?, None), | 1178 | |
1195 | PathResult::PartiallyResolved(def, index) => (def.take_types()?, Some(index)), | 1179 | // if the remaining_index is None, we expect the path |
1196 | }; | 1180 | // to be fully resolved, in this case we continue with |
1181 | // the default by attempting to `take_values´ from the resolution. | ||
1182 | // Otherwise the path was partially resolved, which means | ||
1183 | // we might have resolved into a type for which | ||
1184 | // we may find some associated item starting at the | ||
1185 | // path.segment pointed to by `remaining_index´ | ||
1186 | let resolved = | ||
1187 | if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; | ||
1197 | 1188 | ||
1198 | match resolved { | 1189 | match resolved { |
1199 | Resolution::Def(def) => { | 1190 | Resolution::Def(def) => { |
1200 | let typable: Option<TypableDef> = def.into(); | 1191 | let typable: Option<TypableDef> = def.into(); |
1201 | let typable = typable?; | 1192 | let typable = typable?; |
1202 | 1193 | ||
1203 | if let Some(segment_index) = segment_index { | 1194 | if let Some(remaining_index) = remaining_index { |
1204 | let ty = self.db.type_for_def(typable, Namespace::Types); | 1195 | let ty = self.db.type_for_def(typable, Namespace::Types); |
1205 | // TODO: What to do if segment_index is not the last segment | 1196 | // TODO: Keep resolving the segments |
1206 | // in the path | 1197 | // if we have more segments to process |
1207 | let segment = &path.segments[segment_index]; | 1198 | let segment = &path.segments[remaining_index]; |
1208 | 1199 | ||
1209 | // Attempt to find an impl_item for the type which has a name matching | 1200 | // Attempt to find an impl_item for the type which has a name matching |
1210 | // the current segment | 1201 | // the current segment |
@@ -1216,17 +1207,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1216 | } | 1207 | } |
1217 | None | 1208 | None |
1218 | } | 1209 | } |
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 | 1210 | ||
1228 | None | 1211 | // TODO: Resolve associated const |
1229 | } | 1212 | crate::ImplItem::Const(_) => None, |
1230 | 1213 | ||
1231 | // TODO: Resolve associated types | 1214 | // TODO: Resolve associated types |
1232 | crate::ImplItem::Type(_) => None, | 1215 | crate::ImplItem::Type(_) => None, |
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 index 14ab8ba96..131d1fa16 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_associated_const.snap | |||
@@ -1,14 +1,14 @@ | |||
1 | --- | 1 | --- |
2 | created: "2019-02-20T11:04:56.553382800Z" | 2 | created: "2019-02-21T21:51:46.497925200Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | source: crates/ra_hir/src/ty/tests.rs | 4 | source: crates/ra_hir/src/ty/tests.rs |
5 | expression: "&result" | 5 | expression: "&result" |
6 | --- | 6 | --- |
7 | [227; 305) '{ ...:ID; }': () | 7 | [227; 305) '{ ...:ID; }': () |
8 | [237; 238) 'x': u32 | 8 | [237; 238) 'x': [unknown] |
9 | [241; 252) 'Struct::FOO': u32 | 9 | [241; 252) 'Struct::FOO': [unknown] |
10 | [262; 263) 'y': u32 | 10 | [262; 263) 'y': [unknown] |
11 | [266; 275) 'Enum::BAR': u32 | 11 | [266; 275) 'Enum::BAR': [unknown] |
12 | [285; 286) 'z': u32 | 12 | [285; 286) 'z': [unknown] |
13 | [289; 302) 'TraitTest::ID': u32 | 13 | [289; 302) 'TraitTest::ID': [unknown] |
14 | 14 | ||