diff options
author | uHOOCCOOHu <[email protected]> | 2019-09-11 19:01:07 +0100 |
---|---|---|
committer | uHOOCCOOHu <[email protected]> | 2019-09-15 12:40:32 +0100 |
commit | 4926bed42680d329f906be93450bec6b2ba0e99b (patch) | |
tree | 455c0bc9d839a18fffda6d018bf41d1c58ebfa52 /crates/ra_hir/src/ty | |
parent | 2d79a1ad83cc39075c7c9e3230973013c8c58b17 (diff) |
Support path starting with a type
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 120 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 58 |
2 files changed, 113 insertions, 65 deletions
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#" |