fix: Add missing autoborrow adjustment for index expressions

This commit is contained in:
Lukas Wirth 2023-03-29 16:11:48 +02:00
parent bea1c71f83
commit 798990bf33
5 changed files with 104 additions and 33 deletions

View File

@ -793,10 +793,12 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
canonicalized.value, canonicalized.value,
index_trait, index_trait,
); );
let (self_ty, adj) = receiver_adjustments let (self_ty, mut adj) = receiver_adjustments
.map_or((self.err_ty(), Vec::new()), |adj| { .map_or((self.err_ty(), Vec::new()), |adj| {
adj.apply(&mut self.table, base_ty) adj.apply(&mut self.table, base_ty)
}); });
// mutability will be fixed up in `InferenceContext::infer_mut`;
adj.push(Adjustment::borrow(Mutability::Not, self_ty.clone()));
self.write_expr_adj(*base, adj); self.write_expr_adj(*base, adj);
if let Some(func) = if let Some(func) =
self.db.trait_data(index_trait).method_by_name(&name!(index)) self.db.trait_data(index_trait).method_by_name(&name!(index))

View File

@ -8,7 +8,7 @@
}; };
use hir_expand::name; use hir_expand::name;
use crate::{lower::lower_to_chalk_mutability, Adjust, AutoBorrow, OverloadedDeref}; use crate::{lower::lower_to_chalk_mutability, Adjust, Adjustment, AutoBorrow, OverloadedDeref};
use super::InferenceContext; use super::InferenceContext;
@ -18,15 +18,15 @@ pub(crate) fn infer_mut_body(&mut self) {
} }
fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) { fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) {
let mut v = vec![]; if let Some(adjustments) = self.result.expr_adjustments.get_mut(&tgt_expr) {
let adjustments = self.result.expr_adjustments.get_mut(&tgt_expr).unwrap_or(&mut v); for adj in adjustments.iter_mut().rev() {
for adj in adjustments.iter_mut().rev() { match &mut adj.kind {
match &mut adj.kind { Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (), Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)),
Adjust::Deref(Some(d)) => *d = OverloadedDeref(Some(mutability)), Adjust::Borrow(b) => match b {
Adjust::Borrow(b) => match b { AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m,
AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m) => mutability = *m, },
}, }
} }
} }
self.infer_mut_expr_without_adjust(tgt_expr, mutability); self.infer_mut_expr_without_adjust(tgt_expr, mutability);
@ -94,8 +94,8 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi
self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread)) self.infer_mut_not_expr_iter(fields.iter().map(|x| x.expr).chain(*spread))
} }
&Expr::Index { base, index } => { &Expr::Index { base, index } => {
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if mutability == Mutability::Mut {
if mutability == Mutability::Mut { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
if let Some(index_trait) = self if let Some(index_trait) = self
.db .db
.lang_item(self.table.trait_env.krate, LangItem::IndexMut) .lang_item(self.table.trait_env.krate, LangItem::IndexMut)
@ -105,6 +105,18 @@ fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutabi
self.db.trait_data(index_trait).method_by_name(&name![index_mut]) self.db.trait_data(index_trait).method_by_name(&name![index_mut])
{ {
*f = index_fn; *f = index_fn;
let base_adjustments = self
.result
.expr_adjustments
.get_mut(&base)
.and_then(|it| it.last_mut());
if let Some(Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(mutability)),
..
}) = base_adjustments
{
*mutability = Mutability::Mut;
}
} }
} }
} }

View File

