|
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 |
|
@@ -115,17 +118,35 @@ 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 | {
|
128 | 132 | *mutability = Mutability::Mut;
|
| 133 | + if let TyKind::Ref(_, _, ty) = target.kind(Interner) { |
| 134 | + base_ty = Some(ty.clone()); |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + if let Some(base_ty) = base_ty { |
| 139 | + let index_ty = |
| 140 | + if let Some(ty) = self.result.type_of_expr.get(index) { |
| 141 | + ty.clone() |
| 142 | + } else { |
| 143 | + self.infer_expr(index, &Expectation::none()) |
| 144 | + }; |
| 145 | + let trait_ref = TyBuilder::trait_ref(self.db, index_trait) |
| 146 | + .push(base_ty) |
| 147 | + .fill(|_| index_ty.clone().cast(Interner)) |
| 148 | + .build(); |
| 149 | + self.push_obligation(trait_ref.cast(Interner)); |
129 | 150 | }
|
130 | 151 | }
|
131 | 152 | }
|
|
0 commit comments