diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/expr/validation.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir/src/resolve.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 120 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 58 |
7 files changed, 203 insertions, 124 deletions
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index 030ec53a2..c675bf8de 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs | |||
@@ -8,7 +8,7 @@ use crate::{ | |||
8 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, | 8 | diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, |
9 | expr::AstPtr, | 9 | expr::AstPtr, |
10 | name, | 10 | name, |
11 | path::{PathKind, PathSegment}, | 11 | path::PathKind, |
12 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, | 12 | ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, |
13 | Adt, Function, Name, Path, | 13 | Adt, Function, Name, Path, |
14 | }; | 14 | }; |
@@ -108,14 +108,10 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
108 | None => return, | 108 | None => return, |
109 | }; | 109 | }; |
110 | 110 | ||
111 | let std_result_path = Path { | 111 | let std_result_path = Path::from_simple_segments( |
112 | kind: PathKind::Abs, | 112 | PathKind::Abs, |
113 | segments: vec![ | 113 | vec![name::STD, name::RESULT_MOD, name::RESULT_TYPE], |
114 | PathSegment { name: name::STD, args_and_bindings: None }, | 114 | ); |
115 | PathSegment { name: name::RESULT_MOD, args_and_bindings: None }, | ||
116 | PathSegment { name: name::RESULT_TYPE, args_and_bindings: None }, | ||
117 | ], | ||
118 | }; | ||
119 | 115 | ||
120 | let resolver = self.func.resolver(db); | 116 | let resolver = self.func.resolver(db); |
121 | let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { | 117 | let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { |
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 7922e3f7e..be1cc76b6 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs | |||
@@ -382,6 +382,11 @@ impl CrateDefMap { | |||
382 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude | 382 | return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude |
383 | } | 383 | } |
384 | } | 384 | } |
385 | PathKind::Type => { | ||
386 | // This is handled in `infer::infer_path_expr` | ||
387 | // The result returned here does not matter | ||
388 | return ResolvePathResult::empty(ReachedFixedPoint::Yes); | ||
389 | } | ||
385 | }; | 390 | }; |
386 | 391 | ||
387 | for (i, segment) in segments { | 392 | for (i, segment) in segments { |
@@ -401,8 +406,11 @@ impl CrateDefMap { | |||
401 | curr_per_ns = match curr { | 406 | curr_per_ns = match curr { |
402 | ModuleDef::Module(module) => { | 407 | ModuleDef::Module(module) => { |
403 | if module.krate != self.krate { | 408 | if module.krate != self.krate { |
404 | let path = | 409 | let path = Path { |
405 | Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; | 410 | segments: path.segments[i..].to_vec(), |
411 | kind: PathKind::Self_, | ||
412 | type_ref: None, | ||
413 | }; | ||
406 | log::debug!("resolving {:?} in other crate", path); | 414 | log::debug!("resolving {:?} in other crate", path); |
407 | let defp_map = db.crate_def_map(module.krate); | 415 | let defp_map = db.crate_def_map(module.krate); |
408 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); | 416 | let (def, s) = defp_map.resolve_path(db, module.module_id, &path); |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index d6c78593b..7c19fda14 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::sync::Arc; | 1 | use std::{iter, sync::Arc}; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, NameOwner, TypeAscriptionOwner}, | 4 | ast::{self, NameOwner, TypeAscriptionOwner}, |
@@ -10,6 +10,7 @@ use crate::{name, type_ref::TypeRef, AsName, Name}; | |||
10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 10 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
11 | pub struct Path { | 11 | pub struct Path { |
12 | pub kind: PathKind, | 12 | pub kind: PathKind, |
13 | pub type_ref: Option<Box<TypeRef>>, | ||
13 | pub segments: Vec<PathSegment>, | 14 | pub segments: Vec<PathSegment>, |
14 | } | 15 | } |
15 | 16 | ||
@@ -50,6 +51,8 @@ pub enum PathKind { | |||
50 | Crate, | 51 | Crate, |
51 | // Absolute path | 52 | // Absolute path |
52 | Abs, | 53 | Abs, |
54 | // Type based path like `<T>::foo` | ||
55 | Type, | ||
53 | } | 56 | } |
54 | 57 | ||
55 | impl Path { | 58 | impl Path { |
@@ -63,10 +66,22 @@ impl Path { | |||
63 | } | 66 | } |
64 | } | 67 | } |
65 | 68 | ||
69 | pub fn from_simple_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> Path { | ||
70 | Path { | ||
71 | kind, | ||
72 | type_ref: None, | ||
73 | segments: segments | ||
74 | .into_iter() | ||
75 | .map(|name| PathSegment { name, args_and_bindings: None }) | ||
76 | .collect(), | ||
77 | } | ||
78 | } | ||
79 | |||
66 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 80 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
67 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { | 81 | pub fn from_ast(mut path: ast::Path) -> Option<Path> { |
68 | let mut kind = PathKind::Plain; | 82 | let mut kind = PathKind::Plain; |
69 | let mut segments = Vec::new(); | 83 | let mut segments = Vec::new(); |
84 | let mut path_type_ref = None; | ||
70 | loop { | 85 | loop { |
71 | let segment = path.segment()?; | 86 | let segment = path.segment()?; |
72 | 87 | ||
@@ -92,24 +107,33 @@ impl Path { | |||
92 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | 107 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { |
93 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | 108 | assert!(path.qualifier().is_none()); // this can only occur at the first segment |
94 | 109 | ||
95 | // FIXME: handle <T> syntax (type segments without trait) | ||
96 | |||
97 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
98 | let path = Path::from_ast(trait_ref?.path()?)?; | ||
99 | kind = path.kind; | ||
100 | let mut prefix_segments = path.segments; | ||
101 | prefix_segments.reverse(); | ||
102 | segments.extend(prefix_segments); | ||
103 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
104 | let self_type = TypeRef::from_ast(type_ref?); | 110 | let self_type = TypeRef::from_ast(type_ref?); |
105 | let mut last_segment = segments.last_mut()?; | 111 | |
106 | if last_segment.args_and_bindings.is_none() { | 112 | match trait_ref { |
107 | last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); | 113 | // <T>::foo |
108 | }; | 114 | None => { |
109 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | 115 | kind = PathKind::Type; |
110 | let mut args_inner = Arc::make_mut(args); | 116 | path_type_ref = Some(Box::new(self_type)); |
111 | args_inner.has_self_type = true; | 117 | } |
112 | args_inner.args.insert(0, GenericArg::Type(self_type)); | 118 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo |
119 | Some(trait_ref) => { | ||
120 | let path = Path::from_ast(trait_ref.path()?)?; | ||
121 | kind = path.kind; | ||
122 | let mut prefix_segments = path.segments; | ||
123 | prefix_segments.reverse(); | ||
124 | segments.extend(prefix_segments); | ||
125 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
126 | let mut last_segment = segments.last_mut()?; | ||
127 | if last_segment.args_and_bindings.is_none() { | ||
128 | last_segment.args_and_bindings = | ||
129 | Some(Arc::new(GenericArgs::empty())); | ||
130 | }; | ||
131 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
132 | let mut args_inner = Arc::make_mut(args); | ||
133 | args_inner.has_self_type = true; | ||
134 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
135 | } | ||
136 | } | ||
113 | } | 137 | } |
114 | ast::PathSegmentKind::CrateKw => { | 138 | ast::PathSegmentKind::CrateKw => { |
115 | kind = PathKind::Crate; | 139 | kind = PathKind::Crate; |
@@ -130,7 +154,7 @@ impl Path { | |||
130 | }; | 154 | }; |
131 | } | 155 | } |
132 | segments.reverse(); | 156 | segments.reverse(); |
133 | return Some(Path { kind, segments }); | 157 | return Some(Path { kind, type_ref: path_type_ref, segments }); |
134 | 158 | ||
135 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { | 159 | fn qualifier(path: &ast::Path) -> Option<ast::Path> { |
136 | if let Some(q) = path.qualifier() { | 160 | if let Some(q) = path.qualifier() { |
@@ -230,10 +254,7 @@ impl GenericArgs { | |||
230 | 254 | ||
231 | impl From<Name> for Path { | 255 | impl From<Name> for Path { |
232 | fn from(name: Name) -> Path { | 256 | fn from(name: Name) -> Path { |
233 | Path { | 257 | Path::from_simple_segments(PathKind::Plain, iter::once(name)) |
234 | kind: PathKind::Plain, | ||
235 | segments: vec![PathSegment { name, args_and_bindings: None }], | ||
236 | } | ||
237 | } | 258 | } |
238 | } | 259 | } |
239 | 260 | ||
@@ -287,8 +308,12 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
287 | let segment = path.segment()?; | 308 | let segment = path.segment()?; |
288 | let res = match segment.kind()? { | 309 | let res = match segment.kind()? { |
289 | ast::PathSegmentKind::Name(name) => { | 310 | ast::PathSegmentKind::Name(name) => { |
290 | let mut res = prefix | 311 | // no type args in use |
291 | .unwrap_or_else(|| Path { kind: PathKind::Plain, segments: Vec::with_capacity(1) }); | 312 | let mut res = prefix.unwrap_or_else(|| Path { |
313 | kind: PathKind::Plain, | ||
314 | type_ref: None, | ||
315 | segments: Vec::with_capacity(1), | ||
316 | }); | ||
292 | res.segments.push(PathSegment { | 317 | res.segments.push(PathSegment { |
293 | name: name.as_name(), | 318 | name: name.as_name(), |
294 | args_and_bindings: None, // no type args in use | 319 | args_and_bindings: None, // no type args in use |
@@ -299,19 +324,19 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
299 | if prefix.is_some() { | 324 | if prefix.is_some() { |
300 | return None; | 325 | return None; |
301 | } | 326 | } |
302 | Path { kind: PathKind::Crate, segments: Vec::new() } | 327 | Path::from_simple_segments(PathKind::Crate, iter::empty()) |
303 | } | 328 | } |
304 | ast::PathSegmentKind::SelfKw => { | 329 | ast::PathSegmentKind::SelfKw => { |
305 | if prefix.is_some() { | 330 | if prefix.is_some() { |
306 | return None; | 331 | return None; |
307 | } | 332 | } |
308 | Path { kind: PathKind::Self_, segments: Vec::new() } | 333 | Path::from_simple_segments(PathKind::Self_, iter::empty()) |
309 | } | 334 | } |
310 | ast::PathSegmentKind::SuperKw => { | 335 | ast::PathSegmentKind::SuperKw => { |
311 | if prefix.is_some() { | 336 | if prefix.is_some() { |
312 | return None; | 337 | return None; |
313 | } | 338 | } |
314 | Path { kind: PathKind::Super, segments: Vec::new() } | 339 | Path::from_simple_segments(PathKind::Super, iter::empty()) |
315 | } | 340 | } |
316 | ast::PathSegmentKind::Type { .. } => { | 341 | ast::PathSegmentKind::Type { .. } => { |
317 | // not allowed in imports | 342 | // not allowed in imports |
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 3207b6626..e357c74e3 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs | |||
@@ -15,6 +15,7 @@ use crate::{ | |||
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, PathKind}, | 17 | path::{Path, PathKind}, |
18 | type_ref::TypeRef, | ||
18 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, | 19 | Adt, BuiltinType, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, |
19 | Trait, TypeAlias, | 20 | Trait, TypeAlias, |
20 | }; | 21 | }; |
@@ -64,9 +65,10 @@ pub enum TypeNs { | |||
64 | } | 65 | } |
65 | 66 | ||
66 | #[derive(Debug)] | 67 | #[derive(Debug)] |
67 | pub enum ValueOrPartial { | 68 | pub enum ResolveValueResult<'a> { |
68 | ValueNs(ValueNs), | 69 | ValueNs(ValueNs), |
69 | Partial(TypeNs, usize), | 70 | Partial(TypeNs, usize), |
71 | TypeRef(&'a TypeRef), | ||
70 | } | 72 | } |
71 | 73 | ||
72 | #[derive(Debug)] | 74 | #[derive(Debug)] |
@@ -183,11 +185,15 @@ impl Resolver { | |||
183 | Some(res) | 185 | Some(res) |
184 | } | 186 | } |
185 | 187 | ||
186 | pub(crate) fn resolve_path_in_value_ns( | 188 | pub(crate) fn resolve_path_in_value_ns<'p>( |
187 | &self, | 189 | &self, |
188 | db: &impl HirDatabase, | 190 | db: &impl HirDatabase, |
189 | path: &Path, | 191 | path: &'p Path, |
190 | ) -> Option<ValueOrPartial> { | 192 | ) -> Option<ResolveValueResult<'p>> { |
193 | if let Some(type_ref) = &path.type_ref { | ||
194 | return Some(ResolveValueResult::TypeRef(type_ref)); | ||
195 | } | ||
196 | |||
191 | let n_segments = path.segments.len(); | 197 | let n_segments = path.segments.len(); |
192 | let tmp = SELF_PARAM; | 198 | let tmp = SELF_PARAM; |
193 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; | 199 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; |
@@ -208,7 +214,7 @@ impl Resolver { | |||
208 | .find(|entry| entry.name() == first_name); | 214 | .find(|entry| entry.name() == first_name); |
209 | 215 | ||
210 | if let Some(e) = entry { | 216 | if let Some(e) = entry { |
211 | return Some(ValueOrPartial::ValueNs(ValueNs::LocalBinding(e.pat()))); | 217 | return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); |
212 | } | 218 | } |
213 | } | 219 | } |
214 | Scope::ExprScope(_) => continue, | 220 | Scope::ExprScope(_) => continue, |
@@ -216,7 +222,7 @@ impl Resolver { | |||
216 | Scope::GenericParams(params) if n_segments > 1 => { | 222 | Scope::GenericParams(params) if n_segments > 1 => { |
217 | if let Some(param) = params.find_by_name(first_name) { | 223 | if let Some(param) = params.find_by_name(first_name) { |
218 | let ty = TypeNs::GenericParam(param.idx); | 224 | let ty = TypeNs::GenericParam(param.idx); |
219 | return Some(ValueOrPartial::Partial(ty, 1)); | 225 | return Some(ResolveValueResult::Partial(ty, 1)); |
220 | } | 226 | } |
221 | } | 227 | } |
222 | Scope::GenericParams(_) => continue, | 228 | Scope::GenericParams(_) => continue, |
@@ -224,7 +230,7 @@ impl Resolver { | |||
224 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { | 230 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { |
225 | if first_name == &SELF_TYPE { | 231 | if first_name == &SELF_TYPE { |
226 | let ty = TypeNs::SelfType(*impl_); | 232 | let ty = TypeNs::SelfType(*impl_); |
227 | return Some(ValueOrPartial::Partial(ty, 1)); | 233 | return Some(ResolveValueResult::Partial(ty, 1)); |
228 | } | 234 | } |
229 | } | 235 | } |
230 | Scope::ImplBlockScope(_) => continue, | 236 | Scope::ImplBlockScope(_) => continue, |
@@ -247,7 +253,7 @@ impl Resolver { | |||
247 | | ModuleDef::BuiltinType(_) | 253 | | ModuleDef::BuiltinType(_) |
248 | | ModuleDef::Module(_) => return None, | 254 | | ModuleDef::Module(_) => return None, |
249 | }; | 255 | }; |
250 | Some(ValueOrPartial::ValueNs(value)) | 256 | Some(ResolveValueResult::ValueNs(value)) |
251 | } | 257 | } |
252 | Some(idx) => { | 258 | Some(idx) => { |
253 | let ty = match module_def.take_types()? { | 259 | let ty = match module_def.take_types()? { |
@@ -262,7 +268,7 @@ impl Resolver { | |||
262 | | ModuleDef::Const(_) | 268 | | ModuleDef::Const(_) |
263 | | ModuleDef::Static(_) => return None, | 269 | | ModuleDef::Static(_) => return None, |
264 | }; | 270 | }; |
265 | Some(ValueOrPartial::Partial(ty, idx)) | 271 | Some(ResolveValueResult::Partial(ty, idx)) |
266 | } | 272 | } |
267 | }; | 273 | }; |
268 | } | 274 | } |
@@ -277,8 +283,8 @@ impl Resolver { | |||
277 | path: &Path, | 283 | path: &Path, |
278 | ) -> Option<ValueNs> { | 284 | ) -> Option<ValueNs> { |
279 | match self.resolve_path_in_value_ns(db, path)? { | 285 | match self.resolve_path_in_value_ns(db, path)? { |
280 | ValueOrPartial::ValueNs(it) => Some(it), | 286 | ResolveValueResult::ValueNs(it) => Some(it), |
281 | ValueOrPartial::Partial(..) => None, | 287 | ResolveValueResult::Partial(..) | ResolveValueResult::TypeRef(_) => None, |
282 | } | 288 | } |
283 | } | 289 | } |
284 | 290 | ||
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index cff55b640..59053cda3 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -26,7 +26,7 @@ use crate::{ | |||
26 | }, | 26 | }, |
27 | ids::LocationCtx, | 27 | ids::LocationCtx, |
28 | name, | 28 | name, |
29 | path::{PathKind, PathSegment}, | 29 | path::PathKind, |
30 | resolve::{ScopeDef, TypeNs, ValueNs}, | 30 | resolve::{ScopeDef, TypeNs, ValueNs}, |
31 | ty::method_resolution::implements_trait, | 31 | ty::method_resolution::implements_trait, |
32 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, | 32 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HasBody, HirFileId, MacroDef, |
@@ -433,14 +433,10 @@ impl SourceAnalyzer { | |||
433 | /// Checks that particular type `ty` implements `std::future::Future`. | 433 | /// Checks that particular type `ty` implements `std::future::Future`. |
434 | /// This function is used in `.await` syntax completion. | 434 | /// This function is used in `.await` syntax completion. |
435 | pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { | 435 | pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { |
436 | let std_future_path = Path { | 436 | let std_future_path = Path::from_simple_segments( |
437 | kind: PathKind::Abs, | 437 | PathKind::Abs, |
438 | segments: vec![ | 438 | vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], |
439 | PathSegment { name: name::STD, args_and_bindings: None }, | 439 | ); |
440 | PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, | ||
441 | PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, | ||
442 | ], | ||
443 | }; | ||
444 | 440 | ||
445 | let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { | 441 | let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { |
446 | Some(it) => it, | 442 | Some(it) => it, |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index bf57bb3b7..3981de829 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -44,11 +44,12 @@ use crate::{ | |||
44 | generics::{GenericParams, HasGenericParams}, | 44 | generics::{GenericParams, HasGenericParams}, |
45 | name, | 45 | name, |
46 | nameres::Namespace, | 46 | nameres::Namespace, |
47 | path::{GenericArg, GenericArgs, PathKind, PathSegment}, | 47 | path::{GenericArg, GenericArgs, PathKind}, |
48 | resolve::{Resolver, TypeNs, ValueNs, ValueOrPartial}, | 48 | resolve::{ResolveValueResult, Resolver, TypeNs, ValueNs}, |
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, Name, Path, StructField, | 51 | Adt, ConstData, DefWithBody, Either, FnData, Function, HasBody, ImplItem, Name, Path, |
52 | StructField, | ||
52 | }; | 53 | }; |
53 | 54 | ||
54 | mod unify; | 55 | mod unify; |
@@ -470,9 +471,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
470 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; | 471 | let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; |
471 | 472 | ||
472 | let (value, self_subst) = match value_or_partial { | 473 | let (value, self_subst) = match value_or_partial { |
473 | ValueOrPartial::ValueNs(it) => (it, None), | 474 | ResolveValueResult::ValueNs(it) => (it, None), |
474 | ValueOrPartial::Partial(def, remaining_index) => { | 475 | ResolveValueResult::Partial(def, remaining_index) => { |
475 | self.resolve_assoc_item(def, path, remaining_index, id)? | 476 | self.resolve_assoc_item(Either::A(def), path, remaining_index, id)? |
477 | } | ||
478 | ResolveValueResult::TypeRef(type_ref) => { | ||
479 | let ty = self.make_ty(type_ref); | ||
480 | self.resolve_assoc_item(Either::B(ty), path, 0, id)? | ||
476 | } | 481 | } |
477 | }; | 482 | }; |
478 | 483 | ||
@@ -503,7 +508,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
503 | 508 | ||
504 | fn resolve_assoc_item( | 509 | fn resolve_assoc_item( |
505 | &mut self, | 510 | &mut self, |
506 | mut def: TypeNs, | 511 | mut def_or_ty: Either<TypeNs, Ty>, |
507 | path: &Path, | 512 | path: &Path, |
508 | remaining_index: usize, | 513 | remaining_index: usize, |
509 | id: ExprOrPatId, | 514 | id: ExprOrPatId, |
@@ -516,30 +521,33 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
516 | // resolve intermediate segments | 521 | // resolve intermediate segments |
517 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { | 522 | for (i, segment) in path.segments[remaining_index..].iter().enumerate() { |
518 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; | 523 | let is_last_segment = i == path.segments[remaining_index..].len() - 1; |
519 | ty = { | 524 | ty = match def_or_ty { |
520 | let typable: TypableDef = match def { | 525 | Either::A(def) => { |
521 | TypeNs::Adt(it) => it.into(), | 526 | let typable: TypableDef = match def { |
522 | TypeNs::TypeAlias(it) => it.into(), | 527 | TypeNs::Adt(it) => it.into(), |
523 | TypeNs::BuiltinType(it) => it.into(), | 528 | TypeNs::TypeAlias(it) => it.into(), |
524 | // FIXME associated item of traits, generics, and Self | 529 | TypeNs::BuiltinType(it) => it.into(), |
525 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { | 530 | // FIXME associated item of traits, generics, and Self |
526 | return None; | 531 | TypeNs::Trait(_) | TypeNs::GenericParam(_) | TypeNs::SelfType(_) => { |
527 | } | 532 | return None; |
528 | // FIXME: report error here | 533 | } |
529 | TypeNs::EnumVariant(_) => return None, | 534 | // FIXME: report error here |
530 | }; | 535 | TypeNs::EnumVariant(_) => return None, |
531 | 536 | }; | |
532 | let ty = self.db.type_for_def(typable, Namespace::Types); | ||
533 | 537 | ||
534 | // For example, this substs will take `Gen::*<u32>*::make` | 538 | let ty = self.db.type_for_def(typable, Namespace::Types); |
535 | assert!(remaining_index > 0); | 539 | |
536 | let substs = Ty::substs_from_path_segment( | 540 | // For example, this substs will take `Gen::*<u32>*::make` |
537 | self.db, | 541 | assert!(remaining_index > 0); |
538 | &self.resolver, | 542 | let substs = Ty::substs_from_path_segment( |
539 | &path.segments[remaining_index + i - 1], | 543 | self.db, |
540 | typable, | 544 | &self.resolver, |
541 | ); | 545 | &path.segments[remaining_index + i - 1], |
542 | ty.subst(&substs) | 546 | typable, |
547 | ); | ||
548 | ty.subst(&substs) | ||
549 | } | ||
550 | Either::B(ty) => ty, | ||
543 | }; | 551 | }; |
544 | if is_last_segment { | 552 | if is_last_segment { |
545 | break; | 553 | break; |
@@ -550,15 +558,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
550 | log::debug!("looking for path segment: {:?}", segment); | 558 | log::debug!("looking for path segment: {:?}", segment); |
551 | 559 | ||
552 | let ty = mem::replace(&mut ty, Ty::Unknown); | 560 | let ty = mem::replace(&mut ty, Ty::Unknown); |
553 | def = ty.iterate_impl_items(self.db, krate, |item| { | 561 | def_or_ty = ty.iterate_impl_items(self.db, krate, |item| { |
554 | match item { | 562 | match item { |
555 | crate::ImplItem::Method(_) => None, | 563 | crate::ImplItem::Method(_) => None, |
556 | crate::ImplItem::Const(_) => None, | 564 | crate::ImplItem::Const(_) => None, |
557 | 565 | ||
558 | // FIXME: Resolve associated types | 566 | // FIXME: Resolve associated types |
559 | crate::ImplItem::TypeAlias(_) => { | 567 | crate::ImplItem::TypeAlias(_) => { |
560 | // Some(TypeNs::TypeAlias(..)) | 568 | // Some(Either::A(TypeNs::TypeAlias(..))) |
561 | None::<TypeNs> | 569 | None |
562 | } | 570 | } |
563 | } | 571 | } |
564 | })?; | 572 | })?; |
@@ -1434,56 +1442,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1434 | } | 1442 | } |
1435 | 1443 | ||
1436 | fn resolve_into_iter_item(&self) -> Option<TypeAlias> { | 1444 | fn resolve_into_iter_item(&self) -> Option<TypeAlias> { |
1437 | let into_iter_path = Path { | 1445 | let into_iter_path = Path::from_simple_segments( |
1438 | kind: PathKind::Abs, | 1446 | PathKind::Abs, |
1439 | segments: vec![ | 1447 | vec![name::STD, name::ITER, name::INTO_ITERATOR], |
1440 | PathSegment { name: name::STD, args_and_bindings: None }, | 1448 | ); |
1441 | PathSegment { name: name::ITER, args_and_bindings: None }, | ||
1442 | PathSegment { name: name::INTO_ITERATOR, args_and_bindings: None }, | ||
1443 | ], | ||
1444 | }; | ||
1445 | 1449 | ||
1446 | let trait_ = self.resolver.resolve_known_trait(self.db, &into_iter_path)?; | 1450 | let trait_ = self.resolver.resolve_known_trait(self.db, &into_iter_path)?; |
1447 | trait_.associated_type_by_name(self.db, &name::ITEM) | 1451 | trait_.associated_type_by_name(self.db, &name::ITEM) |
1448 | } | 1452 | } |
1449 | 1453 | ||
1450 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { | 1454 | fn resolve_ops_try_ok(&self) -> Option<TypeAlias> { |
1451 | let ops_try_path = Path { | 1455 | let ops_try_path = |
1452 | kind: PathKind::Abs, | 1456 | Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY]); |
1453 | segments: vec![ | ||
1454 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
1455 | PathSegment { name: name::OPS, args_and_bindings: None }, | ||
1456 | PathSegment { name: name::TRY, args_and_bindings: None }, | ||
1457 | ], | ||
1458 | }; | ||
1459 | 1457 | ||
1460 | let trait_ = self.resolver.resolve_known_trait(self.db, &ops_try_path)?; | 1458 | let trait_ = self.resolver.resolve_known_trait(self.db, &ops_try_path)?; |
1461 | trait_.associated_type_by_name(self.db, &name::OK) | 1459 | trait_.associated_type_by_name(self.db, &name::OK) |
1462 | } | 1460 | } |
1463 | 1461 | ||
1464 | fn resolve_future_future_output(&self) -> Option<TypeAlias> { | 1462 | fn resolve_future_future_output(&self) -> Option<TypeAlias> { |
1465 | let future_future_path = Path { | 1463 | let future_future_path = Path::from_simple_segments( |
1466 | kind: PathKind::Abs, | 1464 | PathKind::Abs, |
1467 | segments: vec![ | 1465 | vec![name::STD, name::FUTURE_MOD, name::FUTURE_TYPE], |
1468 | PathSegment { name: name::STD, args_and_bindings: None }, | 1466 | ); |
1469 | PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, | ||
1470 | PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, | ||
1471 | ], | ||
1472 | }; | ||
1473 | 1467 | ||
1474 | let trait_ = self.resolver.resolve_known_trait(self.db, &future_future_path)?; | 1468 | let trait_ = self.resolver.resolve_known_trait(self.db, &future_future_path)?; |
1475 | trait_.associated_type_by_name(self.db, &name::OUTPUT) | 1469 | trait_.associated_type_by_name(self.db, &name::OUTPUT) |
1476 | } | 1470 | } |
1477 | 1471 | ||
1478 | fn resolve_boxed_box(&self) -> Option<Adt> { | 1472 | fn resolve_boxed_box(&self) -> Option<Adt> { |
1479 | let boxed_box_path = Path { | 1473 | let boxed_box_path = Path::from_simple_segments( |
1480 | kind: PathKind::Abs, | 1474 | PathKind::Abs, |
1481 | segments: vec![ | 1475 | vec![name::STD, name::BOXED_MOD, name::BOX_TYPE], |
1482 | PathSegment { name: name::STD, args_and_bindings: None }, | 1476 | ); |
1483 | PathSegment { name: name::BOXED_MOD, args_and_bindings: None }, | ||
1484 | PathSegment { name: name::BOX_TYPE, args_and_bindings: None }, | ||
1485 | ], | ||
1486 | }; | ||
1487 | let struct_ = self.resolver.resolve_known_struct(self.db, &boxed_box_path)?; | 1477 | let struct_ = self.resolver.resolve_known_struct(self.db, &boxed_box_path)?; |
1488 | Some(Adt::Struct(struct_)) | 1478 | Some(Adt::Struct(struct_)) |
1489 | } | 1479 | } |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f6a2a658f..1bd677cab 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -282,6 +282,64 @@ fn test() { | |||
282 | } | 282 | } |
283 | 283 | ||
284 | #[test] | 284 | #[test] |
285 | fn infer_path_type() { | ||
286 | assert_snapshot!( | ||
287 | infer(r#" | ||
288 | struct S; | ||
289 | |||
290 | impl S { | ||
291 | fn foo() -> i32 { 1 } | ||
292 | } | ||
293 | |||
294 | fn test() { | ||
295 | S::foo(); | ||
296 | <S>::foo(); | ||
297 | } | ||
298 | "#), | ||
299 | @r###" | ||
300 | [41; 46) '{ 1 }': i32 | ||
301 | [43; 44) '1': i32 | ||
302 | [60; 93) '{ ...o(); }': () | ||
303 | [66; 72) 'S::foo': fn foo() -> i32 | ||
304 | [66; 74) 'S::foo()': i32 | ||
305 | [80; 88) '<S>::foo': fn foo() -> i32 | ||
306 | [80; 90) '<S>::foo()': i32 | ||
307 | "### | ||
308 | ); | ||
309 | } | ||
310 | |||
311 | #[test] | ||
312 | fn infer_slice_method() { | ||
313 | assert_snapshot!( | ||
314 | infer(r#" | ||
315 | #[lang = "slice"] | ||
316 | impl<T> [T] { | ||
317 | fn foo(&self) -> T { | ||
318 | loop {} | ||
319 | } | ||
320 | } | ||
321 | |||
322 | #[lang = "slice_alloc"] | ||
323 | impl<T> [T] {} | ||
324 | |||
325 | fn test() { | ||
326 | <[_]>::foo(b"foo"); | ||
327 | } | ||
328 | "#), | ||
329 | @r###" | ||
330 | [45; 49) 'self': &[T] | ||
331 | [56; 79) '{ ... }': ! | ||
332 | [66; 73) 'loop {}': ! | ||
333 | [71; 73) '{}': () | ||
334 | [133; 160) '{ ...o"); }': () | ||
335 | [139; 149) '<[_]>::foo': fn foo<u8>(&[T]) -> T | ||
336 | [139; 157) '<[_]>:..."foo")': u8 | ||
337 | [150; 156) 'b"foo"': &[u8] | ||
338 | "### | ||
339 | ); | ||
340 | } | ||
341 | |||
342 | #[test] | ||
285 | fn infer_struct() { | 343 | fn infer_struct() { |
286 | assert_snapshot!( | 344 | assert_snapshot!( |
287 | infer(r#" | 345 | infer(r#" |