11//! Finds if an expression is an immutable context or a mutable context, which is used in selecting
22//! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar.
33
4- use chalk_ir:: Mutability ;
4+ use chalk_ir:: { cast :: Cast , Mutability } ;
55use hir_def:: {
66 hir:: { Array , BinaryOp , BindingAnnotation , Expr , ExprId , PatId , Statement , UnaryOp } ,
77 lang_item:: LangItem ,
88} ;
99use hir_expand:: name:: Name ;
1010use intern:: sym;
1111
12- use crate :: { lower:: lower_to_chalk_mutability, Adjust , Adjustment , AutoBorrow , OverloadedDeref } ;
12+ use crate :: {
13+ infer:: Expectation , lower:: lower_to_chalk_mutability, Adjust , Adjustment , AutoBorrow , Interner ,
14+ OverloadedDeref , TyBuilder , TyKind ,
15+ } ;
1316
1417use super :: InferenceContext ;
1518
@@ -101,7 +104,7 @@ impl InferenceContext<'_> {
101104 Expr :: RecordLit { path : _, fields, spread, ellipsis : _, is_assignee_expr : _ } => {
102105 self . infer_mut_not_expr_iter ( fields. iter ( ) . map ( |it| it. expr ) . chain ( * spread) )
103106 }
104- & Expr :: Index { base, index, is_assignee_expr : _ } => {
107+ & Expr :: Index { base, index, is_assignee_expr } => {
105108 if mutability == Mutability :: Mut {
106109 if let Some ( ( f, _) ) = self . result . method_resolutions . get_mut ( & tgt_expr) {
107110 if let Some ( index_trait) = self
@@ -115,18 +118,40 @@ impl InferenceContext<'_> {
115118 . method_by_name ( & Name :: new_symbol_root ( sym:: index_mut. clone ( ) ) )
116119 {
117120 * f = index_fn;
121+ let mut base_ty = None ;
118122 let base_adjustments = self
119123 . result
120124 . expr_adjustments
121125 . get_mut ( & base)
122126 . and_then ( |it| it. last_mut ( ) ) ;
123127 if let Some ( Adjustment {
124128 kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutability) ) ,
125- ..
129+ target ,
126130 } ) = base_adjustments
127131 {
132+ // For assignee exprs `IndexMut` obiligations are already applied
133+ if !is_assignee_expr {
134+ if let TyKind :: Ref ( _, _, ty) = target. kind ( Interner ) {
135+ base_ty = Some ( ty. clone ( ) ) ;
136+ }
137+ }
128138 * mutability = Mutability :: Mut ;
129139 }
140+
141+ // Apply `IndexMut` obligation for non-assignee expr
142+ if let Some ( base_ty) = base_ty {
143+ let index_ty =
144+ if let Some ( ty) = self . result . type_of_expr . get ( index) {
145+ ty. clone ( )
146+ } else {
147+ self . infer_expr ( index, & Expectation :: none ( ) )
148+ } ;
149+ let trait_ref = TyBuilder :: trait_ref ( self . db , index_trait)
150+ . push ( base_ty)
151+ . fill ( |_| index_ty. clone ( ) . cast ( Interner ) )
152+ . build ( ) ;
153+ self . push_obligation ( trait_ref. cast ( Interner ) ) ;
154+ }
130155 }
131156 }
132157 }
0 commit comments