aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/auto_import.rs7
-rw-r--r--crates/ra_hir/src/expr/validation.rs14
-rw-r--r--crates/ra_hir/src/nameres.rs12
-rw-r--r--crates/ra_hir/src/path.rs81
-rw-r--r--crates/ra_hir/src/resolve.rs28
-rw-r--r--crates/ra_hir/src/source_binder.rs14
-rw-r--r--crates/ra_hir/src/ty/infer.rs120
-rw-r--r--crates/ra_hir/src/ty/tests.rs58
-rw-r--r--crates/ra_syntax/src/ast/generated.rs3
-rw-r--r--crates/ra_syntax/src/grammar.ron2
10 files changed, 211 insertions, 128 deletions
diff --git a/crates/ra_assists/src/auto_import.rs b/crates/ra_assists/src/auto_import.rs
index 1158adbbc..5ecda1ff5 100644
--- a/crates/ra_assists/src/auto_import.rs
+++ b/crates/ra_assists/src/auto_import.rs
@@ -504,7 +504,7 @@ fn apply_auto_import(
504 } 504 }
505} 505}
506 506
507pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> { 507pub fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
508 let mut ps = Vec::<SmolStr>::with_capacity(10); 508 let mut ps = Vec::<SmolStr>::with_capacity(10);
509 match path.kind { 509 match path.kind {
510 hir::PathKind::Abs => ps.push("".into()), 510 hir::PathKind::Abs => ps.push("".into()),
@@ -512,11 +512,12 @@ pub fn collect_hir_path_segments(path: &hir::Path) -> Vec<SmolStr> {
512 hir::PathKind::Plain => {} 512 hir::PathKind::Plain => {}
513 hir::PathKind::Self_ => ps.push("self".into()), 513 hir::PathKind::Self_ => ps.push("self".into()),
514 hir::PathKind::Super => ps.push("super".into()), 514 hir::PathKind::Super => ps.push("super".into()),
515 hir::PathKind::Type => return None,
515 } 516 }
516 for s in path.segments.iter() { 517 for s in path.segments.iter() {
517 ps.push(s.name.to_string().into()); 518 ps.push(s.name.to_string().into());
518 } 519 }
519 ps 520 Some(ps)
520} 521}
521 522
522// This function produces sequence of text edits into edit 523// This function produces sequence of text edits into edit
@@ -552,7 +553,7 @@ pub(crate) fn auto_import(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist
552 } 553 }
553 554
554 let hir_path = hir::Path::from_ast(path.clone())?; 555 let hir_path = hir::Path::from_ast(path.clone())?;
555 let segments = collect_hir_path_segments(&hir_path); 556 let segments = collect_hir_path_segments(&hir_path)?;
556 if segments.len() < 2 { 557 if segments.len() < 2 {
557 return None; 558 return None;
558 } 559 }
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 @@
1use std::sync::Arc; 1use std::{iter, sync::Arc};
2 2
3use ra_syntax::{ 3use 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)]
11pub struct Path { 11pub 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
55impl Path { 58impl 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
231impl From<Name> for Path { 255impl 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)]
67pub enum ValueOrPartial { 68pub 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
54mod unify; 55mod 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]
285fn infer_path_type() {
286 assert_snapshot!(
287 infer(r#"
288struct S;
289
290impl S {
291 fn foo() -> i32 { 1 }
292}
293
294fn 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]
312fn infer_slice_method() {
313 assert_snapshot!(
314 infer(r#"
315#[lang = "slice"]
316impl<T> [T] {
317 fn foo(&self) -> T {
318 loop {}
319 }
320}
321
322#[lang = "slice_alloc"]
323impl<T> [T] {}
324
325fn 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]
285fn infer_struct() { 343fn infer_struct() {
286 assert_snapshot!( 344 assert_snapshot!(
287 infer(r#" 345 infer(r#"
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 591ac8ca3..dc1f8c82c 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -2385,6 +2385,9 @@ impl PathSegment {
2385 pub fn ret_type(&self) -> Option<RetType> { 2385 pub fn ret_type(&self) -> Option<RetType> {
2386 AstChildren::new(&self.syntax).next() 2386 AstChildren::new(&self.syntax).next()
2387 } 2387 }
2388 pub fn path_type(&self) -> Option<PathType> {
2389 AstChildren::new(&self.syntax).next()
2390 }
2388} 2391}
2389#[derive(Debug, Clone, PartialEq, Eq, Hash)] 2392#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2390pub struct PathType { 2393pub struct PathType {
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 08cc6eeea..da9de2214 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -689,7 +689,7 @@ Grammar(
689 ] 689 ]
690 ), 690 ),
691 "PathSegment": ( 691 "PathSegment": (
692 options: [ "NameRef", "TypeArgList", "ParamList", "RetType" ] 692 options: [ "NameRef", "TypeArgList", "ParamList", "RetType", "PathType" ]
693 ), 693 ),
694 "TypeArgList": (collections: [ 694 "TypeArgList": (collections: [
695 ("type_args", "TypeArg"), 695 ("type_args", "TypeArg"),