aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/infer.rs5
-rw-r--r--crates/ra_hir_ty/src/lib.rs15
-rw-r--r--crates/ra_hir_ty/src/lower.rs137
-rw-r--r--crates/ra_hir_ty/src/tests.rs59
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs103
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs29
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs32
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs68
-rw-r--r--crates/ra_hir_ty/src/utils.rs48
9 files changed, 424 insertions, 72 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 6a53be621..bd4ef69a0 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -667,7 +667,7 @@ impl Expectation {
667} 667}
668 668
669mod diagnostics { 669mod diagnostics {
670 use hir_def::{expr::ExprId, src::HasSource, FunctionId, Lookup}; 670 use hir_def::{expr::ExprId, FunctionId};
671 use hir_expand::diagnostics::DiagnosticSink; 671 use hir_expand::diagnostics::DiagnosticSink;
672 672
673 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 673 use crate::{db::HirDatabase, diagnostics::NoSuchField};
@@ -686,10 +686,9 @@ mod diagnostics {
686 ) { 686 ) {
687 match self { 687 match self {
688 InferenceDiagnostic::NoSuchField { expr, field } => { 688 InferenceDiagnostic::NoSuchField { expr, field } => {
689 let source = owner.lookup(db.upcast()).source(db.upcast());
690 let (_, source_map) = db.body_with_source_map(owner.into()); 689 let (_, source_map) = db.body_with_source_map(owner.into());
691 let field = source_map.field_syntax(*expr, *field); 690 let field = source_map.field_syntax(*expr, *field);
692 sink.push(NoSuchField { file: source.file_id, field: field.value }) 691 sink.push(NoSuchField { file: field.file_id, field: field.value })
693 } 692 }
694 } 693 }
695 } 694 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 279c06d65..a6f56c661 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -66,7 +66,8 @@ pub use autoderef::autoderef;
66pub use infer::{InferTy, InferenceResult}; 66pub use infer::{InferTy, InferenceResult};
67pub use lower::CallableDef; 67pub use lower::CallableDef;
68pub use lower::{ 68pub use lower::{
69 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId, 69 associated_type_shorthand_candidates, callable_item_sig, ImplTraitLoweringMode, TyDefId,
70 TyLoweringContext, ValueTyDefId,
70}; 71};
71pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 72pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
72 73
@@ -487,6 +488,18 @@ impl<T> Binders<T> {
487 pub fn new(num_binders: usize, value: T) -> Self { 488 pub fn new(num_binders: usize, value: T) -> Self {
488 Self { num_binders, value } 489 Self { num_binders, value }
489 } 490 }
491
492 pub fn as_ref(&self) -> Binders<&T> {
493 Binders { num_binders: self.num_binders, value: &self.value }
494 }
495
496 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
497 Binders { num_binders: self.num_binders, value: f(self.value) }
498 }
499
500 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
501 Some(Binders { num_binders: self.num_binders, value: f(self.value)? })
502 }
490} 503}
491 504
492impl<T: Clone> Binders<&T> { 505impl<T: Clone> Binders<&T> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index b57214296..9ad6dbe07 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -17,9 +17,9 @@ use hir_def::{
17 path::{GenericArg, Path, PathSegment, PathSegments}, 17 path::{GenericArg, Path, PathSegment, PathSegments},
18 resolver::{HasResolver, Resolver, TypeNs}, 18 resolver::{HasResolver, Resolver, TypeNs},
19 type_ref::{TypeBound, TypeRef}, 19 type_ref::{TypeBound, TypeRef},
20 AdtId, AssocContainerId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, 20 AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId,
21 ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId, 21 HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
22 VariantId, 22 UnionId, VariantId,
23}; 23};
24use ra_arena::map::ArenaMap; 24use ra_arena::map::ArenaMap;
25use ra_db::CrateId; 25use ra_db::CrateId;
@@ -28,12 +28,13 @@ use crate::{
28 db::HirDatabase, 28 db::HirDatabase,
29 primitive::{FloatTy, IntTy}, 29 primitive::{FloatTy, IntTy},
30 utils::{ 30 utils::{
31 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, 31 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
32 variant_data, 32 make_mut_slice, variant_data,
33 }, 33 },
34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, 34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
36}; 36};
37use hir_expand::name::Name;
37 38
38#[derive(Debug)] 39#[derive(Debug)]
39pub struct TyLoweringContext<'a> { 40pub struct TyLoweringContext<'a> {
@@ -256,7 +257,7 @@ impl Ty {
256 if remaining_segments.len() == 1 { 257 if remaining_segments.len() == 1 {
257 // resolve unselected assoc types 258 // resolve unselected assoc types
258 let segment = remaining_segments.first().unwrap(); 259 let segment = remaining_segments.first().unwrap();
259 (Ty::select_associated_type(ctx, ty, res, segment), None) 260 (Ty::select_associated_type(ctx, res, segment), None)
260 } else if remaining_segments.len() > 1 { 261 } else if remaining_segments.len() > 1 {
261 // FIXME report error (ambiguous associated type) 262 // FIXME report error (ambiguous associated type)
262 (Ty::Unknown, None) 263 (Ty::Unknown, None)
@@ -380,48 +381,41 @@ impl Ty {
380 381
381 fn select_associated_type( 382 fn select_associated_type(
382 ctx: &TyLoweringContext<'_>, 383 ctx: &TyLoweringContext<'_>,
383 self_ty: Ty,
384 res: Option<TypeNs>, 384 res: Option<TypeNs>,
385 segment: PathSegment<'_>, 385 segment: PathSegment<'_>,
386 ) -> Ty { 386 ) -> Ty {
387 let traits_from_env: Vec<_> = match res { 387 if let Some(res) = res {
388 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { 388 let ty =
389 None => return Ty::Unknown, 389 associated_type_shorthand_candidates(ctx.db, res, move |name, t, associated_ty| {
390 Some(trait_ref) => vec![trait_ref.value.trait_], 390 if name == segment.name {
391 }, 391 let substs = match ctx.type_param_mode {
392 Some(TypeNs::GenericParam(param_id)) => { 392 TypeParamLoweringMode::Placeholder => {
393 let predicates = ctx.db.generic_predicates_for_param(param_id); 393 // if we're lowering to placeholders, we have to put
394 let mut traits_: Vec<_> = predicates 394 // them in now
395 .iter() 395 let s = Substs::type_params(
396 .filter_map(|pred| match &pred.value { 396 ctx.db,
397 GenericPredicate::Implemented(tr) => Some(tr.trait_), 397 ctx.resolver.generic_def().expect(
398 _ => None, 398 "there should be generics if there's a generic param",
399 }) 399 ),
400 .collect(); 400 );
401 // Handle `Self::Type` referring to own associated type in trait definitions 401 t.substs.clone().subst_bound_vars(&s)
402 if let GenericDefId::TraitId(trait_id) = param_id.parent { 402 }
403 let generics = generics(ctx.db.upcast(), trait_id.into()); 403 TypeParamLoweringMode::Variable => t.substs.clone(),
404 if generics.params.types[param_id.local_id].provenance 404 };
405 == TypeParamProvenance::TraitSelf 405 // FIXME handle type parameters on the segment
406 { 406 return Some(Ty::Projection(ProjectionTy {
407 traits_.push(trait_id); 407 associated_ty,
408 parameters: substs,
409 }));
408 } 410 }
409 } 411
410 traits_ 412 None
411 } 413 });
412 _ => return Ty::Unknown, 414
413 }; 415 ty.unwrap_or(Ty::Unknown)
414 let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db.upcast(), t)); 416 } else {
415 for t in traits { 417 Ty::Unknown
416 if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name)
417 {
418 let substs =
419 Substs::build_for_def(ctx.db, t).push(self_ty).fill_with_unknown().build();
420 // FIXME handle type parameters on the segment
421 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
422 }
423 } 418 }
424 Ty::Unknown
425 } 419 }
426 420
427 fn from_hir_path_inner( 421 fn from_hir_path_inner(
@@ -678,6 +672,61 @@ pub fn callable_item_sig(db: &dyn HirDatabase, def: CallableDef) -> PolyFnSig {
678 } 672 }
679} 673}
680 674
675pub fn associated_type_shorthand_candidates<R>(
676 db: &dyn HirDatabase,
677 res: TypeNs,
678 mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
679) -> Option<R> {
680 let traits_from_env: Vec<_> = match res {
681 TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) {
682 None => vec![],
683 Some(trait_ref) => vec![trait_ref.value],
684 },
685 TypeNs::GenericParam(param_id) => {
686 let predicates = db.generic_predicates_for_param(param_id);
687 let mut traits_: Vec<_> = predicates
688 .iter()
689 .filter_map(|pred| match &pred.value {
690 GenericPredicate::Implemented(tr) => Some(tr.clone()),
691 _ => None,
692 })
693 .collect();
694 // Handle `Self::Type` referring to own associated type in trait definitions
695 if let GenericDefId::TraitId(trait_id) = param_id.parent {
696 let generics = generics(db.upcast(), trait_id.into());
697 if generics.params.types[param_id.local_id].provenance
698 == TypeParamProvenance::TraitSelf
699 {
700 let trait_ref = TraitRef {
701 trait_: trait_id,
702 substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
703 };
704 traits_.push(trait_ref);
705 }
706 }
707 traits_
708 }
709 _ => vec![],
710 };
711
712 for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
713 let data = db.trait_data(t.trait_);
714
715 for (name, assoc_id) in &data.items {
716 match assoc_id {
717 AssocItemId::TypeAliasId(alias) => {
718 if let Some(result) = cb(name, &t, *alias) {
719 return Some(result);
720 }
721 }
722 AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {}
723 }
724 }
725 }
726
727 None
728}
729
681/// Build the type of all specific fields of a struct or enum variant. 730/// Build the type of all specific fields of a struct or enum variant.
682pub(crate) fn field_types_query( 731pub(crate) fn field_types_query(
683 db: &dyn HirDatabase, 732 db: &dyn HirDatabase,
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index b6a96bb5c..d60732e19 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -361,6 +361,33 @@ fn no_such_field_with_feature_flag_diagnostics() {
361} 361}
362 362
363#[test] 363#[test]
364fn no_such_field_enum_with_feature_flag_diagnostics() {
365 let diagnostics = TestDB::with_files(
366 r#"
367 //- /lib.rs crate:foo cfg:feature=foo
368 enum Foo {
369 #[cfg(not(feature = "foo"))]
370 Buz,
371 #[cfg(feature = "foo")]
372 Bar,
373 Baz
374 }
375
376 fn test_fn(f: Foo) {
377 match f {
378 Foo::Bar => {},
379 Foo::Baz => {},
380 }
381 }
382 "#,
383 )
384 .diagnostics()
385 .0;
386
387 assert_snapshot!(diagnostics, @r###""###);
388}
389
390#[test]
364fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() { 391fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
365 let diagnostics = TestDB::with_files( 392 let diagnostics = TestDB::with_files(
366 r#" 393 r#"
@@ -391,6 +418,38 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
391} 418}
392 419
393#[test] 420#[test]
421fn no_such_field_with_feature_flag_diagnostics_on_block_expr() {
422 let diagnostics = TestDB::with_files(
423 r#"
424 //- /lib.rs crate:foo cfg:feature=foo
425 struct S {
426 #[cfg(feature = "foo")]
427 foo: u32,
428 #[cfg(not(feature = "foo"))]
429 bar: u32,
430 }
431
432 impl S {
433 fn new(bar: u32) -> Self {
434 #[cfg(feature = "foo")]
435 {
436 Self { foo: bar }
437 }
438 #[cfg(not(feature = "foo"))]
439 {
440 Self { bar }
441 }
442 }
443 }
444 "#,
445 )
446 .diagnostics()
447 .0;
448
449 assert_snapshot!(diagnostics, @r###""###);
450}
451
452#[test]
394fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { 453fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
395 let diagnostics = TestDB::with_files( 454 let diagnostics = TestDB::with_files(
396 r#" 455 r#"
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 6b5267232..07398ddcc 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -269,7 +269,7 @@ fn test() { S.foo()<|>; }
269} 269}
270 270
271#[test] 271#[test]
272fn infer_impl_items_generated_by_macros() { 272fn infer_assoc_items_generated_by_macros() {
273 let t = type_at( 273 let t = type_at(
274 r#" 274 r#"
275//- /main.rs 275//- /main.rs
@@ -288,7 +288,7 @@ fn test() { S.foo()<|>; }
288} 288}
289 289
290#[test] 290#[test]
291fn infer_impl_items_generated_by_macros_chain() { 291fn infer_assoc_items_generated_by_macros_chain() {
292 let t = type_at( 292 let t = type_at(
293 r#" 293 r#"
294//- /main.rs 294//- /main.rs
@@ -339,6 +339,46 @@ pub fn baz() -> usize { 31usize }
339} 339}
340 340
341#[test] 341#[test]
342fn infer_macro_with_dollar_crate_is_correct_in_trait_associate_type() {
343 let (db, pos) = TestDB::with_position(
344 r#"
345//- /main.rs crate:main deps:foo
346use foo::Trait;
347
348fn test() {
349 let msg = foo::Message(foo::MessageRef);
350 let r = msg.deref();
351 r<|>;
352}
353
354//- /lib.rs crate:foo
355pub struct MessageRef;
356pub struct Message(MessageRef);
357
358pub trait Trait {
359 type Target;
360 fn deref(&self) -> &Self::Target;
361}
362
363#[macro_export]
364macro_rules! expand {
365 () => {
366 impl Trait for Message {
367 type Target = $crate::MessageRef;
368 fn deref(&self) -> &Self::Target {
369 &self.0
370 }
371 }
372 }
373}
374
375expand!();
376"#,
377 );
378 assert_eq!("&MessageRef", type_at_pos(&db, pos));
379}
380
381#[test]
342fn infer_type_value_non_legacy_macro_use_as() { 382fn infer_type_value_non_legacy_macro_use_as() {
343 assert_snapshot!( 383 assert_snapshot!(
344 infer(r#" 384 infer(r#"
@@ -388,6 +428,32 @@ fn main() {
388} 428}
389 429
390#[test] 430#[test]
431fn infer_local_inner_macros() {
432 let (db, pos) = TestDB::with_position(
433 r#"
434//- /main.rs crate:main deps:foo
435fn test() {
436 let x = foo::foo!(1);
437 x<|>;
438}
439
440//- /lib.rs crate:foo
441#[macro_export(local_inner_macros)]
442macro_rules! foo {
443 (1) => { bar!() };
444}
445
446#[macro_export]
447macro_rules! bar {
448 () => { 42 }
449}
450
451"#,
452 );
453 assert_eq!("i32", type_at_pos(&db, pos));
454}
455
456#[test]
391fn infer_builtin_macros_line() { 457fn infer_builtin_macros_line() {
392 assert_snapshot!( 458 assert_snapshot!(
393 infer(r#" 459 infer(r#"
@@ -622,14 +688,31 @@ fn main() {
622fn infer_derive_clone_simple() { 688fn infer_derive_clone_simple() {
623 let (db, pos) = TestDB::with_position( 689 let (db, pos) = TestDB::with_position(
624 r#" 690 r#"
625//- /main.rs crate:main deps:std 691//- /main.rs crate:main deps:core
626#[derive(Clone)] 692#[derive(Clone)]
627struct S; 693struct S;
628fn test() { 694fn test() {
629 S.clone()<|>; 695 S.clone()<|>;
630} 696}
631 697
632//- /lib.rs crate:std 698//- /lib.rs crate:core
699#[prelude_import]
700use clone::*;
701mod clone {
702 trait Clone {
703 fn clone(&self) -> Self;
704 }
705}
706"#,
707 );
708 assert_eq!("S", type_at_pos(&db, pos));
709}
710
711#[test]
712fn infer_derive_clone_in_core() {
713 let (db, pos) = TestDB::with_position(
714 r#"
715//- /lib.rs crate:core
633#[prelude_import] 716#[prelude_import]
634use clone::*; 717use clone::*;
635mod clone { 718mod clone {
@@ -637,6 +720,14 @@ mod clone {
637 fn clone(&self) -> Self; 720 fn clone(&self) -> Self;
638 } 721 }
639} 722}
723#[derive(Clone)]
724pub struct S;
725
726//- /main.rs crate:main deps:core
727use core::S;
728fn test() {
729 S.clone()<|>;
730}
640"#, 731"#,
641 ); 732 );
642 assert_eq!("S", type_at_pos(&db, pos)); 733 assert_eq!("S", type_at_pos(&db, pos));
@@ -646,7 +737,7 @@ mod clone {
646fn infer_derive_clone_with_params() { 737fn infer_derive_clone_with_params() {
647 let (db, pos) = TestDB::with_position( 738 let (db, pos) = TestDB::with_position(
648 r#" 739 r#"
649//- /main.rs crate:main deps:std 740//- /main.rs crate:main deps:core
650#[derive(Clone)] 741#[derive(Clone)]
651struct S; 742struct S;
652#[derive(Clone)] 743#[derive(Clone)]
@@ -656,7 +747,7 @@ fn test() {
656 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; 747 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
657} 748}
658 749
659//- /lib.rs crate:std 750//- /lib.rs crate:core
660#[prelude_import] 751#[prelude_import]
661use clone::*; 752use clone::*;
662mod clone { 753mod clone {
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 8a1292c7a..115ad8328 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -535,6 +535,35 @@ fn foo(b: Bar) {
535} 535}
536 536
537#[test] 537#[test]
538fn issue_4235_name_conflicts() {
539 assert_snapshot!(
540 infer(r#"
541struct FOO {}
542static FOO:FOO = FOO {};
543
544impl FOO {
545 fn foo(&self) {}
546}
547
548fn main() {
549 let a = &FOO;
550 a.foo();
551}
552"#), @r###"
553 32..38 'FOO {}': FOO
554 64..68 'self': &FOO
555 70..72 '{}': ()
556 86..120 '{ ...o(); }': ()
557 96..97 'a': &FOO
558 100..104 '&FOO': &FOO
559 101..104 'FOO': FOO
560 110..111 'a': &FOO
561 110..117 'a.foo()': ()
562"###
563 );
564}
565
566#[test]
538fn issue_4053_diesel_where_clauses() { 567fn issue_4053_diesel_where_clauses() {
539 assert_snapshot!( 568 assert_snapshot!(
540 infer(r#" 569 infer(r#"
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 56abc65b8..3d3088965 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -1755,3 +1755,35 @@ fn main() {
1755 "### 1755 "###
1756 ); 1756 );
1757} 1757}
1758
1759#[test]
1760fn effects_smoke_test() {
1761 assert_snapshot!(
1762 infer(r#"
1763fn main() {
1764 let x = unsafe { 92 };
1765 let y = async { async { () }.await };
1766 let z = try { () };
1767 let t = 'a: { 92 };
1768}
1769"#),
1770 @r###"
1771 11..131 '{ ...2 }; }': ()
1772 21..22 'x': i32
1773 32..38 '{ 92 }': i32
1774 34..36 '92': i32
1775 48..49 'y': {unknown}
1776 58..80 '{ asyn...wait }': {unknown}
1777 60..78 'async ....await': {unknown}
1778 66..72 '{ () }': ()
1779 68..70 '()': ()
1780 90..91 'z': {unknown}
1781 94..104 'try { () }': {unknown}
1782 98..104 '{ () }': ()
1783 100..102 '()': ()
1784 114..115 't': i32
1785 122..128 '{ 92 }': i32
1786 124..126 '92': i32
1787 "###
1788 )
1789}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index f51cdd496..9d32cbc7a 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1898,6 +1898,36 @@ fn test() {
1898} 1898}
1899 1899
1900#[test] 1900#[test]
1901fn unselected_projection_chalk_fold() {
1902 let t = type_at(
1903 r#"
1904//- /main.rs
1905trait Interner {}
1906trait Fold<I: Interner, TI = I> {
1907 type Result;
1908}
1909
1910struct Ty<I: Interner> {}
1911impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> {
1912 type Result = Ty<TI>;
1913}
1914
1915fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result
1916where
1917 T: Fold<I, I>,
1918{
1919 loop {}
1920}
1921
1922fn foo<I: Interner>(interner: &I, t: Ty<I>) {
1923 fold(interner, t)<|>;
1924}
1925"#,
1926 );
1927 assert_eq!(t, "Ty<I>");
1928}
1929
1930#[test]
1901fn trait_impl_self_ty() { 1931fn trait_impl_self_ty() {
1902 let t = type_at( 1932 let t = type_at(
1903 r#" 1933 r#"
@@ -2025,7 +2055,7 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
2025#[test] 2055#[test]
2026fn proc_macro_server_types() { 2056fn proc_macro_server_types() {
2027 assert_snapshot!( 2057 assert_snapshot!(
2028 infer_with_mismatches(r#" 2058 infer(r#"
2029macro_rules! with_api { 2059macro_rules! with_api {
2030 ($S:ident, $self:ident, $m:ident) => { 2060 ($S:ident, $self:ident, $m:ident) => {
2031 $m! { 2061 $m! {
@@ -2039,9 +2069,9 @@ macro_rules! with_api {
2039} 2069}
2040macro_rules! associated_item { 2070macro_rules! associated_item {
2041 (type TokenStream) => 2071 (type TokenStream) =>
2042 (type TokenStream: 'static + Clone;); 2072 (type TokenStream: 'static;);
2043 (type Group) => 2073 (type Group) =>
2044 (type Group: 'static + Clone;); 2074 (type Group: 'static;);
2045 ($($item:tt)*) => ($($item)*;) 2075 ($($item:tt)*) => ($($item)*;)
2046} 2076}
2047macro_rules! declare_server_traits { 2077macro_rules! declare_server_traits {
@@ -2053,21 +2083,23 @@ macro_rules! declare_server_traits {
2053 } 2083 }
2054 2084
2055 $(pub trait $name: Types { 2085 $(pub trait $name: Types {
2056 $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* 2086 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2057 })* 2087 })*
2058 2088
2059 pub trait Server: Types $(+ $name)* {} 2089 pub trait Server: Types $(+ $name)* {}
2060 impl<S: Types $(+ $name)*> Server for S {} 2090 impl<S: Types $(+ $name)*> Server for S {}
2061 } 2091 }
2062} 2092}
2093
2063with_api!(Self, self_, declare_server_traits); 2094with_api!(Self, self_, declare_server_traits);
2064struct Group {} 2095struct G {}
2065struct TokenStream {} 2096struct T {}
2066struct Rustc; 2097struct Rustc;
2067impl Types for Rustc { 2098impl Types for Rustc {
2068 type TokenStream = TokenStream; 2099 type TokenStream = T;
2069 type Group = Group; 2100 type Group = G;
2070} 2101}
2102
2071fn make<T>() -> T { loop {} } 2103fn make<T>() -> T { loop {} }
2072impl TokenStream for Rustc { 2104impl TokenStream for Rustc {
2073 fn new() -> Self::TokenStream { 2105 fn new() -> Self::TokenStream {
@@ -2075,17 +2107,17 @@ impl TokenStream for Rustc {
2075 make() 2107 make()
2076 } 2108 }
2077} 2109}
2078"#, true), 2110"#),
2079 @r###" 2111 @r###"
2080 1115..1126 '{ loop {} }': T 2112 1062..1073 '{ loop {} }': T
2081 1117..1124 'loop {}': ! 2113 1064..1071 'loop {}': !
2082 1122..1124 '{}': () 2114 1069..1071 '{}': ()
2083 1190..1253 '{ ... }': {unknown} 2115 1137..1200 '{ ... }': T
2084 1204..1209 'group': {unknown} 2116 1151..1156 'group': G
2085 1225..1229 'make': fn make<{unknown}>() -> {unknown} 2117 1172..1176 'make': fn make<G>() -> G
2086 1225..1231 'make()': {unknown} 2118 1172..1178 'make()': G
2087 1241..1245 'make': fn make<{unknown}>() -> {unknown} 2119 1188..1192 'make': fn make<T>() -> T
2088 1241..1247 'make()': {unknown} 2120 1188..1194 'make()': T
2089 "### 2121 "###
2090 ); 2122 );
2091} 2123}
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index 1e5022fa4..f98350bf9 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -14,6 +14,8 @@ use hir_def::{
14}; 14};
15use hir_expand::name::{name, Name}; 15use hir_expand::name::{name, Name};
16 16
17use crate::{db::HirDatabase, GenericPredicate, TraitRef};
18
17fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 19fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
18 let resolver = trait_.resolver(db); 20 let resolver = trait_.resolver(db);
19 // returning the iterator directly doesn't easily work because of 21 // returning the iterator directly doesn't easily work because of
@@ -41,6 +43,28 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
41 .collect() 43 .collect()
42} 44}
43 45
46fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> {
47 // returning the iterator directly doesn't easily work because of
48 // lifetime problems, but since there usually shouldn't be more than a
49 // few direct traits this should be fine (we could even use some kind of
50 // SmallVec if performance is a concern)
51 let generic_params = db.generic_params(trait_ref.trait_.into());
52 let trait_self = match generic_params.find_trait_self_param() {
53 Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p },
54 None => return Vec::new(),
55 };
56 db.generic_predicates_for_param(trait_self)
57 .iter()
58 .filter_map(|pred| {
59 pred.as_ref().filter_map(|pred| match pred {
60 GenericPredicate::Implemented(tr) => Some(tr.clone()),
61 _ => None,
62 })
63 })
64 .map(|pred| pred.subst(&trait_ref.substs))
65 .collect()
66}
67
44/// Returns an iterator over the whole super trait hierarchy (including the 68/// Returns an iterator over the whole super trait hierarchy (including the
45/// trait itself). 69/// trait itself).
46pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 70pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
@@ -62,6 +86,30 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra
62 result 86 result
63} 87}
64 88
89/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
90/// super traits. The original trait ref will be included. So the difference to
91/// `all_super_traits` is that we keep track of type parameters; for example if
92/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
93/// `Self: OtherTrait<i32>`.
94pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> {
95 // we need to take care a bit here to avoid infinite loops in case of cycles
96 // (i.e. if we have `trait A: B; trait B: A;`)
97 let mut result = vec![trait_ref];
98 let mut i = 0;
99 while i < result.len() {
100 let t = &result[i];
101 // yeah this is quadratic, but trait hierarchies should be flat
102 // enough that this doesn't matter
103 for tt in direct_super_trait_refs(db, t) {
104 if !result.iter().any(|tr| tr.trait_ == tt.trait_) {
105 result.push(tt);
106 }
107 }
108 i += 1;
109 }
110 result
111}
112
65/// Finds a path from a trait to one of its super traits. Returns an empty 113/// Finds a path from a trait to one of its super traits. Returns an empty
66/// vector if there is no path. 114/// vector if there is no path.
67pub(super) fn find_super_trait_path( 115pub(super) fn find_super_trait_path(