fix: try obligation of IndexMut when infer

This commit is contained in:
austaras 2023-12-11 16:26:27 +08:00
parent 3ab1666370
commit 1b7968a2cb
8 changed files with 74 additions and 12 deletions

View file

@ -622,7 +622,8 @@ impl ExprCollector<'_> {
ast::Expr::IndexExpr(e) => { ast::Expr::IndexExpr(e) => {
let base = self.collect_expr_opt(e.base()); let base = self.collect_expr_opt(e.base());
let index = self.collect_expr_opt(e.index()); let index = self.collect_expr_opt(e.index());
self.alloc_expr(Expr::Index { base, index }, syntax_ptr) let is_assignee_expr = self.is_lowering_assignee_expr;
self.alloc_expr(Expr::Index { base, index, is_assignee_expr }, syntax_ptr)
} }
ast::Expr::RangeExpr(e) => { ast::Expr::RangeExpr(e) => {
let lhs = e.start().map(|lhs| self.collect_expr(lhs)); let lhs = e.start().map(|lhs| self.collect_expr(lhs));

View file

@ -376,7 +376,7 @@ impl Printer<'_> {
w!(self, ") "); w!(self, ") ");
} }
} }
Expr::Index { base, index } => { Expr::Index { base, index, is_assignee_expr: _ } => {
self.print_expr(*base); self.print_expr(*base);
w!(self, "["); w!(self, "[");
self.print_expr(*index); self.print_expr(*index);

View file

@ -265,6 +265,7 @@ pub enum Expr {
Index { Index {
base: ExprId, base: ExprId,
index: ExprId, index: ExprId,
is_assignee_expr: bool,
}, },
Closure { Closure {
args: Box<[PatId]>, args: Box<[PatId]>,
@ -432,7 +433,7 @@ impl Expr {
f(rhs); f(rhs);
} }
} }
Expr::Index { base, index } => { Expr::Index { base, index, .. } => {
f(*base); f(*base);
f(*index); f(*index);
} }

View file

@ -598,7 +598,7 @@ impl InferenceContext<'_> {
self.consume_expr(expr); self.consume_expr(expr);
} }
} }
Expr::Index { base, index } => { Expr::Index { base, index, is_assignee_expr: _ } => {
self.select_from_expr(*base); self.select_from_expr(*base);
self.consume_expr(*index); self.consume_expr(*index);
} }

View file

@ -744,7 +744,7 @@ impl InferenceContext<'_> {
(RangeOp::Inclusive, _, None) => self.err_ty(), (RangeOp::Inclusive, _, None) => self.err_ty(),
} }
} }
Expr::Index { base, index } => { Expr::Index { base, index, is_assignee_expr } => {
let base_ty = self.infer_expr_inner(*base, &Expectation::none()); let base_ty = self.infer_expr_inner(*base, &Expectation::none());
let index_ty = self.infer_expr(*index, &Expectation::none()); let index_ty = self.infer_expr(*index, &Expectation::none());
@ -772,11 +772,24 @@ impl InferenceContext<'_> {
.build(); .build();
self.write_method_resolution(tgt_expr, func, substs); self.write_method_resolution(tgt_expr, func, substs);
} }
self.resolve_associated_type_with_params( let assoc = self.resolve_ops_index_output();
self_ty, let res = self.resolve_associated_type_with_params(
self.resolve_ops_index_output(), self_ty.clone(),
&[index_ty.cast(Interner)], assoc,
) &[index_ty.clone().cast(Interner)],
);
if *is_assignee_expr {
if let Some(index_trait) = self.resolve_lang_trait(LangItem::IndexMut) {
let trait_ref = TyBuilder::trait_ref(self.db, index_trait)
.push(self_ty)
.fill(|_| index_ty.clone().cast(Interner))
.build();
self.push_obligation(trait_ref.cast(Interner));
}
}
res
} else { } else {
self.err_ty() self.err_ty()
} }

View file

@ -96,7 +96,7 @@ impl InferenceContext<'_> {
Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => { Expr::RecordLit { path: _, fields, spread, ellipsis: _, is_assignee_expr: _ } => {
self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread)) self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr).chain(*spread))
} }
&Expr::Index { base, index } => { &Expr::Index { base, index, is_assignee_expr: _ } => {
if mutability == Mutability::Mut { if mutability == Mutability::Mut {
if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) {
if let Some(index_trait) = self if let Some(index_trait) = self

View file

@ -218,7 +218,7 @@ impl MirLowerCtx<'_> {
self.push_field_projection(&mut r, expr_id)?; self.push_field_projection(&mut r, expr_id)?;
Ok(Some((r, current))) Ok(Some((r, current)))
} }
Expr::Index { base, index } => { Expr::Index { base, index, is_assignee_expr: _ } => {
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()

View file

@ -4506,3 +4506,50 @@ fn ttt() {
"#, "#,
); );
} }
#[test]
fn infer_borrow() {
check_types(
r#"
//- minicore: index
pub struct SomeMap<K>;
pub trait Borrow<Borrowed: ?Sized> {
fn borrow(&self) -> &Borrowed;
}
impl<T: ?Sized> Borrow<T> for T {
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized> Borrow<T> for &T {
fn borrow(&self) -> &T {
&**self
}
}
impl<K, KB: Borrow<K>> core::ops::Index<KB> for SomeMap<K> {
type Output = ();
fn index(&self, _: KB) -> &() {
&()
}
}
impl<K> core::ops::IndexMut<K> for SomeMap<K> {
fn index_mut(&mut self, _: K) -> &mut () {
&mut ()
}
}
fn foo() {
let mut map = SomeMap;
map["a"] = ();
map;
//^^^ SomeMap<&str>
}
"#,
);
}