1
1
//! Finds if an expression is an immutable context or a mutable context, which is used in selecting
2
2
//! between `Deref` and `DerefMut` or `Index` and `IndexMut` or similar.
3
3
4
- use chalk_ir:: Mutability ;
4
+ use chalk_ir:: { cast :: Cast , Mutability } ;
5
5
use hir_def:: {
6
6
hir:: { Array , BinaryOp , BindingAnnotation , Expr , ExprId , PatId , Statement , UnaryOp } ,
7
7
lang_item:: LangItem ,
8
8
} ;
9
9
use hir_expand:: name:: Name ;
10
10
use intern:: sym;
11
11
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
+ } ;
13
16
14
17
use super :: InferenceContext ;
15
18
@@ -101,7 +104,7 @@ impl InferenceContext<'_> {
101
104
Expr :: RecordLit { path : _, fields, spread, ellipsis : _, is_assignee_expr : _ } => {
102
105
self . infer_mut_not_expr_iter ( fields. iter ( ) . map ( |it| it. expr ) . chain ( * spread) )
103
106
}
104
- & Expr :: Index { base, index, is_assignee_expr : _ } => {
107
+ & Expr :: Index { base, index, is_assignee_expr } => {
105
108
if mutability == Mutability :: Mut {
106
109
if let Some ( ( f, _) ) = self . result . method_resolutions . get_mut ( & tgt_expr) {
107
110
if let Some ( index_trait) = self
@@ -115,18 +118,40 @@ impl InferenceContext<'_> {
115
118
. method_by_name ( & Name :: new_symbol_root ( sym:: index_mut. clone ( ) ) )
116
119
{
117
120
* f = index_fn;
121
+ let mut base_ty = None ;
118
122
let base_adjustments = self
119
123
. result
120
124
. expr_adjustments
121
125
. get_mut ( & base)
122
126
. and_then ( |it| it. last_mut ( ) ) ;
123
127
if let Some ( Adjustment {
124
128
kind : Adjust :: Borrow ( AutoBorrow :: Ref ( mutability) ) ,
125
- ..
129
+ target ,
126
130
} ) = base_adjustments
127
131
{
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
+ }
128
138
* mutability = Mutability :: Mut ;
129
139
}
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
+ }
130
155
}
131
156
}
132
157
}
0 commit comments