diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 10 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/per_ns.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 405 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 66 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 256 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 108 |
8 files changed, 458 insertions, 408 deletions
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index c1938bd86..dad1c93c4 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -22,7 +22,7 @@ use crate::{ | |||
22 | U8, USIZE, | 22 | U8, USIZE, |
23 | }, | 23 | }, |
24 | nameres::{CrateModuleId, ImportId, ModuleScope, Namespace}, | 24 | nameres::{CrateModuleId, ImportId, ModuleScope, Namespace}, |
25 | resolve::Resolver, | 25 | resolve::{Resolver, TypeNs}, |
26 | traits::{TraitData, TraitItem}, | 26 | traits::{TraitData, TraitItem}, |
27 | ty::{ | 27 | ty::{ |
28 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, | 28 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, |
@@ -868,11 +868,9 @@ impl Trait { | |||
868 | } | 868 | } |
869 | _ => None, | 869 | _ => None, |
870 | }) | 870 | }) |
871 | .filter_map(|path| { | 871 | .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { |
872 | match resolver.resolve_path_without_assoc_items(db, path).take_types() { | 872 | Some(TypeNs::Trait(t)) => Some(t), |
873 | Some(crate::Resolution::Def(ModuleDef::Trait(t))) => Some(t), | 873 | _ => None, |
874 | _ => None, | ||
875 | } | ||
876 | }) | 874 | }) |
877 | .collect() | 875 | .collect() |
878 | } | 876 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 508da3623..80cf8d9c0 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -73,7 +73,7 @@ pub use self::{ | |||
73 | name::Name, | 73 | name::Name, |
74 | nameres::{ImportId, Namespace, PerNs}, | 74 | nameres::{ImportId, Namespace, PerNs}, |
75 | path::{Path, PathKind}, | 75 | path::{Path, PathKind}, |
76 | resolve::Resolution, | 76 | resolve::ScopeDef, |
77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, | 77 | source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, |
78 | source_id::{AstIdMap, ErasedFileAstId}, | 78 | source_id::{AstIdMap, ErasedFileAstId}, |
79 | ty::{ | 79 | ty::{ |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 3a3bf6b5f..44a4ddba0 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -279,10 +279,6 @@ impl CrateDefMap { | |||
279 | self.root | 279 | self.root |
280 | } | 280 | } |
281 | 281 | ||
282 | pub(crate) fn mk_module(&self, module_id: CrateModuleId) -> Module { | ||
283 | Module { krate: self.krate, module_id } | ||
284 | } | ||
285 | |||
286 | pub(crate) fn prelude(&self) -> Option<Module> { | 282 | pub(crate) fn prelude(&self) -> Option<Module> { |
287 | self.prelude | 283 | self.prelude |
288 | } | 284 | } |
@@ -389,7 +385,7 @@ impl CrateDefMap { | |||
389 | }; | 385 | }; |
390 | 386 | ||
391 | for (i, segment) in segments { | 387 | for (i, segment) in segments { |
392 | let curr = match curr_per_ns.as_ref().take_types() { | 388 | let curr = match curr_per_ns.take_types() { |
393 | Some(r) => r, | 389 | Some(r) => r, |
394 | None => { | 390 | None => { |
395 | // we still have path segments left, but the path so far | 391 | // we still have path segments left, but the path so far |
@@ -433,7 +429,7 @@ impl CrateDefMap { | |||
433 | Some(variant) => PerNs::both(variant.into(), variant.into()), | 429 | Some(variant) => PerNs::both(variant.into(), variant.into()), |
434 | None => { | 430 | None => { |
435 | return ResolvePathResult::with( | 431 | return ResolvePathResult::with( |
436 | PerNs::types((*e).into()), | 432 | PerNs::types(e.into()), |
437 | ReachedFixedPoint::Yes, | 433 | ReachedFixedPoint::Yes, |
438 | Some(i), | 434 | Some(i), |
439 | ); | 435 | ); |
@@ -450,7 +446,7 @@ impl CrateDefMap { | |||
450 | ); | 446 | ); |
451 | 447 | ||
452 | return ResolvePathResult::with( | 448 | return ResolvePathResult::with( |
453 | PerNs::types(*s), | 449 | PerNs::types(s), |
454 | ReachedFixedPoint::Yes, | 450 | ReachedFixedPoint::Yes, |
455 | Some(i), | 451 | Some(i), |
456 | ); | 452 | ); |
diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir/src/nameres/per_ns.rs index d07cc08f4..b0f4dff33 100644 --- a/crates/ra_hir/src/nameres/per_ns.rs +++ b/crates/ra_hir/src/nameres/per_ns.rs | |||
@@ -68,10 +68,6 @@ impl<T> PerNs<T> { | |||
68 | PerNs { types: None, values: None, macros: self.macros } | 68 | PerNs { types: None, values: None, macros: self.macros } |
69 | } | 69 | } |
70 | 70 | ||
71 | pub fn as_ref(&self) -> PerNs<&T> { | ||
72 | PerNs { types: self.types.as_ref(), values: self.values.as_ref(), macros: self.macros } | ||
73 | } | ||
74 | |||
75 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { | 71 | pub fn or(self, other: PerNs<T>) -> PerNs<T> { |
76 | PerNs { | 72 | PerNs { |
77 | types: self.types.or(other.types), | 73 | types: self.types.or(other.types), |
@@ -79,9 +75,4 @@ impl<T> PerNs<T> { | |||
79 | macros: self.macros.or(other.macros), | 75 | macros: self.macros.or(other.macros), |
80 | } | 76 | } |
81 | } | 77 | } |
82 | |||
83 | /// Map types and values. Leave macros unchanged. | ||
84 | pub fn map<U>(self, f: impl Fn(T) -> U) -> PerNs<U> { | ||
85 | PerNs { types: self.types.map(&f), values: self.values.map(&f), macros: self.macros } | ||
86 | } | ||
87 | } | 78 | } |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index a77a9aeb1..d841593f8 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! Name resolution. | 1 | //! Name resolution. |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use rustc_hash::{FxHashMap, FxHashSet}; | 4 | use rustc_hash::FxHashSet; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | code_model::Crate, | 7 | code_model::Crate, |
@@ -14,8 +14,9 @@ use crate::{ | |||
14 | impl_block::ImplBlock, | 14 | impl_block::ImplBlock, |
15 | name::{Name, SELF_PARAM, SELF_TYPE}, | 15 | name::{Name, SELF_PARAM, SELF_TYPE}, |
16 | nameres::{CrateDefMap, CrateModuleId, PerNs}, | 16 | nameres::{CrateDefMap, CrateModuleId, PerNs}, |
17 | path::Path, | 17 | path::{Path, PathKind}, |
18 | Adt, Enum, MacroDef, ModuleDef, Struct, Trait, | 18 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, |
19 | Trait, TypeAlias, | ||
19 | }; | 20 | }; |
20 | 21 | ||
21 | #[derive(Debug, Clone, Default)] | 22 | #[derive(Debug, Clone, Default)] |
@@ -37,69 +38,6 @@ pub(crate) struct ExprScope { | |||
37 | } | 38 | } |
38 | 39 | ||
39 | #[derive(Debug, Clone)] | 40 | #[derive(Debug, Clone)] |
40 | pub(crate) struct PathResult { | ||
41 | /// The actual path resolution | ||
42 | // FIXME: `PerNs<Resolution>` type doesn't make sense, as not every | ||
43 | // Resolution variant can appear in every namespace | ||
44 | resolution: PerNs<Resolution>, | ||
45 | /// The first index in the path that we | ||
46 | /// were unable to resolve. | ||
47 | /// When path is fully resolved, this is 0. | ||
48 | remaining_index: usize, | ||
49 | } | ||
50 | |||
51 | impl PathResult { | ||
52 | /// Returns the remaining index in the result | ||
53 | /// returns None if the path was fully resolved | ||
54 | pub(crate) fn remaining_index(&self) -> Option<usize> { | ||
55 | if self.remaining_index > 0 { | ||
56 | Some(self.remaining_index) | ||
57 | } else { | ||
58 | None | ||
59 | } | ||
60 | } | ||
61 | |||
62 | /// Consumes `PathResult` and returns the contained `PerNs<Resolution>` | ||
63 | /// if the path was fully resolved, meaning we have no remaining items | ||
64 | pub(crate) fn into_fully_resolved(self) -> PerNs<Resolution> { | ||
65 | if self.is_fully_resolved() { | ||
66 | self.resolution | ||
67 | } else { | ||
68 | PerNs::none() | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /// Consumes `PathResult` and returns the resolution and the | ||
73 | /// remaining_index as a tuple. | ||
74 | pub(crate) fn into_inner(self) -> (PerNs<Resolution>, Option<usize>) { | ||
75 | let index = self.remaining_index(); | ||
76 | (self.resolution, index) | ||
77 | } | ||
78 | |||
79 | /// Path is fully resolved when `remaining_index` is none | ||
80 | /// and the resolution contains anything | ||
81 | pub(crate) fn is_fully_resolved(&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 } | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | #[derive(Debug, Clone)] | ||
103 | pub(crate) enum Scope { | 41 | pub(crate) enum Scope { |
104 | /// All the items and imported names of a module | 42 | /// All the items and imported names of a module |
105 | ModuleScope(ModuleItemMap), | 43 | ModuleScope(ModuleItemMap), |
@@ -112,25 +50,41 @@ pub(crate) enum Scope { | |||
112 | } | 50 | } |
113 | 51 | ||
114 | #[derive(Debug, Clone, PartialEq, Eq)] | 52 | #[derive(Debug, Clone, PartialEq, Eq)] |
115 | pub enum Resolution { | 53 | pub enum TypeNs { |
116 | /// An item | 54 | SelfType(ImplBlock), |
117 | Def(ModuleDef), | 55 | GenericParam(u32), |
56 | Adt(Adt), | ||
57 | EnumVariant(EnumVariant), | ||
58 | TypeAlias(TypeAlias), | ||
59 | BuiltinType(BuiltinType), | ||
60 | Trait(Trait), | ||
61 | // Module belong to type ns, but the resovler is used when all module paths | ||
62 | // are fully resolved. | ||
63 | // Module(Module) | ||
64 | } | ||
65 | |||
66 | #[derive(Debug)] | ||
67 | pub enum ValueOrPartial { | ||
68 | ValueNs(ValueNs), | ||
69 | Partial(TypeNs, usize), | ||
70 | } | ||
118 | 71 | ||
119 | // FIXME: there's no way we can syntactically confuse a local with generic | 72 | #[derive(Debug)] |
120 | // param, so these two should not be members of the single enum | 73 | pub enum ValueNs { |
121 | /// A local binding (only value namespace) | ||
122 | LocalBinding(PatId), | 74 | LocalBinding(PatId), |
123 | /// A generic parameter | 75 | Function(Function), |
124 | GenericParam(u32), | 76 | Const(Const), |
125 | SelfType(ImplBlock), | 77 | Static(Static), |
78 | Struct(Struct), | ||
79 | EnumVariant(EnumVariant), | ||
126 | } | 80 | } |
127 | 81 | ||
128 | impl Resolver { | 82 | impl Resolver { |
129 | /// Resolve known trait from std, like `std::futures::Future` | 83 | /// Resolve known trait from std, like `std::futures::Future` |
130 | pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> { | 84 | pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option<Trait> { |
131 | let res = self.resolve_path_segments(db, path).into_fully_resolved().take_types()?; | 85 | let res = self.resolve_module_path(db, path).take_types()?; |
132 | match res { | 86 | match res { |
133 | Resolution::Def(ModuleDef::Trait(it)) => Some(it), | 87 | ModuleDef::Trait(it) => Some(it), |
134 | _ => None, | 88 | _ => None, |
135 | } | 89 | } |
136 | } | 90 | } |
@@ -141,94 +95,214 @@ impl Resolver { | |||
141 | db: &impl HirDatabase, | 95 | db: &impl HirDatabase, |
142 | path: &Path, | 96 | path: &Path, |
143 | ) -> Option<Struct> { | 97 | ) -> Option<Struct> { |
144 | let res = self.resolve_path_segments(db, path).into_fully_resolved().take_types()?; | 98 | let res = self.resolve_module_path(db, path).take_types()?; |
145 | match res { | 99 | match res { |
146 | Resolution::Def(ModuleDef::Adt(Adt::Struct(it))) => Some(it), | 100 | ModuleDef::Adt(Adt::Struct(it)) => Some(it), |
147 | _ => None, | 101 | _ => None, |
148 | } | 102 | } |
149 | } | 103 | } |
150 | 104 | ||
151 | /// Resolve known enum from std, like `std::result::Result` | 105 | /// Resolve known enum from std, like `std::result::Result` |
152 | pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> { | 106 | pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option<Enum> { |
153 | let res = self.resolve_path_segments(db, path).into_fully_resolved().take_types()?; | 107 | let res = self.resolve_module_path(db, path).take_types()?; |
154 | match res { | 108 | match res { |
155 | Resolution::Def(ModuleDef::Adt(Adt::Enum(it))) => Some(it), | 109 | ModuleDef::Adt(Adt::Enum(it)) => Some(it), |
156 | _ => None, | 110 | _ => None, |
157 | } | 111 | } |
158 | } | 112 | } |
159 | 113 | ||
160 | pub(crate) fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> { | 114 | /// pub only for source-binder |
161 | let mut resolution = PerNs::none(); | 115 | pub(crate) fn resolve_module_path( |
116 | &self, | ||
117 | db: &impl HirDatabase, | ||
118 | path: &Path, | ||
119 | ) -> PerNs<ModuleDef> { | ||
120 | let (item_map, module) = match self.module() { | ||
121 | Some(it) => it, | ||
122 | None => return PerNs::none(), | ||
123 | }; | ||
124 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); | ||
125 | if segment_index.is_some() { | ||
126 | return PerNs::none(); | ||
127 | } | ||
128 | module_res | ||
129 | } | ||
130 | |||
131 | pub(crate) fn resolve_path_in_type_ns( | ||
132 | &self, | ||
133 | db: &impl HirDatabase, | ||
134 | path: &Path, | ||
135 | ) -> Option<(TypeNs, Option<usize>)> { | ||
136 | let first_name = &path.segments.first()?.name; | ||
137 | let skip_to_mod = path.kind != PathKind::Plain; | ||
162 | for scope in self.scopes.iter().rev() { | 138 | for scope in self.scopes.iter().rev() { |
163 | resolution = resolution.or(scope.resolve_name(db, name)); | 139 | match scope { |
164 | if resolution.is_all() { | 140 | Scope::ExprScope(_) => continue, |
165 | return resolution; | 141 | Scope::GenericParams(_) | Scope::ImplBlockScope(_) if skip_to_mod => continue, |
142 | |||
143 | Scope::GenericParams(params) => { | ||
144 | if let Some(param) = params.find_by_name(first_name) { | ||
145 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | ||
146 | return Some((TypeNs::GenericParam(param.idx), idx)); | ||
147 | } | ||
148 | } | ||
149 | Scope::ImplBlockScope(impl_) => { | ||
150 | if first_name == &SELF_TYPE { | ||
151 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | ||
152 | return Some((TypeNs::SelfType(*impl_), idx)); | ||
153 | } | ||
154 | } | ||
155 | Scope::ModuleScope(m) => { | ||
156 | let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); | ||
157 | let res = match module_def.take_types()? { | ||
158 | ModuleDef::Adt(it) => TypeNs::Adt(it), | ||
159 | ModuleDef::EnumVariant(it) => TypeNs::EnumVariant(it), | ||
160 | |||
161 | ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it), | ||
162 | ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it), | ||
163 | |||
164 | ModuleDef::Trait(it) => TypeNs::Trait(it), | ||
165 | |||
166 | ModuleDef::Function(_) | ||
167 | | ModuleDef::Const(_) | ||
168 | | ModuleDef::Static(_) | ||
169 | | ModuleDef::Module(_) => return None, | ||
170 | }; | ||
171 | return Some((res, idx)); | ||
172 | } | ||
166 | } | 173 | } |
167 | } | 174 | } |
168 | resolution | 175 | None |
169 | } | 176 | } |
170 | 177 | ||
171 | pub(crate) fn resolve_path_as_macro( | 178 | pub(crate) fn resolve_path_in_type_ns_fully( |
172 | &self, | 179 | &self, |
173 | db: &impl HirDatabase, | 180 | db: &impl HirDatabase, |
174 | path: &Path, | 181 | path: &Path, |
175 | ) -> Option<MacroDef> { | 182 | ) -> Option<TypeNs> { |
176 | let (item_map, module) = self.module()?; | 183 | let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; |
177 | item_map.resolve_path(db, module, path).0.get_macros() | 184 | if unresolved.is_some() { |
185 | return None; | ||
186 | } | ||
187 | Some(res) | ||
178 | } | 188 | } |
179 | 189 | ||
180 | /// Returns the resolved path segments | 190 | pub(crate) fn resolve_path_in_value_ns( |
181 | /// Which may be fully resolved, empty or partially resolved. | 191 | &self, |
182 | pub(crate) fn resolve_path_segments(&self, db: &impl HirDatabase, path: &Path) -> PathResult { | 192 | db: &impl HirDatabase, |
183 | if let Some(name) = path.as_ident() { | 193 | path: &Path, |
184 | PathResult::from_resolution(self.resolve_name(db, name)) | 194 | ) -> Option<ValueOrPartial> { |
185 | } else if path.is_self() { | 195 | let n_segments = path.segments.len(); |
186 | PathResult::from_resolution(self.resolve_name(db, &SELF_PARAM)) | 196 | let tmp = SELF_PARAM; |
187 | } else { | 197 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; |
188 | let (item_map, module) = match self.module() { | 198 | let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); |
189 | Some(it) => it, | 199 | for scope in self.scopes.iter().rev() { |
190 | None => return PathResult::empty(), | 200 | match scope { |
191 | }; | 201 | Scope::ExprScope(_) | Scope::GenericParams(_) | Scope::ImplBlockScope(_) |
192 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); | 202 | if skip_to_mod => |
193 | 203 | { | |
194 | let def = module_res.map(Resolution::Def); | 204 | continue |
195 | 205 | } | |
196 | if let Some(index) = segment_index { | 206 | |
197 | PathResult::from_resolution_with_index(def, index) | 207 | Scope::ExprScope(scope) if n_segments <= 1 => { |
198 | } else { | 208 | let entry = scope |
199 | PathResult::from_resolution(def) | 209 | .expr_scopes |
210 | .entries(scope.scope_id) | ||
211 | .iter() | ||
212 | .find(|entry| entry.name() == first_name); | ||
213 | |||
214 | if let Some(e) = entry { | ||
215 | return Some(ValueOrPartial::ValueNs(ValueNs::LocalBinding(e.pat()))); | ||
216 | } | ||
217 | } | ||
218 | Scope::ExprScope(_) => continue, | ||
219 | |||
220 | Scope::GenericParams(params) if n_segments > 1 => { | ||
221 | if let Some(param) = params.find_by_name(first_name) { | ||
222 | let ty = TypeNs::GenericParam(param.idx); | ||
223 | return Some(ValueOrPartial::Partial(ty, 1)); | ||
224 | } | ||
225 | } | ||
226 | Scope::GenericParams(_) => continue, | ||
227 | |||
228 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { | ||
229 | if first_name == &SELF_TYPE { | ||
230 | let ty = TypeNs::SelfType(*impl_); | ||
231 | return Some(ValueOrPartial::Partial(ty, 1)); | ||
232 | } | ||
233 | } | ||
234 | Scope::ImplBlockScope(_) => continue, | ||
235 | |||
236 | Scope::ModuleScope(m) => { | ||
237 | let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); | ||
238 | return match idx { | ||
239 | None => { | ||
240 | let value = match module_def.take_values()? { | ||
241 | ModuleDef::Function(it) => ValueNs::Function(it), | ||
242 | ModuleDef::Adt(Adt::Struct(it)) => ValueNs::Struct(it), | ||
243 | ModuleDef::EnumVariant(it) => ValueNs::EnumVariant(it), | ||
244 | ModuleDef::Const(it) => ValueNs::Const(it), | ||
245 | ModuleDef::Static(it) => ValueNs::Static(it), | ||
246 | |||
247 | ModuleDef::Adt(Adt::Enum(_)) | ||
248 | | ModuleDef::Adt(Adt::Union(_)) | ||
249 | | ModuleDef::Trait(_) | ||
250 | | ModuleDef::TypeAlias(_) | ||
251 | | ModuleDef::BuiltinType(_) | ||
252 | | ModuleDef::Module(_) => return None, | ||
253 | }; | ||
254 | Some(ValueOrPartial::ValueNs(value)) | ||
255 | } | ||
256 | Some(idx) => { | ||
257 | let ty = match module_def.take_types()? { | ||
258 | ModuleDef::Adt(it) => TypeNs::Adt(it), | ||
259 | ModuleDef::Trait(it) => TypeNs::Trait(it), | ||
260 | ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it), | ||
261 | ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it), | ||
262 | |||
263 | ModuleDef::Module(_) | ||
264 | | ModuleDef::Function(_) | ||
265 | | ModuleDef::EnumVariant(_) | ||
266 | | ModuleDef::Const(_) | ||
267 | | ModuleDef::Static(_) => return None, | ||
268 | }; | ||
269 | Some(ValueOrPartial::Partial(ty, idx)) | ||
270 | } | ||
271 | }; | ||
272 | } | ||
200 | } | 273 | } |
201 | } | 274 | } |
275 | None | ||
202 | } | 276 | } |
203 | 277 | ||
204 | /// Returns the fully resolved path if we were able to resolve it. | 278 | pub(crate) fn resolve_path_in_value_ns_fully( |
205 | /// otherwise returns `PerNs::none` | ||
206 | pub(crate) fn resolve_path_without_assoc_items( | ||
207 | &self, | 279 | &self, |
208 | db: &impl HirDatabase, | 280 | db: &impl HirDatabase, |
209 | path: &Path, | 281 | path: &Path, |
210 | ) -> PerNs<Resolution> { | 282 | ) -> Option<ValueNs> { |
211 | // into_fully_resolved() returns the fully resolved path or PerNs::none() otherwise | 283 | match self.resolve_path_in_value_ns(db, path)? { |
212 | self.resolve_path_segments(db, path).into_fully_resolved() | 284 | ValueOrPartial::ValueNs(it) => Some(it), |
285 | ValueOrPartial::Partial(..) => None, | ||
286 | } | ||
213 | } | 287 | } |
214 | 288 | ||
215 | pub(crate) fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<Resolution>> { | 289 | pub(crate) fn resolve_path_as_macro( |
216 | let mut names = FxHashMap::default(); | 290 | &self, |
291 | db: &impl HirDatabase, | ||
292 | path: &Path, | ||
293 | ) -> Option<MacroDef> { | ||
294 | let (item_map, module) = self.module()?; | ||
295 | item_map.resolve_path(db, module, path).0.get_macros() | ||
296 | } | ||
297 | |||
298 | pub(crate) fn process_all_names( | ||
299 | &self, | ||
300 | db: &impl HirDatabase, | ||
301 | f: &mut dyn FnMut(Name, ScopeDef), | ||
302 | ) { | ||
217 | for scope in self.scopes.iter().rev() { | 303 | for scope in self.scopes.iter().rev() { |
218 | scope.collect_names(db, &mut |name, res| { | 304 | scope.process_names(db, f); |
219 | let current: &mut PerNs<Resolution> = names.entry(name).or_default(); | ||
220 | if current.types.is_none() { | ||
221 | current.types = res.types; | ||
222 | } | ||
223 | if current.values.is_none() { | ||
224 | current.values = res.values; | ||
225 | } | ||
226 | if current.macros.is_none() { | ||
227 | current.macros = res.macros; | ||
228 | } | ||
229 | }); | ||
230 | } | 305 | } |
231 | names | ||
232 | } | 306 | } |
233 | 307 | ||
234 | pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> { | 308 | pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> { |
@@ -301,41 +375,28 @@ impl Resolver { | |||
301 | } | 375 | } |
302 | } | 376 | } |
303 | 377 | ||
304 | impl Scope { | 378 | /// For IDE only |
305 | fn resolve_name(&self, db: &impl HirDatabase, name: &Name) -> PerNs<Resolution> { | 379 | pub enum ScopeDef { |
306 | match self { | 380 | ModuleDef(ModuleDef), |
307 | Scope::ModuleScope(m) => { | 381 | MacroDef(MacroDef), |
308 | if name == &SELF_PARAM { | 382 | GenericParam(u32), |
309 | PerNs::types(Resolution::Def(m.crate_def_map.mk_module(m.module_id).into())) | 383 | SelfType(ImplBlock), |
310 | } else { | 384 | LocalBinding(PatId), |
311 | m.crate_def_map | 385 | Unknown, |
312 | .resolve_name_in_module(db, m.module_id, name) | 386 | } |
313 | .map(Resolution::Def) | 387 | |
314 | } | 388 | impl From<PerNs<ModuleDef>> for ScopeDef { |
315 | } | 389 | fn from(def: PerNs<ModuleDef>) -> Self { |
316 | Scope::GenericParams(gp) => match gp.find_by_name(name) { | 390 | def.take_types() |
317 | Some(gp) => PerNs::types(Resolution::GenericParam(gp.idx)), | 391 | .or_else(|| def.take_values()) |
318 | None => PerNs::none(), | 392 | .map(ScopeDef::ModuleDef) |
319 | }, | 393 | .or_else(|| def.get_macros().map(ScopeDef::MacroDef)) |
320 | Scope::ImplBlockScope(i) => { | 394 | .unwrap_or(ScopeDef::Unknown) |
321 | if name == &SELF_TYPE { | ||
322 | PerNs::types(Resolution::SelfType(*i)) | ||
323 | } else { | ||
324 | PerNs::none() | ||
325 | } | ||
326 | } | ||
327 | Scope::ExprScope(e) => { | ||
328 | let entry = | ||
329 | e.expr_scopes.entries(e.scope_id).iter().find(|entry| entry.name() == name); | ||
330 | match entry { | ||
331 | Some(e) => PerNs::values(Resolution::LocalBinding(e.pat())), | ||
332 | None => PerNs::none(), | ||
333 | } | ||
334 | } | ||
335 | } | ||
336 | } | 395 | } |
396 | } | ||
337 | 397 | ||
338 | fn collect_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, PerNs<Resolution>)) { | 398 | impl Scope { |
399 | fn process_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { | ||
339 | match self { | 400 | match self { |
340 | Scope::ModuleScope(m) => { | 401 | Scope::ModuleScope(m) => { |
341 | // FIXME: should we provide `self` here? | 402 | // FIXME: should we provide `self` here? |
@@ -346,32 +407,32 @@ impl Scope { | |||
346 | // }), | 407 | // }), |
347 | // ); | 408 | // ); |
348 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { | 409 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { |
349 | f(name.clone(), res.def.map(Resolution::Def)); | 410 | f(name.clone(), res.def.into()); |
350 | }); | 411 | }); |
351 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { | 412 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { |
352 | f(name.clone(), PerNs::macros(macro_)); | 413 | f(name.clone(), ScopeDef::MacroDef(macro_)); |
353 | }); | 414 | }); |
354 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { | 415 | m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { |
355 | f(name.clone(), PerNs::types(Resolution::Def(*def))); | 416 | f(name.clone(), ScopeDef::ModuleDef(*def)); |
356 | }); | 417 | }); |
357 | if let Some(prelude) = m.crate_def_map.prelude() { | 418 | if let Some(prelude) = m.crate_def_map.prelude() { |
358 | let prelude_def_map = db.crate_def_map(prelude.krate); | 419 | let prelude_def_map = db.crate_def_map(prelude.krate); |
359 | prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { | 420 | prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { |
360 | f(name.clone(), res.def.map(Resolution::Def)); | 421 | f(name.clone(), res.def.into()); |
361 | }); | 422 | }); |
362 | } | 423 | } |
363 | } | 424 | } |
364 | Scope::GenericParams(gp) => { | 425 | Scope::GenericParams(gp) => { |
365 | for param in &gp.params { | 426 | for param in &gp.params { |
366 | f(param.name.clone(), PerNs::types(Resolution::GenericParam(param.idx))) | 427 | f(param.name.clone(), ScopeDef::GenericParam(param.idx)) |
367 | } | 428 | } |
368 | } | 429 | } |
369 | Scope::ImplBlockScope(i) => { | 430 | Scope::ImplBlockScope(i) => { |
370 | f(SELF_TYPE, PerNs::types(Resolution::SelfType(*i))); | 431 | f(SELF_TYPE, ScopeDef::SelfType(*i)); |
371 | } | 432 | } |
372 | Scope::ExprScope(e) => { | 433 | Scope::ExprScope(e) => { |
373 | e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { | 434 | e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { |
374 | f(e.name().clone(), PerNs::values(Resolution::LocalBinding(e.pat()))); | 435 | f(e.name().clone(), ScopeDef::LocalBinding(e.pat())); |
375 | }); | 436 | }); |
376 | } | 437 | } |
377 | } | 438 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 65b304b43..cff55b640 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -15,7 +15,7 @@ use ra_syntax::{ | |||
15 | SyntaxKind::*, | 15 | SyntaxKind::*, |
16 | SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, | 16 | SyntaxNode, SyntaxNodePtr, TextRange, TextUnit, |
17 | }; | 17 | }; |
18 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::FxHashSet; |
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | db::HirDatabase, | 21 | db::HirDatabase, |
@@ -27,9 +27,10 @@ use crate::{ | |||
27 | ids::LocationCtx, | 27 | ids::LocationCtx, |
28 | name, | 28 | name, |
29 | path::{PathKind, PathSegment}, | 29 | path::{PathKind, PathSegment}, |
30 | resolve::{ScopeDef, TypeNs, ValueNs}, | ||
30 | ty::method_resolution::implements_trait, | 31 | ty::method_resolution::implements_trait, |
31 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, | 32 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, |
32 | Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, | 33 | Module, Name, Path, Resolver, Static, Struct, Trait, Ty, |
33 | }; | 34 | }; |
34 | 35 | ||
35 | /// Locates the module by `FileId`. Picks topmost module in the file. | 36 | /// Locates the module by `FileId`. Picks topmost module in the file. |
@@ -301,8 +302,41 @@ impl SourceAnalyzer { | |||
301 | &self, | 302 | &self, |
302 | db: &impl HirDatabase, | 303 | db: &impl HirDatabase, |
303 | path: &crate::Path, | 304 | path: &crate::Path, |
304 | ) -> PerNs<crate::Resolution> { | 305 | ) -> Option<PathResolution> { |
305 | self.resolver.resolve_path_without_assoc_items(db, path) | 306 | let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { |
307 | TypeNs::SelfType(it) => PathResolution::SelfType(it), | ||
308 | TypeNs::GenericParam(it) => PathResolution::GenericParam(it), | ||
309 | TypeNs::Adt(it) => PathResolution::Def(it.into()), | ||
310 | TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), | ||
311 | TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), | ||
312 | TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), | ||
313 | TypeNs::Trait(it) => PathResolution::Def(it.into()), | ||
314 | }); | ||
315 | let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| { | ||
316 | let res = match val { | ||
317 | ValueNs::LocalBinding(it) => { | ||
318 | // We get a `PatId` from resolver, but it actually can only | ||
319 | // point at `BindPat`, and not at the arbitrary pattern. | ||
320 | let pat_ptr = self | ||
321 | .body_source_map | ||
322 | .as_ref()? | ||
323 | .pat_syntax(it)? | ||
324 | .ast // FIXME: ignoring file_id here is definitelly wrong | ||
325 | .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); | ||
326 | PathResolution::LocalBinding(pat_ptr) | ||
327 | } | ||
328 | ValueNs::Function(it) => PathResolution::Def(it.into()), | ||
329 | ValueNs::Const(it) => PathResolution::Def(it.into()), | ||
330 | ValueNs::Static(it) => PathResolution::Def(it.into()), | ||
331 | ValueNs::Struct(it) => PathResolution::Def(it.into()), | ||
332 | ValueNs::EnumVariant(it) => PathResolution::Def(it.into()), | ||
333 | }; | ||
334 | Some(res) | ||
335 | }); | ||
336 | |||
337 | let items = | ||
338 | self.resolver.resolve_module_path(db, &path).take_types().map(PathResolution::Def); | ||
339 | types.or(values).or(items) | ||
306 | } | 340 | } |
307 | 341 | ||
308 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { | 342 | pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> { |
@@ -319,25 +353,7 @@ impl SourceAnalyzer { | |||
319 | } | 353 | } |
320 | } | 354 | } |
321 | let hir_path = crate::Path::from_ast(path.clone())?; | 355 | let hir_path = crate::Path::from_ast(path.clone())?; |
322 | let res = self.resolver.resolve_path_without_assoc_items(db, &hir_path); | 356 | self.resolve_hir_path(db, &hir_path) |
323 | let res = res.clone().take_types().or_else(|| res.take_values())?; | ||
324 | let res = match res { | ||
325 | crate::Resolution::Def(it) => PathResolution::Def(it), | ||
326 | crate::Resolution::LocalBinding(it) => { | ||
327 | // We get a `PatId` from resolver, but it actually can only | ||
328 | // point at `BindPat`, and not at the arbitrary pattern. | ||
329 | let pat_ptr = self | ||
330 | .body_source_map | ||
331 | .as_ref()? | ||
332 | .pat_syntax(it)? | ||
333 | .ast // FIXME: ignoring file_id here is definitelly wrong | ||
334 | .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); | ||
335 | PathResolution::LocalBinding(pat_ptr) | ||
336 | } | ||
337 | crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it), | ||
338 | crate::Resolution::SelfType(it) => PathResolution::SelfType(it), | ||
339 | }; | ||
340 | Some(res) | ||
341 | } | 357 | } |
342 | 358 | ||
343 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { | 359 | pub fn resolve_local_name(&self, name_ref: &ast::NameRef) -> Option<ScopeEntryWithSyntax> { |
@@ -360,8 +376,8 @@ impl SourceAnalyzer { | |||
360 | }) | 376 | }) |
361 | } | 377 | } |
362 | 378 | ||
363 | pub fn all_names(&self, db: &impl HirDatabase) -> FxHashMap<Name, PerNs<crate::Resolution>> { | 379 | pub fn process_all_names(&self, db: &impl HirDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { |
364 | self.resolver.all_names(db) | 380 | self.resolver.process_all_names(db, f) |
365 | } | 381 | } |
366 | 382 | ||
367 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { | 383 | pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 540a99b15..3ee083a04 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -45,11 +45,10 @@ use crate::{ | |||
45 | name, | 45 | name, |
46 | nameres::Namespace, | 46 | nameres::Namespace, |
47 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, | 47 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, |
48 | resolve::{Resolution, Resolver}, | 48 | resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial}, |
49 | ty::infer::diagnostics::InferenceDiagnostic, | 49 | ty::infer::diagnostics::InferenceDiagnostic, |
50 | type_ref::{Mutability, TypeRef}, | 50 | type_ref::{Mutability, TypeRef}, |
51 | Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, ModuleDef, Name, Path, | 51 | Adt, ConstData, DefWithBody, FnData, Function, HasBody, ImplItem, Name, Path, StructField, |
52 | StructField, | ||
53 | }; | 52 | }; |
54 | 53 | ||
55 | mod unify; | 54 | mod unify; |
@@ -472,141 +471,138 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
472 | } | 471 | } |
473 | 472 | ||
474 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { | 473 | fn infer_path_expr(&mut self, resolver: &Resolver, path: &Path, id: ExprOrPatId) -> Option<Ty> { |
475 | let resolved = resolver.resolve_path_segments(self.db, &path); | 474 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; |
476 | 475 | ||
477 | let (def, remaining_index) = resolved.into_inner(); | 476 | let (value, self_subst) = match value_or_partial { |
477 | ValueOrPartial::ValueNs(it) => (it, None), | ||
478 | ValueOrPartial::Partial(def, remaining_index) => { | ||
479 | self.resolve_assoc_item(def, path, remaining_index, id)? | ||
480 | } | ||
481 | }; | ||
478 | 482 | ||
479 | log::debug!( | 483 | let typable: TypableDef = match value { |
480 | "path {:?} resolved to {:?} with remaining index {:?}", | 484 | ValueNs::LocalBinding(pat) => { |
481 | path, | 485 | let ty = self.result.type_of_pat.get(pat)?.clone(); |
482 | def, | 486 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); |
483 | remaining_index | 487 | return Some(ty); |
484 | ); | 488 | } |
489 | ValueNs::Function(it) => it.into(), | ||
490 | ValueNs::Const(it) => it.into(), | ||
491 | ValueNs::Static(it) => it.into(), | ||
492 | ValueNs::Struct(it) => it.into(), | ||
493 | ValueNs::EnumVariant(it) => it.into(), | ||
494 | }; | ||
485 | 495 | ||
486 | // if the remaining_index is None, we expect the path | 496 | let mut ty = self.db.type_for_def(typable, Namespace::Values); |
487 | // to be fully resolved, in this case we continue with | 497 | if let Some(self_subst) = self_subst { |
488 | // the default by attempting to `take_values´ from the resolution. | 498 | ty = ty.subst(&self_subst); |
489 | // Otherwise the path was partially resolved, which means | 499 | } |
490 | // we might have resolved into a type for which | ||
491 | // we may find some associated item starting at the | ||
492 | // path.segment pointed to by `remaining_index´ | ||
493 | let mut resolved = | ||
494 | if remaining_index.is_none() { def.take_values()? } else { def.take_types()? }; | ||
495 | 500 | ||
496 | let remaining_index = remaining_index.unwrap_or_else(|| path.segments.len()); | 501 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
497 | let mut actual_def_ty: Option<Ty> = None; | 502 | let ty = ty.subst(&substs); |
503 | let ty = self.insert_type_vars(ty); | ||
504 | let ty = self.normalize_associated_types_in(ty); | ||
505 | Some(ty) | ||
506 | } | ||
507 | |||
508 | fn resolve_assoc_item( | ||
509 | &mut self, | ||
510 | mut def: TypeNs, | ||
511 | path: &Path, | ||
512 | remaining_index: usize, | ||
513 | id: ExprOrPatId, | ||
514 | ) -> Option<(ValueNs, Option<Substs>)> { | ||
515 | assert!(remaining_index < path.segments.len()); | ||
516 | let krate = self.resolver.krate()?; | ||
517 | |||
518 | let mut ty = Ty::Unknown; | ||
498 | 519 | ||
499 | let krate = resolver.krate()?; | ||
500 | // resolve intermediate segments | 520 | // resolve intermediate segments |
501 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | 521 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
502 | let ty = match resolved { | 522 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; |
503 | Resolution::Def(def) => { | 523 | ty = { |
504 | // FIXME resolve associated items from traits as well | 524 | let typable: TypableDef = match def { |
505 | let typable: Option<TypableDef> = def.into(); | 525 | TypeNs::Adt(it) => it.into(), |
506 | let typable = typable?; | 526 | TypeNs::TypeAlias(it) => it.into(), |
507 | 527 | TypeNs::BuiltinType(it) => it.into(), | |
508 | let ty = self.db.type_for_def(typable, Namespace::Types); | 528 | // FIXME associated item of traits, generics, and Self |
509 | 529 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { | |
510 | // For example, this substs will take `Gen::*<u32>*::make` | 530 | return None; |
511 | assert!(remaining_index > 0); | 531 | } |
512 | let substs = Ty::substs_from_path_segment( | 532 | // FIXME: report error here |
513 | self.db, | 533 | TypeNs::EnumVariant(_) => return None, |
514 | &self.resolver, | 534 | }; |
515 | &path.segments[remaining_index + i - 1], | 535 | |
516 | typable, | 536 | let ty = self.db.type_for_def(typable, Namespace::Types); |
517 | ); | 537 | |
518 | 538 | // For example, this substs will take `Gen::*<u32>*::make` | |
519 | ty.subst(&substs) | 539 | assert!(remaining_index > 0); |
520 | } | 540 | let substs = Ty::substs_from_path_segment( |
521 | Resolution::LocalBinding(_) => { | 541 | self.db, |
522 | // can't have a local binding in an associated item path | 542 | &self.resolver, |
523 | return None; | 543 | &path.segments[remaining_index + i - 1], |
524 | } | 544 | typable, |
525 | Resolution::GenericParam(..) => { | 545 | ); |
526 | // FIXME associated item of generic param | 546 | ty.subst(&substs) |
527 | return None; | ||
528 | } | ||
529 | Resolution::SelfType(_) => { | ||
530 | // FIXME associated item of self type | ||
531 | return None; | ||
532 | } | ||
533 | }; | 547 | }; |
548 | if is_last_segment { | ||
549 | break; | ||
550 | } | ||
534 | 551 | ||
535 | // Attempt to find an impl_item for the type which has a name matching | 552 | // Attempt to find an impl_item for the type which has a name matching |
536 | // the current segment | 553 | // the current segment |
537 | log::debug!("looking for path segment: {:?}", segment); | 554 | log::debug!("looking for path segment: {:?}", segment); |
538 | 555 | ||
539 | actual_def_ty = Some(ty.clone()); | 556 | let ty = mem::replace(&mut ty, Ty::Unknown); |
540 | 557 | def = ty.iterate_impl_items(self.db, krate, |item| { | |
541 | let item: crate::ModuleDef = ty.iterate_impl_items(self.db, krate, |item| { | 558 | match item { |
542 | let matching_def: Option<crate::ModuleDef> = match item { | 559 | crate::ImplItem::Method(_) => None, |
543 | crate::ImplItem::Method(func) => { | 560 | crate::ImplItem::Const(_) => None, |
544 | if segment.name == func.name(self.db) { | ||
545 | Some(func.into()) | ||
546 | } else { | ||
547 | None | ||
548 | } | ||
549 | } | ||
550 | |||
551 | crate::ImplItem::Const(konst) => { | ||
552 | let data = konst.data(self.db); | ||
553 | if segment.name == *data.name() { | ||
554 | Some(konst.into()) | ||
555 | } else { | ||
556 | None | ||
557 | } | ||
558 | } | ||
559 | 561 | ||
560 | // FIXME: Resolve associated types | 562 | // FIXME: Resolve associated types |
561 | crate::ImplItem::TypeAlias(_) => None, | 563 | crate::ImplItem::TypeAlias(_) => { |
562 | }; | 564 | // Some(TypeNs::TypeAlias(..)) |
563 | match matching_def { | 565 | None::<TypeNs> |
564 | Some(_) => { | ||
565 | self.write_assoc_resolution(id, item); | ||
566 | matching_def | ||
567 | } | 566 | } |
568 | None => None, | ||
569 | } | 567 | } |
570 | })?; | 568 | })?; |
571 | |||
572 | resolved = Resolution::Def(item); | ||
573 | } | 569 | } |
574 | 570 | ||
575 | match resolved { | 571 | let segment = path.segments.last().unwrap(); |
576 | Resolution::Def(def) => { | 572 | let def = ty.clone().iterate_impl_items(self.db, krate, |item| { |
577 | let typable: Option<TypableDef> = def.into(); | 573 | let matching_def: Option<ValueNs> = match item { |
578 | let typable = typable?; | 574 | crate::ImplItem::Method(func) => { |
579 | let mut ty = self.db.type_for_def(typable, Namespace::Values); | 575 | if segment.name == func.name(self.db) { |
580 | if let Some(sts) = self.find_self_types(&def, actual_def_ty) { | 576 | Some(ValueNs::Function(func)) |
581 | ty = ty.subst(&sts); | 577 | } else { |
578 | None | ||
579 | } | ||
582 | } | 580 | } |
583 | 581 | ||
584 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 582 | crate::ImplItem::Const(konst) => { |
585 | let ty = ty.subst(&substs); | 583 | let data = konst.data(self.db); |
586 | let ty = self.insert_type_vars(ty); | 584 | if segment.name == *data.name() { |
587 | let ty = self.normalize_associated_types_in(ty); | 585 | Some(ValueNs::Const(konst)) |
588 | Some(ty) | 586 | } else { |
589 | } | 587 | None |
590 | Resolution::LocalBinding(pat) => { | 588 | } |
591 | let ty = self.result.type_of_pat.get(pat)?.clone(); | 589 | } |
592 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | 590 | crate::ImplItem::TypeAlias(_) => None, |
593 | Some(ty) | 591 | }; |
594 | } | 592 | match matching_def { |
595 | Resolution::GenericParam(..) => { | 593 | Some(_) => { |
596 | // generic params can't refer to values... yet | 594 | self.write_assoc_resolution(id, item); |
597 | None | 595 | matching_def |
598 | } | 596 | } |
599 | Resolution::SelfType(_) => { | 597 | None => None, |
600 | log::error!("path expr {:?} resolved to Self type in values ns", path); | ||
601 | None | ||
602 | } | 598 | } |
603 | } | 599 | })?; |
600 | let self_types = self.find_self_types(&def, ty); | ||
601 | Some((def, self_types)) | ||
604 | } | 602 | } |
605 | 603 | ||
606 | fn find_self_types(&self, def: &ModuleDef, actual_def_ty: Option<Ty>) -> Option<Substs> { | 604 | fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> { |
607 | let actual_def_ty = actual_def_ty?; | 605 | if let ValueNs::Function(func) = def { |
608 | |||
609 | if let crate::ModuleDef::Function(func) = def { | ||
610 | // We only do the infer if parent has generic params | 606 | // We only do the infer if parent has generic params |
611 | let gen = func.generic_params(self.db); | 607 | let gen = func.generic_params(self.db); |
612 | if gen.count_parent_params() == 0 { | 608 | if gen.count_parent_params() == 0 { |
@@ -641,30 +637,24 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
641 | None => return (Ty::Unknown, None), | 637 | None => return (Ty::Unknown, None), |
642 | }; | 638 | }; |
643 | let resolver = &self.resolver; | 639 | let resolver = &self.resolver; |
644 | let typable: Option<TypableDef> = | 640 | let def: TypableDef = |
645 | // FIXME: this should resolve assoc items as well, see this example: | 641 | // FIXME: this should resolve assoc items as well, see this example: |
646 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 | 642 | // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 |
647 | match resolver.resolve_path_without_assoc_items(self.db, &path).take_types() { | 643 | match resolver.resolve_path_in_type_ns_fully(self.db, &path) { |
648 | Some(Resolution::Def(def)) => def.into(), | 644 | Some(TypeNs::Adt(Adt::Struct(it))) => it.into(), |
649 | Some(Resolution::LocalBinding(..)) => { | 645 | Some(TypeNs::Adt(Adt::Union(it))) => it.into(), |
650 | // this cannot happen | 646 | Some(TypeNs::EnumVariant(it)) => it.into(), |
651 | log::error!("path resolved to local binding in type ns"); | 647 | Some(TypeNs::TypeAlias(it)) => it.into(), |
652 | return (Ty::Unknown, None); | 648 | |
653 | } | 649 | Some(TypeNs::SelfType(_)) | |
654 | Some(Resolution::GenericParam(..)) => { | 650 | Some(TypeNs::GenericParam(_)) | |
655 | // generic params can't be used in struct literals | 651 | Some(TypeNs::BuiltinType(_)) | |
656 | return (Ty::Unknown, None); | 652 | Some(TypeNs::Trait(_)) | |
657 | } | 653 | Some(TypeNs::Adt(Adt::Enum(_))) | |
658 | Some(Resolution::SelfType(..)) => { | 654 | None => { |
659 | // FIXME this is allowed in an impl for a struct, handle this | 655 | return (Ty::Unknown, None) |
660 | return (Ty::Unknown, None); | ||
661 | } | 656 | } |
662 | None => return (Ty::Unknown, None), | ||
663 | }; | 657 | }; |
664 | let def = match typable { | ||
665 | None => return (Ty::Unknown, None), | ||
666 | Some(it) => it, | ||
667 | }; | ||
668 | // FIXME remove the duplication between here and `Ty::from_path`? | 658 | // FIXME remove the duplication between here and `Ty::from_path`? |
669 | let substs = Ty::substs_from_path(self.db, resolver, path, def); | 659 | let substs = Ty::substs_from_path(self.db, resolver, path, def); |
670 | match def { | 660 | match def { |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 946e9e9fb..3fdb2ca92 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | generics::{GenericDef, WherePredicate}, | 19 | generics::{GenericDef, WherePredicate}, |
20 | nameres::Namespace, | 20 | nameres::Namespace, |
21 | path::{GenericArg, PathSegment}, | 21 | path::{GenericArg, PathSegment}, |
22 | resolve::{Resolution, Resolver}, | 22 | resolve::{Resolver, TypeNs}, |
23 | ty::Adt, | 23 | ty::Adt, |
24 | type_ref::{TypeBound, TypeRef}, | 24 | type_ref::{TypeBound, TypeRef}, |
25 | BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, | 25 | BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, |
@@ -88,16 +88,47 @@ impl Ty { | |||
88 | 88 | ||
89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | 89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { |
90 | // Resolve the path (in type namespace) | 90 | // Resolve the path (in type namespace) |
91 | let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner(); | 91 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { |
92 | let resolution = resolution.take_types(); | 92 | Some(it) => it, |
93 | 93 | None => return Ty::Unknown, | |
94 | let def = match resolution { | 94 | }; |
95 | Some(Resolution::Def(def)) => def, | 95 | |
96 | Some(Resolution::LocalBinding(..)) => { | 96 | let typable: TypableDef = match resolution { |
97 | // this should never happen | 97 | TypeNs::Trait(trait_) => { |
98 | panic!("path resolved to local binding in type ns"); | 98 | let segment = match remaining_index { |
99 | None => path.segments.last().expect("resolved path has at least one element"), | ||
100 | Some(i) => &path.segments[i - 1], | ||
101 | }; | ||
102 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | ||
103 | return if let Some(remaining_index) = remaining_index { | ||
104 | if remaining_index == path.segments.len() - 1 { | ||
105 | let segment = &path.segments[remaining_index]; | ||
106 | match trait_ref | ||
107 | .trait_ | ||
108 | .associated_type_by_name_including_super_traits(db, &segment.name) | ||
109 | { | ||
110 | Some(associated_ty) => { | ||
111 | // FIXME handle type parameters on the segment | ||
112 | Ty::Projection(ProjectionTy { | ||
113 | associated_ty, | ||
114 | parameters: trait_ref.substs, | ||
115 | }) | ||
116 | } | ||
117 | None => { | ||
118 | // associated type not found | ||
119 | Ty::Unknown | ||
120 | } | ||
121 | } | ||
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | ||
126 | } else { | ||
127 | // FIXME dyn Trait without the dyn | ||
128 | Ty::Unknown | ||
129 | }; | ||
99 | } | 130 | } |
100 | Some(Resolution::GenericParam(idx)) => { | 131 | TypeNs::GenericParam(idx) => { |
101 | if remaining_index.is_some() { | 132 | if remaining_index.is_some() { |
102 | // e.g. T::Item | 133 | // e.g. T::Item |
103 | return Ty::Unknown; | 134 | return Ty::Unknown; |
@@ -111,57 +142,24 @@ impl Ty { | |||
111 | .clone(), | 142 | .clone(), |
112 | }; | 143 | }; |
113 | } | 144 | } |
114 | Some(Resolution::SelfType(impl_block)) => { | 145 | TypeNs::SelfType(impl_block) => { |
115 | if remaining_index.is_some() { | 146 | if remaining_index.is_some() { |
116 | // e.g. Self::Item | 147 | // e.g. Self::Item |
117 | return Ty::Unknown; | 148 | return Ty::Unknown; |
118 | } | 149 | } |
119 | return impl_block.target_ty(db); | 150 | return impl_block.target_ty(db); |
120 | } | 151 | } |
121 | None => { | 152 | |
122 | // path did not resolve | 153 | TypeNs::Adt(it) => it.into(), |
123 | return Ty::Unknown; | 154 | TypeNs::BuiltinType(it) => it.into(), |
124 | } | 155 | TypeNs::TypeAlias(it) => it.into(), |
156 | // FIXME: report error | ||
157 | TypeNs::EnumVariant(_) => return Ty::Unknown, | ||
125 | }; | 158 | }; |
126 | 159 | ||
127 | if let ModuleDef::Trait(trait_) = def { | 160 | let ty = db.type_for_def(typable, Namespace::Types); |
128 | let segment = match remaining_index { | 161 | let substs = Ty::substs_from_path(db, resolver, path, typable); |
129 | None => path.segments.last().expect("resolved path has at least one element"), | 162 | ty.subst(&substs) |
130 | Some(i) => &path.segments[i - 1], | ||
131 | }; | ||
132 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | ||
133 | if let Some(remaining_index) = remaining_index { | ||
134 | if remaining_index == path.segments.len() - 1 { | ||
135 | let segment = &path.segments[remaining_index]; | ||
136 | let associated_ty = match trait_ref | ||
137 | .trait_ | ||
138 | .associated_type_by_name_including_super_traits(db, &segment.name) | ||
139 | { | ||
140 | Some(t) => t, | ||
141 | None => { | ||
142 | // associated type not found | ||
143 | return Ty::Unknown; | ||
144 | } | ||
145 | }; | ||
146 | // FIXME handle type parameters on the segment | ||
147 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
148 | } else { | ||
149 | // FIXME more than one segment remaining, is this possible? | ||
150 | Ty::Unknown | ||
151 | } | ||
152 | } else { | ||
153 | // FIXME dyn Trait without the dyn | ||
154 | Ty::Unknown | ||
155 | } | ||
156 | } else { | ||
157 | let typable: TypableDef = match def.into() { | ||
158 | None => return Ty::Unknown, | ||
159 | Some(it) => it, | ||
160 | }; | ||
161 | let ty = db.type_for_def(typable, Namespace::Types); | ||
162 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
163 | ty.subst(&substs) | ||
164 | } | ||
165 | } | 163 | } |
166 | 164 | ||
167 | pub(super) fn substs_from_path_segment( | 165 | pub(super) fn substs_from_path_segment( |
@@ -278,8 +276,8 @@ impl TraitRef { | |||
278 | path: &Path, | 276 | path: &Path, |
279 | explicit_self_ty: Option<Ty>, | 277 | explicit_self_ty: Option<Ty>, |
280 | ) -> Option<Self> { | 278 | ) -> Option<Self> { |
281 | let resolved = match resolver.resolve_path_without_assoc_items(db, &path).take_types()? { | 279 | let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { |
282 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 280 | TypeNs::Trait(tr) => tr, |
283 | _ => return None, | 281 | _ => return None, |
284 | }; | 282 | }; |
285 | let segment = path.segments.last().expect("path should have at least one segment"); | 283 | let segment = path.segments.last().expect("path should have at least one segment"); |