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.rs12
-rw-r--r--crates/ra_hir_ty/src/lower.rs42
-rw-r--r--crates/ra_hir_ty/src/tests.rs32
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs33
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs30
-rw-r--r--crates/ra_hir_ty/src/utils.rs48
7 files changed, 182 insertions, 20 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..a8ef32ec5 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -487,6 +487,18 @@ impl<T> Binders<T> {
487 pub fn new(num_binders: usize, value: T) -> Self { 487 pub fn new(num_binders: usize, value: T) -> Self {
488 Self { num_binders, value } 488 Self { num_binders, value }
489 } 489 }
490
491 pub fn as_ref(&self) -> Binders<&T> {
492 Binders { num_binders: self.num_binders, value: &self.value }
493 }
494
495 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
496 Binders { num_binders: self.num_binders, value: f(self.value) }
497 }
498
499 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
500 Some(Binders { num_binders: self.num_binders, value: f(self.value)? })
501 }
490} 502}
491 503
492impl<T: Clone> Binders<&T> { 504impl<T: Clone> Binders<&T> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index b57214296..a6f893037 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -28,11 +28,11 @@ 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};
37 37
38#[derive(Debug)] 38#[derive(Debug)]
@@ -256,7 +256,7 @@ impl Ty {
256 if remaining_segments.len() == 1 { 256 if remaining_segments.len() == 1 {
257 // resolve unselected assoc types 257 // resolve unselected assoc types
258 let segment = remaining_segments.first().unwrap(); 258 let segment = remaining_segments.first().unwrap();
259 (Ty::select_associated_type(ctx, ty, res, segment), None) 259 (Ty::select_associated_type(ctx, res, segment), None)
260 } else if remaining_segments.len() > 1 { 260 } else if remaining_segments.len() > 1 {
261 // FIXME report error (ambiguous associated type) 261 // FIXME report error (ambiguous associated type)
262 (Ty::Unknown, None) 262 (Ty::Unknown, None)
@@ -380,21 +380,20 @@ impl Ty {
380 380
381 fn select_associated_type( 381 fn select_associated_type(
382 ctx: &TyLoweringContext<'_>, 382 ctx: &TyLoweringContext<'_>,
383 self_ty: Ty,
384 res: Option<TypeNs>, 383 res: Option<TypeNs>,
385 segment: PathSegment<'_>, 384 segment: PathSegment<'_>,
386 ) -> Ty { 385 ) -> Ty {
387 let traits_from_env: Vec<_> = match res { 386 let traits_from_env: Vec<_> = match res {
388 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { 387 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) {
389 None => return Ty::Unknown, 388 None => return Ty::Unknown,
390 Some(trait_ref) => vec![trait_ref.value.trait_], 389 Some(trait_ref) => vec![trait_ref.value],
391 }, 390 },
392 Some(TypeNs::GenericParam(param_id)) => { 391 Some(TypeNs::GenericParam(param_id)) => {
393 let predicates = ctx.db.generic_predicates_for_param(param_id); 392 let predicates = ctx.db.generic_predicates_for_param(param_id);
394 let mut traits_: Vec<_> = predicates 393 let mut traits_: Vec<_> = predicates
395 .iter() 394 .iter()
396 .filter_map(|pred| match &pred.value { 395 .filter_map(|pred| match &pred.value {
397 GenericPredicate::Implemented(tr) => Some(tr.trait_), 396 GenericPredicate::Implemented(tr) => Some(tr.clone()),
398 _ => None, 397 _ => None,
399 }) 398 })
400 .collect(); 399 .collect();
@@ -404,20 +403,37 @@ impl Ty {
404 if generics.params.types[param_id.local_id].provenance 403 if generics.params.types[param_id.local_id].provenance
405 == TypeParamProvenance::TraitSelf 404 == TypeParamProvenance::TraitSelf
406 { 405 {
407 traits_.push(trait_id); 406 let trait_ref = TraitRef {
407 trait_: trait_id,
408 substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
409 };
410 traits_.push(trait_ref);
408 } 411 }
409 } 412 }
410 traits_ 413 traits_
411 } 414 }
412 _ => return Ty::Unknown, 415 _ => return Ty::Unknown,
413 }; 416 };
414 let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db.upcast(), t)); 417 let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t));
415 for t in traits { 418 for t in traits {
416 if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) 419 if let Some(associated_ty) =
420 ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name)
417 { 421 {
418 let substs = 422 let substs = match ctx.type_param_mode {
419 Substs::build_for_def(ctx.db, t).push(self_ty).fill_with_unknown().build(); 423 TypeParamLoweringMode::Placeholder => {
420 // FIXME handle type parameters on the segment 424 // if we're lowering to placeholders, we have to put
425 // them in now
426 let s = Substs::type_params(
427 ctx.db,
428 ctx.resolver
429 .generic_def()
430 .expect("there should be generics if there's a generic param"),
431 );
432 t.substs.subst_bound_vars(&s)
433 }
434 TypeParamLoweringMode::Variable => t.substs,
435 };
436 // FIXME handle (forbid) type parameters on the segment
421 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); 437 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
422 } 438 }
423 } 439 }
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index b6a96bb5c..588d81282 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -391,6 +391,38 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_lit() {
391} 391}
392 392
393#[test] 393#[test]
394fn no_such_field_with_feature_flag_diagnostics_on_block_expr() {
395 let diagnostics = TestDB::with_files(
396 r#"
397 //- /lib.rs crate:foo cfg:feature=foo
398 struct S {
399 #[cfg(feature = "foo")]
400 foo: u32,
401 #[cfg(not(feature = "foo"))]
402 bar: u32,
403 }
404
405 impl S {
406 fn new(bar: u32) -> Self {
407 #[cfg(feature = "foo")]
408 {
409 Self { foo: bar }
410 }
411 #[cfg(not(feature = "foo"))]
412 {
413 Self { bar }
414 }
415 }
416 }
417 "#,
418 )
419 .diagnostics()
420 .0;
421
422 assert_snapshot!(diagnostics, @r###""###);
423}
424
425#[test]
394fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() { 426fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
395 let diagnostics = TestDB::with_files( 427 let diagnostics = TestDB::with_files(
396 r#" 428 r#"
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 6b5267232..5ddecbdc6 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -622,14 +622,14 @@ fn main() {
622fn infer_derive_clone_simple() { 622fn infer_derive_clone_simple() {
623 let (db, pos) = TestDB::with_position( 623 let (db, pos) = TestDB::with_position(
624 r#" 624 r#"
625//- /main.rs crate:main deps:std 625//- /main.rs crate:main deps:core
626#[derive(Clone)] 626#[derive(Clone)]
627struct S; 627struct S;
628fn test() { 628fn test() {
629 S.clone()<|>; 629 S.clone()<|>;
630} 630}
631 631
632//- /lib.rs crate:std 632//- /lib.rs crate:core
633#[prelude_import] 633#[prelude_import]
634use clone::*; 634use clone::*;
635mod clone { 635mod clone {
@@ -643,10 +643,35 @@ mod clone {
643} 643}
644 644
645#[test] 645#[test]
646fn infer_derive_clone_in_core() {
647 let (db, pos) = TestDB::with_position(
648 r#"
649//- /lib.rs crate:core
650#[prelude_import]
651use clone::*;
652mod clone {
653 trait Clone {
654 fn clone(&self) -> Self;
655 }
656}
657#[derive(Clone)]
658pub struct S;
659
660//- /main.rs crate:main deps:core
661use core::S;
662fn test() {
663 S.clone()<|>;
664}
665"#,
666 );
667 assert_eq!("S", type_at_pos(&db, pos));
668}
669
670#[test]
646fn infer_derive_clone_with_params() { 671fn infer_derive_clone_with_params() {
647 let (db, pos) = TestDB::with_position( 672 let (db, pos) = TestDB::with_position(
648 r#" 673 r#"
649//- /main.rs crate:main deps:std 674//- /main.rs crate:main deps:core
650#[derive(Clone)] 675#[derive(Clone)]
651struct S; 676struct S;
652#[derive(Clone)] 677#[derive(Clone)]
@@ -656,7 +681,7 @@ fn test() {
656 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; 681 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
657} 682}
658 683
659//- /lib.rs crate:std 684//- /lib.rs crate:core
660#[prelude_import] 685#[prelude_import]
661use clone::*; 686use clone::*;
662mod clone { 687mod clone {
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index f51cdd496..e555c879a 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#"
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(