Skip to content

Commit 3e78a6e

Browse files
committed
Somewhat handle variables in the derefed type, and add another test
1 parent ca5ed23 commit 3e78a6e

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

crates/ra_hir/src/ty.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,17 @@ impl Ty {
474474
_ => None,
475475
}
476476
}
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+
}
477488
}
478489

479490
impl HirDisplay for &Ty {

crates/ra_hir/src/ty/autoderef.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use std::iter::successors;
77

8-
use log::info;
8+
use log::{info, warn};
99

1010
use crate::{HirDatabase, Name, Resolver};
1111
use super::{traits::Solution, Ty, Canonical};
@@ -43,15 +43,13 @@ fn deref_by_trait(
4343
let target = deref_trait.associated_type_by_name(db, Name::target())?;
4444

4545
// FIXME we should check that Deref has no type parameters, because we assume it below
46-
4746
// FIXME make the Canonical handling nicer
48-
// TODO shift inference variables in ty
4947

5048
let projection = super::traits::ProjectionPredicate {
5149
ty: Ty::Bound(0),
5250
projection_ty: super::ProjectionTy {
5351
associated_ty: target,
54-
parameters: vec![ty.value.clone()].into(),
52+
parameters: vec![ty.value.clone().shift_bound_vars(1)].into(),
5553
},
5654
};
5755

@@ -61,10 +59,26 @@ fn deref_by_trait(
6159

6260
match &solution {
6361
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+
}
6478
Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars })
6579
}
6680
Solution::Ambig(_) => {
67-
info!("Ambiguous solution for deref: {:?}", solution);
81+
info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution);
6882
None
6983
}
7084
}

crates/ra_hir/src/ty/tests.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2766,6 +2766,37 @@ fn test(s: Arc<S>) {
27662766
assert_eq!(t, "(S, u128)");
27672767
}
27682768

2769+
#[test]
2770+
fn 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"]
2776+
trait Deref {
2777+
type Target;
2778+
fn deref(&self) -> &Self::Target;
2779+
}
2780+
2781+
struct Arc<T>;
2782+
fn new_arc<T>() -> Arc<T> {}
2783+
impl<T> Deref for Arc<T> {
2784+
type Target = T;
2785+
}
2786+
2787+
struct S;
2788+
fn foo(a: Arc<S>) {}
2789+
2790+
fn test() {
2791+
let a = new_arc();
2792+
let b = (*a)<|>;
2793+
foo(a);
2794+
}
2795+
"#,
2796+
);
2797+
assert_eq!(t, "S");
2798+
}
2799+
27692800
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
27702801
let file = db.parse(pos.file_id).ok().unwrap();
27712802
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();

0 commit comments

Comments
 (0)