mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
fix: Apply IndexMut
obligations for non-assigning mutable index usages, too
This commit is contained in:
parent
f982f3fa2c
commit
20e2623234
2 changed files with 71 additions and 3 deletions
|
@ -1,7 +1,7 @@
|
||||||
//! Finds if an expression is an immutable context or a mutable context, which is used in selecting
|
//! Finds if an expression is an immutable context or a mutable context, which is used in selecting
|
||||||
//! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar.
|
//! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar.
|
||||||
|
|
||||||
use chalk_ir::Mutability;
|
use chalk_ir::{cast::Cast, Mutability};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp},
|
hir::{Array, BinaryOp, BindingAnnotation, Expr, ExprId, PatId, Statement, UnaryOp},
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
|
@ -9,7 +9,10 @@ use hir_def::{
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use intern::sym;
|
use intern::sym;
|
||||||
|
|
||||||
use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref};
|
use crate::{
|
||||||
|
infer::Expectation, lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, Interner,
|
||||||
|
OverloadedDeref, TyBuilder, TyKind,
|
||||||
|
};
|
||||||
|
|
||||||
use super::InferenceContext;
|
use super::InferenceContext;
|
||||||
|
|
||||||
|
@ -115,6 +118,7 @@ impl InferenceContext<'_> {
|
||||||
.method_by_name(&Name::new_symbol_root(sym::index_mut.clone()))
|
.method_by_name(&Name::new_symbol_root(sym::index_mut.clone()))
|
||||||
{
|
{
|
||||||
*f = index_fn;
|
*f = index_fn;
|
||||||
|
let mut base_ty = None;
|
||||||
let base_adjustments = self
|
let base_adjustments = self
|
||||||
.result
|
.result
|
||||||
.expr_adjustments
|
.expr_adjustments
|
||||||
|
@ -122,10 +126,27 @@ impl InferenceContext<'_> {
|
||||||
.and_then(|it| it.last_mut());
|
.and_then(|it| it.last_mut());
|
||||||
if let Some(Adjustment {
|
if let Some(Adjustment {
|
||||||
kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
|
kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
|
||||||
..
|
target,
|
||||||
}) = base_adjustments
|
}) = base_adjustments
|
||||||
{
|
{
|
||||||
*mutability = Mutability::Mut;
|
*mutability = Mutability::Mut;
|
||||||
|
if let TyKind::Ref(_, _, ty) = target.kind(Interner) {
|
||||||
|
base_ty = Some(ty.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(base_ty) = base_ty {
|
||||||
|
let index_ty =
|
||||||
|
if let Some(ty) = self.result.type_of_expr.get(index) {
|
||||||
|
ty.clone()
|
||||||
|
} else {
|
||||||
|
self.infer_expr(index, &Expectation::none())
|
||||||
|
};
|
||||||
|
let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
|
||||||
|
.push(base_ty)
|
||||||
|
.fill(|_| index_ty.clone().cast(Interner))
|
||||||
|
.build();
|
||||||
|
self.push_obligation(trait_ref.cast(Interner));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2075,3 +2075,50 @@ impl<'a, T> Trait<'a> for &'a T {
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_17738() {
|
||||||
|
check_types(
|
||||||
|
r#"
|
||||||
|
//- minicore: index
|
||||||
|
use core::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
struct Foo<K, V>(K, V);
|
||||||
|
|
||||||
|
struct Bar;
|
||||||
|
|
||||||
|
impl Bar {
|
||||||
|
fn bar(&mut self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> Foo<K, V> {
|
||||||
|
fn new(_v: V) -> Self {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, B, V> Index<B> for Foo<K, V> {
|
||||||
|
type Output = V;
|
||||||
|
fn index(&self, _index: B) -> &Self::Output {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K, V> IndexMut<K> for Foo<K, V> {
|
||||||
|
fn index_mut(&mut self, _index: K) -> &mut Self::Output {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test() {
|
||||||
|
let mut t1 = Foo::new(Bar);
|
||||||
|
// ^^^^^^ Foo<&'? (), Bar>
|
||||||
|
t1[&()] = Bar;
|
||||||
|
|
||||||
|
let mut t2 = Foo::new(Bar);
|
||||||
|
// ^^^^^^ Foo<&'? (), Bar>
|
||||||
|
t2[&()].bar();
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue