Skip to content

Commit 70622db

Browse files
authored
Rollup merge of #72280 - nbdd0121:typeck, r=nikomatsakis
Fix up autoderef when reborrowing Currently `(f)()` and `f.call_mut()` behaves differently if expression `f` contains autoderef in it. This causes a weird error in #72225. When `f` is type checked, `Deref` is used (this is expected as we can't yet determine if we should use `Fn` or `FnMut`). When subsequently we determine the actual trait to be used, when using the `f.call_mut()` syntax the `Deref` is patched to `DerefMut`, while for the `(f)()` syntax case it is not. This PR replicates the fixup for the first case. Fixes #72225 Fixes #68590
2 parents 63b441a + 2b7d858 commit 70622db

File tree

10 files changed

+467
-392
lines changed

10 files changed

+467
-392
lines changed

src/librustc_typeck/check/autoderef.rs

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::method::MethodCallee;
2-
use super::{FnCtxt, Needs, PlaceOp};
2+
use super::{FnCtxt, PlaceOp};
33

44
use rustc_errors::struct_span_err;
55
use rustc_hir as hir;
@@ -170,14 +170,13 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
170170
}
171171

172172
/// Returns the adjustment steps.
173-
pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>, needs: Needs) -> Vec<Adjustment<'tcx>> {
174-
fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
173+
pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
174+
fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx))
175175
}
176176

177177
pub fn adjust_steps_as_infer_ok(
178178
&self,
179179
fcx: &FnCtxt<'a, 'tcx>,
180-
needs: Needs,
181180
) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
182181
let mut obligations = vec![];
183182
let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.cur_ty));
@@ -186,7 +185,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
186185
.iter()
187186
.map(|&(source, kind)| {
188187
if let AutoderefKind::Overloaded = kind {
189-
fcx.try_overloaded_deref(self.span, source, needs).and_then(
188+
fcx.try_overloaded_deref(self.span, source).and_then(
190189
|InferOk { value: method, obligations: o }| {
191190
obligations.extend(o);
192191
if let ty::Ref(region, _, mutbl) = method.sig.output().kind {
@@ -266,8 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
266265
&self,
267266
span: Span,
268267
base_ty: Ty<'tcx>,
269-
needs: Needs,
270268
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
271-
self.try_overloaded_place_op(span, base_ty, &[], needs, PlaceOp::Deref)
269+
self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
272270
}
273271
}

src/librustc_typeck/check/callee.rs

+26-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::autoderef::Autoderef;
22
use super::method::MethodCallee;
3-
use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag};
3+
use super::{Expectation, FnCtxt, TupleArgumentsFlag};
44
use crate::type_error_struct;
55

66
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
@@ -115,7 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
115115
// If the callee is a bare function or a closure, then we're all set.
116116
match adjusted_ty.kind {
117117
ty::FnDef(..) | ty::FnPtr(_) => {
118-
let adjustments = autoderef.adjust_steps(self, Needs::None);
118+
let adjustments = autoderef.adjust_steps(self);
119119
self.apply_adjustments(callee_expr, adjustments);
120120
return Some(CallStep::Builtin(adjusted_ty));
121121
}
@@ -135,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
135135
&closure_sig,
136136
)
137137
.0;
138-
let adjustments = autoderef.adjust_steps(self, Needs::None);
138+
let adjustments = autoderef.adjust_steps(self);
139139
self.record_deferred_call_resolution(
140140
def_id,
141141
DeferredCallResolution {
@@ -176,7 +176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
176176
self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs))
177177
.or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None))
178178
.map(|(autoref, method)| {
179-
let mut adjustments = autoderef.adjust_steps(self, Needs::None);
179+
let mut adjustments = autoderef.adjust_steps(self);
180180
adjustments.extend(autoref);
181181
self.apply_adjustments(callee_expr, adjustments);
182182
CallStep::Overloaded(method)
@@ -220,21 +220,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
220220
let method = self.register_infer_ok_obligations(ok);
221221
let mut autoref = None;
222222
if borrow {
223-
if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
224-
let mutbl = match mutbl {
225-
hir::Mutability::Not => AutoBorrowMutability::Not,
226-
hir::Mutability::Mut => AutoBorrowMutability::Mut {
227-
// For initial two-phase borrow
228-
// deployment, conservatively omit
229-
// overloaded function call ops.
230-
allow_two_phase_borrow: AllowTwoPhase::No,
231-
},
232-
};
233-
autoref = Some(Adjustment {
234-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
235-
target: method.sig.inputs()[0],
236-
});
237-
}
223+
// Check for &self vs &mut self in the method signature. Since this is either
224+
// the Fn or FnMut trait, it should be one of those.
225+
let (region, mutbl) = if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind
226+
{
227+
(r, mutbl)
228+
} else {
229+
span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
230+
};
231+
232+
let mutbl = match mutbl {
233+
hir::Mutability::Not => AutoBorrowMutability::Not,
234+
hir::Mutability::Mut => AutoBorrowMutability::Mut {
235+
// For initial two-phase borrow
236+
// deployment, conservatively omit
237+
// overloaded function call ops.
238+
allow_two_phase_borrow: AllowTwoPhase::No,
239+
},
240+
};
241+
autoref = Some(Adjustment {
242+
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
243+
target: method.sig.inputs()[0],
244+
});
238245
}
239246
return Some((autoref, method));
240247
}

src/librustc_typeck/check/coercion.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
//! we may want to adjust precisely when coercions occur.
5252
5353
use crate::astconv::AstConv;
54-
use crate::check::{FnCtxt, Needs};
54+
use crate::check::FnCtxt;
5555
use rustc_errors::{struct_span_err, DiagnosticBuilder};
5656
use rustc_hir as hir;
5757
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -421,9 +421,8 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
421421
return success(vec![], ty, obligations);
422422
}
423423

424-
let needs = Needs::maybe_mut_place(mutbl_b);
425424
let InferOk { value: mut adjustments, obligations: o } =
426-
autoderef.adjust_steps_as_infer_ok(self, needs);
425+
autoderef.adjust_steps_as_infer_ok(self);
427426
obligations.extend(o);
428427
obligations.extend(autoderef.into_obligations());
429428

src/librustc_typeck/check/expr.rs

+30-57
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ use rustc_hir::{ExprKind, QPath};
2929
use rustc_infer::infer;
3030
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
3131
use rustc_middle::ty;
32-
use rustc_middle::ty::adjustment::{
33-
Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
34-
};
32+
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
3533
use rustc_middle::ty::Ty;
3634
use rustc_middle::ty::TypeFoldable;
3735
use rustc_middle::ty::{AdtKind, Visibility};
@@ -113,12 +111,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
113111
self.check_expr_with_expectation(expr, ExpectHasType(expected))
114112
}
115113

116-
pub(super) fn check_expr_with_expectation(
114+
fn check_expr_with_expectation_and_needs(
117115
&self,
118116
expr: &'tcx hir::Expr<'tcx>,
119117
expected: Expectation<'tcx>,
118+
needs: Needs,
120119
) -> Ty<'tcx> {
121-
self.check_expr_with_expectation_and_needs(expr, expected, Needs::None)
120+
let ty = self.check_expr_with_expectation(expr, expected);
121+
122+
// If the expression is used in a place whether mutable place is required
123+
// e.g. LHS of assignment, perform the conversion.
124+
if let Needs::MutPlace = needs {
125+
self.convert_place_derefs_to_mutable(expr);
126+
}
127+
128+
ty
122129
}
123130

124131
pub(super) fn check_expr(&self, expr: &'tcx hir::Expr<'tcx>) -> Ty<'tcx> {
@@ -143,11 +150,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
143150
/// Note that inspecting a type's structure *directly* may expose the fact
144151
/// that there are actually multiple representations for `Error`, so avoid
145152
/// that when err needs to be handled differently.
146-
fn check_expr_with_expectation_and_needs(
153+
pub(super) fn check_expr_with_expectation(
147154
&self,
148155
expr: &'tcx hir::Expr<'tcx>,
149156
expected: Expectation<'tcx>,
150-
needs: Needs,
151157
) -> Ty<'tcx> {
152158
debug!(">> type-checking: expr={:?} expected={:?}", expr, expected);
153159

@@ -171,7 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
171177
let old_diverges = self.diverges.replace(Diverges::Maybe);
172178
let old_has_errors = self.has_errors.replace(false);
173179

174-
let ty = self.check_expr_kind(expr, expected, needs);
180+
let ty = self.check_expr_kind(expr, expected);
175181

176182
// Warn for non-block expressions with diverging children.
177183
match expr.kind {
@@ -213,9 +219,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
213219
&self,
214220
expr: &'tcx hir::Expr<'tcx>,
215221
expected: Expectation<'tcx>,
216-
needs: Needs,
217222
) -> Ty<'tcx> {
218-
debug!("check_expr_kind(expr={:?}, expected={:?}, needs={:?})", expr, expected, needs,);
223+
debug!("check_expr_kind(expr={:?}, expected={:?})", expr, expected);
219224

220225
let tcx = self.tcx;
221226
match expr.kind {
@@ -226,9 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
226231
self.check_expr_assign(expr, expected, lhs, rhs, span)
227232
}
228233
ExprKind::AssignOp(op, ref lhs, ref rhs) => self.check_binop_assign(expr, op, lhs, rhs),
229-
ExprKind::Unary(unop, ref oprnd) => {
230-
self.check_expr_unary(unop, oprnd, expected, needs, expr)
231-
}
234+
ExprKind::Unary(unop, ref oprnd) => self.check_expr_unary(unop, oprnd, expected, expr),
232235
ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
233236
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
234237
}
@@ -264,7 +267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
264267
ExprKind::Block(ref body, _) => self.check_block_with_expected(&body, expected),
265268
ExprKind::Call(ref callee, ref args) => self.check_call(expr, &callee, args, expected),
266269
ExprKind::MethodCall(ref segment, span, ref args, _) => {
267-
self.check_method_call(expr, segment, span, args, expected, needs)
270+
self.check_method_call(expr, segment, span, args, expected)
268271
}
269272
ExprKind::Cast(ref e, ref t) => self.check_expr_cast(e, t, expr),
270273
ExprKind::Type(ref e, ref t) => {
@@ -281,8 +284,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
281284
ExprKind::Struct(ref qpath, fields, ref base_expr) => {
282285
self.check_expr_struct(expr, expected, qpath, fields, base_expr)
283286
}
284-
ExprKind::Field(ref base, field) => self.check_field(expr, needs, &base, field),
285-
ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, needs, expr),
287+
ExprKind::Field(ref base, field) => self.check_field(expr, &base, field),
288+
ExprKind::Index(ref base, ref idx) => self.check_expr_index(base, idx, expr),
286289
ExprKind::Yield(ref value, ref src) => self.check_expr_yield(value, expr, src),
287290
hir::ExprKind::Err => tcx.ty_error(),
288291
}
@@ -302,48 +305,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
302305
unop: hir::UnOp,
303306
oprnd: &'tcx hir::Expr<'tcx>,
304307
expected: Expectation<'tcx>,
305-
needs: Needs,
306308
expr: &'tcx hir::Expr<'tcx>,
307309
) -> Ty<'tcx> {
308310
let tcx = self.tcx;
309311
let expected_inner = match unop {
310312
hir::UnOp::UnNot | hir::UnOp::UnNeg => expected,
311313
hir::UnOp::UnDeref => NoExpectation,
312314
};
313-
let needs = match unop {
314-
hir::UnOp::UnDeref => needs,
315-
_ => Needs::None,
316-
};
317-
let mut oprnd_t = self.check_expr_with_expectation_and_needs(&oprnd, expected_inner, needs);
315+
let mut oprnd_t = self.check_expr_with_expectation(&oprnd, expected_inner);
318316

