aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty.rs11
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs24
-rw-r--r--crates/ra_hir/src/ty/tests.rs31
3 files changed, 61 insertions, 5 deletions
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d2f92a1f2..4ed19f860 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -474,6 +474,17 @@ impl Ty {
474 _ => None, 474 _ => None,
475 } 475 }
476 } 476 }
477
478 /// Shifts up `Ty::Bound` vars by `n`.
479 pub fn shift_bound_vars(self, n: i32) -> Ty {
480 self.fold(&mut |ty| match ty {
481 Ty::Bound(idx) => {
482 assert!(idx as i32 >= -n);
483 Ty::Bound((idx as i32 + n) as u32)
484 }
485 ty => ty,
486 })
487 }
477} 488}
478 489
479impl HirDisplay for &Ty { 490impl HirDisplay for &Ty {
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index bee756d80..11f489489 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -5,7 +5,7 @@
5 5
6use std::iter::successors; 6use std::iter::successors;
7 7
8use log::info; 8use log::{info, warn};
9 9
10use crate::{HirDatabase, Name, Resolver}; 10use crate::{HirDatabase, Name, Resolver};
11use super::{traits::Solution, Ty, Canonical}; 11use super::{traits::Solution, Ty, Canonical};
@@ -43,15 +43,13 @@ fn deref_by_trait(
43 let target = deref_trait.associated_type_by_name(db, Name::target())?; 43 let target = deref_trait.associated_type_by_name(db, Name::target())?;
44 44
45 // FIXME we should check that Deref has no type parameters, because we assume it below 45 // FIXME we should check that Deref has no type parameters, because we assume it below
46
47 // FIXME make the Canonical handling nicer 46 // FIXME make the Canonical handling nicer
48 // TODO shift inference variables in ty
49 47
50 let projection = super::traits::ProjectionPredicate { 48 let projection = super::traits::ProjectionPredicate {
51 ty: Ty::Bound(0), 49 ty: Ty::Bound(0),
52 projection_ty: super::ProjectionTy { 50 projection_ty: super::ProjectionTy {
53 associated_ty: target, 51 associated_ty: target,
54 parameters: vec![ty.value.clone()].into(), 52 parameters: vec![ty.value.clone().shift_bound_vars(1)].into(),
55 }, 53 },
56 }; 54 };
57 55
@@ -61,10 +59,26 @@ fn deref_by_trait(
61 59
62 match &solution { 60 match &solution {
63 Solution::Unique(vars) => { 61 Solution::Unique(vars) => {
62 // FIXME: vars may contain solutions for any inference variables
63 // that happened to be inside ty. To correctly handle these, we
64 // would have to pass the solution up to the inference context, but
65 // that requires a larger refactoring (especially if the deref
66 // happens during method resolution). So for the moment, we just
67 // check that we're not in the situation we're we would actually
68 // need to handle the values of the additional variables, i.e.
69 // they're just being 'passed through'. In the 'standard' case where
70 // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
71 // the case.
72 for i in 1..vars.0.num_vars {
73 if vars.0.value[i] != Ty::Bound((i - 1) as u32) {
74 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty, solution);
75 return None;
76 }
77 }
64 Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) 78 Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars })
65 } 79 }
66 Solution::Ambig(_) => { 80 Solution::Ambig(_) => {
67 info!("Ambiguous solution for deref: {:?}", solution); 81 info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution);
68 None 82 None
69 } 83 }
70 } 84 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index e587dca31..059a73900 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2766,6 +2766,37 @@ fn test(s: Arc<S>) {
2766 assert_eq!(t, "(S, u128)"); 2766 assert_eq!(t, "(S, u128)");
2767} 2767}
2768 2768
2769#[test]
2770fn deref_trait_with_inference_var() {
2771 // std::env::set_var("RUST_BACKTRACE", "1");
2772 let t = type_at(
2773 r#"
2774//- /main.rs
2775#[lang = "deref"]
2776trait Deref {
2777 type Target;
2778 fn deref(&self) -> &Self::Target;
2779}
2780
2781struct Arc<T>;
2782fn new_arc<T>() -> Arc<T> {}
2783impl<T> Deref for Arc<T> {
2784 type Target = T;
2785}
2786
2787struct S;
2788fn foo(a: Arc<S>) {}
2789
2790fn test() {
2791 let a = new_arc();
2792 let b = (*a)<|>;
2793 foo(a);
2794}
2795"#,
2796 );
2797 assert_eq!(t, "S");
2798}
2799
2769fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2800fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
2770 let file = db.parse(pos.file_id).ok().unwrap(); 2801 let file = db.parse(pos.file_id).ok().unwrap();
2771 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 2802 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();