Auto merge of #16696 - ShoyuVanilla:fix-goto-deref-mut, r=Veykril
fix: Goto definition for `deref_mut` Fixes #16520a3236be9d7/crates/hir/src/source_analyzer.rs (L375-L393)
As we can see from the above, current implementation routes all dereferencing prefix operations to `Deref::deref` implementation, not regarding mutabilities.a3236be9d7/crates/hir-ty/src/infer/mutability.rs (L134-L151)
Since we are resolving them already in mutability inferences, we can use those results for proper `deref` / `deref_mut` routing.
This commit is contained in:
commit
a41cec9f7c
@ -377,14 +377,34 @@ impl SourceAnalyzer {
|
|||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
prefix_expr: &ast::PrefixExpr,
|
prefix_expr: &ast::PrefixExpr,
|
||||||
) -> Option<FunctionId> {
|
) -> Option<FunctionId> {
|
||||||
let (lang_item, fn_name) = match prefix_expr.op_kind()? {
|
let (op_trait, op_fn) = match prefix_expr.op_kind()? {
|
||||||
ast::UnaryOp::Deref => (LangItem::Deref, name![deref]),
|
ast::UnaryOp::Deref => {
|
||||||
ast::UnaryOp::Not => (LangItem::Not, name![not]),
|
// This can be either `Deref::deref` or `DerefMut::deref_mut`.
|
||||||
ast::UnaryOp::Neg => (LangItem::Neg, name![neg]),
|
// Since deref kind is inferenced and stored in `InferenceResult.method_resolution`,
|
||||||
|
// use that result to find out which one it is.
|
||||||
|
let (deref_trait, deref) =
|
||||||
|
self.lang_trait_fn(db, LangItem::Deref, &name![deref])?;
|
||||||
|
self.infer
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|infer| {
|
||||||
|
let expr = self.expr_id(db, &prefix_expr.clone().into())?;
|
||||||
|
let (func, _) = infer.method_resolution(expr)?;
|
||||||
|
let (deref_mut_trait, deref_mut) =
|
||||||
|
self.lang_trait_fn(db, LangItem::DerefMut, &name![deref_mut])?;
|
||||||
|
if func == deref_mut {
|
||||||
|
Some((deref_mut_trait, deref_mut))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or((deref_trait, deref))
|
||||||
|
}
|
||||||
|
ast::UnaryOp::Not => self.lang_trait_fn(db, LangItem::Not, &name![not])?,
|
||||||
|
ast::UnaryOp::Neg => self.lang_trait_fn(db, LangItem::Neg, &name![neg])?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
|
let ty = self.ty_of_expr(db, &prefix_expr.expr()?)?;
|
||||||
|
|
||||||
let (op_trait, op_fn) = self.lang_trait_fn(db, lang_item, &fn_name)?;
|
|
||||||
// HACK: subst for all methods coincides with that for their trait because the methods
|
// HACK: subst for all methods coincides with that for their trait because the methods
|
||||||
// don't have any generic parameters, so we skip building another subst for the methods.
|
// don't have any generic parameters, so we skip building another subst for the methods.
|
||||||
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
|
||||||
|
@ -1977,6 +1977,33 @@ fn f() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn goto_deref_mut() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- minicore: deref, deref_mut
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
struct Bar;
|
||||||
|
|
||||||
|
impl core::ops::Deref for Foo {
|
||||||
|
type Target = Bar;
|
||||||
|
fn deref(&self) -> &Self::Target {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl core::ops::DerefMut for Foo {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {}
|
||||||
|
//^^^^^^^^^
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() {
|
||||||
|
let a = Foo;
|
||||||
|
$0*a = Bar;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn goto_bin_op() {
|
fn goto_bin_op() {
|
||||||
check(
|
check(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user