319317
if !oprnd_t.references_error() {
320318
oprnd_t = self.structurally_resolved_type(expr.span, oprnd_t);
321319
match unop {
322320
hir::UnOp::UnDeref => {
323-
if let Some(mt) = oprnd_t.builtin_deref(true) {
324-
oprnd_t = mt.ty;
325-
} else if let Some(ok) = self.try_overloaded_deref(expr.span, oprnd_t, needs) {
326-
let method = self.register_infer_ok_obligations(ok);
327-
if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind {
328-
let mutbl = match mutbl {
329-
hir::Mutability::Not => AutoBorrowMutability::Not,
330-
hir::Mutability::Mut => AutoBorrowMutability::Mut {
331-
// (It shouldn't actually matter for unary ops whether
332-
// we enable two-phase borrows or not, since a unary
333-
// op has no additional operands.)
334-
allow_two_phase_borrow: AllowTwoPhase::No,
335-
},
336-
};
337-
self.apply_adjustments(
338-
oprnd,
339-
vec![Adjustment {
340-
kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
341-
target: method.sig.inputs()[0],
342-
}],
343-
);
344-
}
345-
oprnd_t = self.make_overloaded_place_return_type(method).ty;
346-
self.write_method_call(expr.hir_id, method);
321+
if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) {
322+
oprnd_t = ty;
347323
} else {
348324
let mut err = type_error_struct!(
349325
tcx.sess,
@@ -405,8 +381,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
405381
_ => NoExpectation,
406382
}
407383
});
408-
let needs = Needs::maybe_mut_place(mutbl);
409-
let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs);
384+
let ty =
385+
self.check_expr_with_expectation_and_needs(&oprnd, hint, Needs::maybe_mut_place(mutbl));
410386

411387
let tm = ty::TypeAndMut { ty, mutbl };
412388
match kind {
@@ -861,10 +837,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
861837
span: Span,
862838
args: &'tcx [hir::Expr<'tcx>],
863839
expected: Expectation<'tcx>,
864-
needs: Needs,
865840
) -> Ty<'tcx> {
866841
let rcvr = &args[0];
867-
let rcvr_t = self.check_expr_with_needs(&rcvr, needs);
842+
let rcvr_t = self.check_expr(&rcvr);
868843
// no need to check for bot/err -- callee does that
869844
let rcvr_t = self.structurally_resolved_type(args[0].span, rcvr_t);
870845

