mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 11:31:15 +00:00
Somewhat handle variables in the derefed type, and add another test
This commit is contained in:
parent
ca5ed2307c
commit
3e78a6e3e0
@ -474,6 +474,17 @@ impl Ty {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shifts up `Ty::Bound` vars by `n`.
|
||||||
|
pub fn shift_bound_vars(self, n: i32) -> Ty {
|
||||||
|
self.fold(&mut |ty| match ty {
|
||||||
|
Ty::Bound(idx) => {
|
||||||
|
assert!(idx as i32 >= -n);
|
||||||
|
Ty::Bound((idx as i32 + n) as u32)
|
||||||
|
}
|
||||||
|
ty => ty,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HirDisplay for &Ty {
|
impl HirDisplay for &Ty {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use std::iter::successors;
|
use std::iter::successors;
|
||||||
|
|
||||||
use log::info;
|
use log::{info, warn};
|
||||||
|
|
||||||
use crate::{HirDatabase, Name, Resolver};
|
use crate::{HirDatabase, Name, Resolver};
|
||||||
use super::{traits::Solution, Ty, Canonical};
|
use super::{traits::Solution, Ty, Canonical};
|
||||||
@ -43,15 +43,13 @@ fn deref_by_trait(
|
|||||||
let target = deref_trait.associated_type_by_name(db, Name::target())?;
|
let target = deref_trait.associated_type_by_name(db, Name::target())?;
|
||||||
|
|
||||||
// FIXME we should check that Deref has no type parameters, because we assume it below
|
// FIXME we should check that Deref has no type parameters, because we assume it below
|
||||||
|
|
||||||
// FIXME make the Canonical handling nicer
|
// FIXME make the Canonical handling nicer
|
||||||
// TODO shift inference variables in ty
|
|
||||||
|
|
||||||
let projection = super::traits::ProjectionPredicate {
|
let projection = super::traits::ProjectionPredicate {
|
||||||
ty: Ty::Bound(0),
|
ty: Ty::Bound(0),
|
||||||
projection_ty: super::ProjectionTy {
|
projection_ty: super::ProjectionTy {
|
||||||
associated_ty: target,
|
associated_ty: target,
|
||||||
parameters: vec![ty.value.clone()].into(),
|
parameters: vec![ty.value.clone().shift_bound_vars(1)].into(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -61,10 +59,26 @@ fn deref_by_trait(
|
|||||||
|
|
||||||
match &solution {
|
match &solution {
|
||||||
Solution::Unique(vars) => {
|
Solution::Unique(vars) => {
|
||||||
|
// FIXME: vars may contain solutions for any inference variables
|
||||||
|
// that happened to be inside ty. To correctly handle these, we
|
||||||
|
// would have to pass the solution up to the inference context, but
|
||||||
|
// that requires a larger refactoring (especially if the deref
|
||||||
|
// happens during method resolution). So for the moment, we just
|
||||||
|
// check that we're not in the situation we're we would actually
|
||||||
|
// need to handle the values of the additional variables, i.e.
|
||||||
|
// they're just being 'passed through'. In the 'standard' case where
|
||||||
|
// we have `impl<T> Deref for Foo<T> { Target = T }`, that should be
|
||||||
|
// the case.
|
||||||
|
for i in 1..vars.0.num_vars {
|
||||||
|
if vars.0.value[i] != Ty::Bound((i - 1) as u32) {
|
||||||
|
warn!("complex solution for derefing {:?}: {:?}, ignoring", ty, solution);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars })
|
Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars })
|
||||||
}
|
}
|
||||||
Solution::Ambig(_) => {
|
Solution::Ambig(_) => {
|
||||||
info!("Ambiguous solution for deref: {:?}", solution);
|
info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2766,6 +2766,37 @@ fn test(s: Arc<S>) {
|
|||||||
assert_eq!(t, "(S, u128)");
|
assert_eq!(t, "(S, u128)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deref_trait_with_inference_var() {
|
||||||
|
// std::env::set_var("RUST_BACKTRACE", "1");
|
||||||
|
let t = type_at(
|
||||||
|
r#"
|
||||||
|
//- /main.rs
|
||||||
|
#[lang = "deref"]
|
||||||
|
trait Deref {
|
||||||
|
type Target;
|
||||||
|
fn deref(&self) -> &Self::Target;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Arc<T>;
|
||||||
|
fn new_arc<T>() -> Arc<T> {}
|
||||||
|
impl<T> Deref for Arc<T> {
|
||||||
|
type Target = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
fn foo(a: Arc<S>) {}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let a = new_arc();
|
||||||
|
let b = (*a)<|>;
|
||||||
|
foo(a);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
assert_eq!(t, "S");
|
||||||
|
}
|
||||||
|
|
||||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||||
let file = db.parse(pos.file_id).ok().unwrap();
|
let file = db.parse(pos.file_id).ok().unwrap();
|
||||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user