@ -192,7 +192,10 @@ pub(super) fn lower_expr_as_place_without_adjust(
let base_ty = self.expr_ty_after_adjustments(*base); let base_ty = self.expr_ty_after_adjustments(*base);
let index_ty = self.expr_ty_after_adjustments(*index); let index_ty = self.expr_ty_after_adjustments(*index);
if index_ty != TyBuilder::usize() if index_ty != TyBuilder::usize()
|| !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..)) || !matches!(
base_ty.strip_reference().kind(Interner),
TyKind::Array(..) | TyKind::Slice(..)
)
{ {
let Some(index_fn) = self.infer.method_resolution(expr_id) else { let Some(index_fn) = self.infer.method_resolution(expr_id) else {
return Err(MirLowerError::UnresolvedMethod); return Err(MirLowerError::UnresolvedMethod);
@ -206,7 +209,7 @@ pub(super) fn lower_expr_as_place_without_adjust(
return self.lower_overloaded_index( return self.lower_overloaded_index(
current, current,
base_place, base_place,
self.expr_ty_after_adjustments(*base), base_ty,
self.expr_ty(expr_id), self.expr_ty(expr_id),
index_operand, index_operand,
expr_id.into(), expr_id.into(),
@ -214,7 +217,8 @@ pub(super) fn lower_expr_as_place_without_adjust(
); );
} }
let Some((mut p_base, current)) = let Some((mut p_base, current)) =
self.lower_expr_as_place(current, *base, true)? else { self.lower_expr_as_place_without_adjust(current, *base, true)?
else {
return Ok(None); return Ok(None);
}; };
let l_index = self.temp(self.expr_ty_after_adjustments(*index))?; let l_index = self.temp(self.expr_ty_after_adjustments(*index))?;
@ -238,23 +242,14 @@ fn lower_overloaded_index(
span: MirSpan, span: MirSpan,
index_fn: (FunctionId, Substitution), index_fn: (FunctionId, Substitution),
) -> Result<Option<(Place, BasicBlockId)>> { ) -> Result<Option<(Place, BasicBlockId)>> {
let is_mutable = 'b: { let (mutability, borrow_kind) = match base_ty.as_reference() {
if let Some(index_mut_trait) = self.resolve_lang_item(LangItem::IndexMut)?.as_trait() { Some((_, _, mutability)) => {
if let Some(index_mut_fn) = (mutability, BorrowKind::Mut { allow_two_phase_borrow: false })
self.db.trait_data(index_mut_trait).method_by_name(&name![index_mut])
{
break 'b index_mut_fn == index_fn.0;
}
} }
false None => (Mutability::Not, BorrowKind::Shared),
}; };
let (mutability, borrow_kind) = match is_mutable {
true => (Mutability::Mut, BorrowKind::Mut { allow_two_phase_borrow: false }),
false => (Mutability::Not, BorrowKind::Shared),
};
let base_ref = TyKind::Ref(mutability, static_lifetime(), base_ty).intern(Interner);
let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner); let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner);
let ref_place: Place = self.temp(base_ref)?.into(); let ref_place: Place = self.temp(base_ty)?.into();
self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span); self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span);
let mut result: Place = self.temp(result_ref)?.into(); let mut result: Place = self.temp(result_ref)?.into();
let index_fn_op = Operand::const_zst( let index_fn_op = Operand::const_zst(

View File

@ -870,3 +870,35 @@ fn test() {
}", }",
); );
} }
#[test]
fn adjust_index() {
check_no_mismatches(
r"
//- minicore: index
struct Struct;
impl core::ops::Index<usize> for Struct {
type Output = ();
fn index(&self, index: usize) -> &Self::Output { &() }
}
struct StructMut;
impl core::ops::Index<usize> for StructMut {
type Output = ();
fn index(&self, index: usize) -> &Self::Output { &() }
}
impl core::ops::IndexMut for StructMut {
fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut () }
}
fn test() {
Struct[0];
// ^^^^^^ adjustments: Borrow(Ref(Not))
StructMut[0];
// ^^^^^^^^^ adjustments: Borrow(Ref(Not))
&mut StructMut[0];
// ^^^^^^^^^ adjustments: Borrow(Ref(Mut))
}",
);
}

View File

@ -264,7 +264,7 @@ fn adjustment_hints() {
check_with_config( check_with_config(
InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG }, InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
r#" r#"
//- minicore: coerce_unsized, fn, eq //- minicore: coerce_unsized, fn, eq, index
fn main() { fn main() {
let _: u32 = loop {}; let _: u32 = loop {};
//^^^^^^^<never-to-any> //^^^^^^^<never-to-any>
@ -360,6 +360,19 @@ fn main() {
(()) == {()}; (()) == {()};
// ^^& // ^^&
// ^^^^& // ^^^^&
let closure: dyn Fn = || ();
closure();
//^^^^^^^(
//^^^^^^^&
//^^^^^^^)
Struct[0];
//^^^^^^(
//^^^^^^&
//^^^^^^)
&mut Struct[0];
//^^^^^^(
//^^^^^^&mut $
//^^^^^^)
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -369,8 +382,13 @@ fn consume(self) {}
fn by_ref(&self) {} fn by_ref(&self) {}
fn by_ref_mut(&mut self) {} fn by_ref_mut(&mut self) {}
} }
struct StructMut;
impl core::ops::Index<usize> for Struct {
type Output = ();
}
impl core::ops::IndexMut for Struct {}
"#, "#,
) );
} }
#[test] #[test]
@ -382,7 +400,7 @@ fn adjustment_hints_postfix() {
..DISABLED_CONFIG ..DISABLED_CONFIG
}, },
r#" r#"
//- minicore: coerce_unsized, fn, eq //- minicore: coerce_unsized, fn, eq, index
fn main() { fn main() {
Struct.consume(); Struct.consume();
@ -457,6 +475,13 @@ fn main() {
(()) == {()}; (()) == {()};
// ^^.& // ^^.&
// ^^^^.& // ^^^^.&
let closure: dyn Fn = || ();
closure();
//^^^^^^^.&
Struct[0];
//^^^^^^.&
&mut Struct[0];
//^^^^^^.&mut
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -466,6 +491,11 @@ fn consume(self) {}
fn by_ref(&self) {} fn by_ref(&self) {}
fn by_ref_mut(&mut self) {} fn by_ref_mut(&mut self) {}
} }
struct StructMut;
impl core::ops::Index<usize> for Struct {
type Output = ();
}
impl core::ops::IndexMut for Struct {}
"#, "#,
); );
} }