@@ -1443,11 +1418,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14431418
fn check_field(
14441419
&self,
14451420
expr: &'tcx hir::Expr<'tcx>,
1446-
needs: Needs,
14471421
base: &'tcx hir::Expr<'tcx>,
14481422
field: Ident,
14491423
) -> Ty<'tcx> {
1450-
let expr_t = self.check_expr_with_needs(base, needs);
1424+
let expr_t = self.check_expr(base);
14511425
let expr_t = self.structurally_resolved_type(base.span, expr_t);
14521426
let mut private_candidate = None;
14531427
let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -1467,7 +1441,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14671441
// of error recovery.
14681442
self.write_field_index(expr.hir_id, index);
14691443
if field.vis.is_accessible_from(def_scope, self.tcx) {
1470-
let adjustments = autoderef.adjust_steps(self, needs);
1444+
let adjustments = autoderef.adjust_steps(self);
14711445
self.apply_adjustments(base, adjustments);
14721446
autoderef.finalize(self);
14731447

@@ -1482,7 +1456,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14821456
if let Ok(index) = fstr.parse::<usize>() {
14831457
if fstr == index.to_string() {
14841458
if let Some(field_ty) = tys.get(index) {
1485-
let adjustments = autoderef.adjust_steps(self, needs);
1459+
let adjustments = autoderef.adjust_steps(self);
14861460
self.apply_adjustments(base, adjustments);
14871461
autoderef.finalize(self);
14881462

@@ -1721,10 +1695,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17211695
&self,
17221696
base: &'tcx hir::Expr<'tcx>,
17231697
idx: &'tcx hir::Expr<'tcx>,
1724-
needs: Needs,
17251698
expr: &'tcx hir::Expr<'tcx>,
17261699
) -> Ty<'tcx> {
1727-
let base_t = self.check_expr_with_needs(&base, needs);
1700+
let base_t = self.check_expr(&base);
17281701
let idx_t = self.check_expr(&idx);
17291702

17301703
if base_t.references_error() {
@@ -1733,7 +1706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17331706
idx_t
17341707
} else {
17351708
let base_t = self.structurally_resolved_type(base.span, base_t);
1736-
match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
1709+
match self.lookup_indexing(expr, base, base_t, idx_t) {
17371710
Some((index_ty, element_ty)) => {
17381711
// two-phase not needed because index_ty is never mutable
17391712
self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);

0 commit comments

Comments
 (0)