fix: Add missing autoborrow adjustment for index expressions
This commit is contained in:
parent
bea1c71f83
commit
798990bf33
@ -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))
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
@ -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))
|
||||||
|
}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -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 {}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user