1use hir_def::hir::{
5 Array, AsmOperand, BinaryOp, BindingAnnotation, Expr, ExprId, Pat, PatId, RecordSpread,
6 Statement, UnaryOp,
7};
8use rustc_ast_ir::Mutability;
9
10use crate::{
11 Adjust, AutoBorrow, OverloadedDeref,
12 infer::{InferenceContext, place_op::PlaceOp},
13 lower::lower_mutability,
14};
15
16impl<'db> InferenceContext<'db> {
17 pub(crate) fn infer_mut_body(&mut self, body_expr: ExprId) {
18 self.infer_mut_expr(body_expr, Mutability::Not);
19 }
20
21 fn infer_mut_expr(&mut self, tgt_expr: ExprId, mut mutability: Mutability) {
22 if let Some(adjustments) = self.result.expr_adjustments.get_mut(&tgt_expr) {
23 let mut adjustments = adjustments.iter_mut().rev().peekable();
24 while let Some(adj) = adjustments.next() {
25 match &mut adj.kind {
26 Adjust::NeverToAny | Adjust::Deref(None) | Adjust::Pointer(_) => (),
27 Adjust::Deref(Some(d)) => {
28 if mutability == Mutability::Mut {
29 let source_ty = match adjustments.peek() {
30 Some(prev_adj) => prev_adj.target.as_ref(),
31 None => self.result.type_of_expr[tgt_expr].as_ref(),
32 };
33 if let Some(infer_ok) = Self::try_mutable_overloaded_place_op(
34 &self.table,
35 tgt_expr,
36 source_ty,
37 None,
38 PlaceOp::Deref,
39 ) {
40 self.table.register_predicates(infer_ok.obligations);
41 }
42 *d = OverloadedDeref(mutability);
43 }
44 }
45 Adjust::Borrow(b) => match b {
46 AutoBorrow::Ref(m) => mutability = (*m).into(),
47 AutoBorrow::RawPtr(m) => mutability = *m,
48 },
49 }
50 }
51 }
52 self.infer_mut_expr_without_adjust(tgt_expr, mutability);
53 }
54
55 fn infer_mut_expr_without_adjust(&mut self, tgt_expr: ExprId, mutability: Mutability) {
56 match &self.store[tgt_expr] {
57 Expr::Missing => (),
58 Expr::InlineAsm(e) => {
59 e.operands.iter().for_each(|(_, op)| match op {
60 AsmOperand::In { expr, .. }
61 | AsmOperand::Out { expr: Some(expr), .. }
62 | AsmOperand::InOut { expr, .. } => {
63 self.infer_mut_expr_without_adjust(*expr, Mutability::Not)
64 }
65 AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
66 self.infer_mut_expr_without_adjust(*in_expr, Mutability::Not);
67 if let Some(out_expr) = out_expr {
68 self.infer_mut_expr_without_adjust(*out_expr, Mutability::Not);
69 }
70 }
71 AsmOperand::Out { expr: None, .. }
72 | AsmOperand::Label(_)
73 | AsmOperand::Sym(_)
74 | AsmOperand::Const(_) => (),
75 });
76 }
77 Expr::OffsetOf(_) => (),
78 &Expr::If { condition, then_branch, else_branch } => {
79 self.infer_mut_expr(condition, Mutability::Not);
80 self.infer_mut_expr(then_branch, Mutability::Not);
81 if let Some(else_branch) = else_branch {
82 self.infer_mut_expr(else_branch, Mutability::Not);
83 }
84 }
85 Expr::Const(id) => {
86 self.infer_mut_expr(*id, Mutability::Not);
87 }
88 Expr::Let { pat, expr } => self.infer_mut_expr(*expr, self.pat_bound_mutability(*pat)),
89 Expr::Block { id: _, statements, tail, label: _, unsafe_: _ } => {
90 for st in statements.iter() {
91 match st {
92 Statement::Let { pat, type_ref: _, initializer, else_branch } => {
93 if let Some(i) = initializer {
94 self.infer_mut_expr(*i, self.pat_bound_mutability(*pat));
95 }
96 if let Some(e) = else_branch {
97 self.infer_mut_expr(*e, Mutability::Not);
98 }
99 }
100 Statement::Expr { expr, has_semi: _ } => {
101 self.infer_mut_expr(*expr, Mutability::Not);
102 }
103 Statement::Item(_) => (),
104 }
105 }
106 if let Some(tail) = tail {
107 self.infer_mut_expr(*tail, Mutability::Not);
108 }
109 }
110 Expr::MethodCall { receiver: it, method_name: _, args, generic_args: _ }
111 | Expr::Call { callee: it, args } => {
112 self.infer_mut_not_expr_iter(args.iter().copied().chain(Some(*it)));
113 }
114 Expr::Match { expr, arms } => {
115 let m = self.pat_iter_bound_mutability(arms.iter().map(|it| it.pat));
116 self.infer_mut_expr(*expr, m);
117 for arm in arms.iter() {
118 self.infer_mut_expr(arm.expr, Mutability::Not);
119 if let Some(g) = arm.guard {
120 self.infer_mut_expr(g, Mutability::Not);
121 }
122 }
123 }
124 Expr::Yield { expr }
125 | Expr::Yeet { expr }
126 | Expr::Return { expr }
127 | Expr::Break { expr, label: _ } => {
128 if let &Some(expr) = expr {
129 self.infer_mut_expr(expr, Mutability::Not);
130 }
131 }
132 Expr::Become { expr } => {
133 self.infer_mut_expr(*expr, Mutability::Not);
134 }
135 Expr::RecordLit { path: _, fields, spread, .. } => {
136 self.infer_mut_not_expr_iter(fields.iter().map(|it| it.expr));
137 if let RecordSpread::Expr(expr) = *spread {
138 self.infer_mut_expr(expr, Mutability::Not);
139 }
140 }
141 &Expr::Index { base, index } => {
142 if mutability == Mutability::Mut {
143 self.convert_place_op_to_mutable(PlaceOp::Index, tgt_expr, base, Some(index));
144 }
145 self.infer_mut_expr(base, mutability);
146 self.infer_mut_expr(index, Mutability::Not);
147 }
148 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
149 if mutability == Mutability::Mut {
150 self.convert_place_op_to_mutable(PlaceOp::Deref, tgt_expr, *expr, None);
151 }
152 self.infer_mut_expr(*expr, mutability);
153 }
154 Expr::Field { expr, name: _ } => {
155 self.infer_mut_expr(*expr, mutability);
156 }
157 Expr::UnaryOp { expr, op: _ }
158 | Expr::Await { expr }
159 | Expr::Loop { body: expr, label: _, source: _ }
160 | Expr::Cast { expr, type_ref: _ } => {
161 self.infer_mut_expr(*expr, Mutability::Not);
162 }
163 Expr::Ref { expr, rawness: _, mutability } => {
164 let mutability = lower_mutability(*mutability);
165 self.infer_mut_expr(*expr, mutability);
166 }
167 Expr::BinaryOp { lhs, rhs, op: Some(BinaryOp::Assignment { .. }) } => {
168 self.infer_mut_expr(*lhs, Mutability::Mut);
169 self.infer_mut_expr(*rhs, Mutability::Not);
170 }
171 &Expr::Assignment { target, value } => {
172 self.store.walk_pats(target, &mut |pat| match self.store[pat] {
173 Pat::Expr(expr) => self.infer_mut_expr(expr, Mutability::Mut),
174 _ => {}
175 });
176 self.infer_mut_expr(value, Mutability::Not);
177 }
178 Expr::Array(Array::Repeat { initializer: lhs, repeat: rhs })
179 | Expr::BinaryOp { lhs, rhs, op: _ } => {
180 self.infer_mut_expr(*lhs, Mutability::Not);
181 self.infer_mut_expr(*rhs, Mutability::Not);
182 }
183 Expr::Closure { body, .. } => {
184 self.infer_mut_expr(*body, Mutability::Not);
185 }
186 Expr::Tuple { exprs } | Expr::Array(Array::ElementList { elements: exprs }) => {
187 self.infer_mut_not_expr_iter(exprs.iter().copied());
188 }
189 Expr::Literal(_)
191 | Expr::Path(_)
192 | Expr::Continue { .. }
193 | Expr::Underscore
194 | Expr::IncludeBytes => (),
195 }
196 }
197
198 fn infer_mut_not_expr_iter(&mut self, exprs: impl Iterator<Item = ExprId>) {
199 for expr in exprs {
200 self.infer_mut_expr(expr, Mutability::Not);
201 }
202 }
203
204 fn pat_iter_bound_mutability(&self, mut pat: impl Iterator<Item = PatId>) -> Mutability {
205 if pat.any(|p| self.pat_bound_mutability(p) == Mutability::Mut) {
206 Mutability::Mut
207 } else {
208 Mutability::Not
209 }
210 }
211
212 fn pat_bound_mutability(&self, pat: PatId) -> Mutability {
216 let mut r = Mutability::Not;
217 self.store.walk_bindings_in_pat(pat, |b| {
218 if self.store[b].mode == BindingAnnotation::RefMut {
219 r = Mutability::Mut;
220 }
221 });
222 r
223 }
224}