From 2cfcc0c65c4642400305823994f0c6b021c4b53a Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 30 Jul 2020 21:14:15 +0100 Subject: [PATCH 1/2] Fix regionck failure when converting Index to IndexMut --- src/librustc_typeck/check/place_op.rs | 37 +++++++++++++++++---------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs index 12468750923..cb681c7b8f8 100644 --- a/src/librustc_typeck/check/place_op.rs +++ b/src/librustc_typeck/check/place_op.rs @@ -9,6 +9,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::autoderef::Autoderef; +use std::slice; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type-check `*oprnd_expr` with `oprnd_expr` type-checked already. @@ -245,19 +246,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } match expr.kind { - hir::ExprKind::Index(ref base_expr, ref index_expr) => { - // We need to get the final type in case dereferences were needed for the trait - // to apply (#72002). - let index_expr_ty = self.typeck_results.borrow().expr_ty_adjusted(index_expr); - self.convert_place_op_to_mutable( - PlaceOp::Index, - expr, - base_expr, - &[index_expr_ty], - ); + hir::ExprKind::Index(ref base_expr, ..) => { + self.convert_place_op_to_mutable(PlaceOp::Index, expr, base_expr); } hir::ExprKind::Unary(hir::UnOp::UnDeref, ref base_expr) => { - self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr, &[]); + self.convert_place_op_to_mutable(PlaceOp::Deref, expr, base_expr); } _ => {} } @@ -269,9 +262,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { op: PlaceOp, expr: &hir::Expr<'_>, base_expr: &hir::Expr<'_>, - arg_tys: &[Ty<'tcx>], ) { - debug!("convert_place_op_to_mutable({:?}, {:?}, {:?}, {:?})", op, expr, base_expr, arg_tys); + debug!("convert_place_op_to_mutable({:?}, {:?}, {:?})", op, expr, base_expr); if !self.typeck_results.borrow().is_method_call(expr) { debug!("convert_place_op_to_mutable - builtin, nothing to do"); return; @@ -286,6 +278,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .expect("place op takes something that is not a ref") .ty; + let arg_ty = match op { + PlaceOp::Deref => None, + PlaceOp::Index => { + // We would need to recover the `T` used when we resolve `<_ as Index>::index` + // in try_index_step. This is the subst at index 1. + // + // Note: we should *not* use `expr_ty` of index_expr here because autoderef + // during coercions can cause type of index_expr to differ from `T` (#72002). + // We also could not use `expr_ty_adjusted` of index_expr because reborrowing + // during coercions can also cause type of index_expr to differ from `T`, + // which can potentially cause regionck failure (#74933). + Some(self.typeck_results.borrow().node_substs(expr.hir_id).type_at(1)) + } + }; + let arg_tys = match arg_ty { + None => &[], + Some(ref ty) => slice::from_ref(ty), + }; + let method = self.try_mutable_overloaded_place_op(expr.span, base_ty, arg_tys, op); let method = match method { Some(ok) => self.register_infer_ok_obligations(ok), From 000f5cdd24be7067c3294e1fba2da4a3e88dd849 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 30 Jul 2020 21:54:18 +0100 Subject: [PATCH 2/2] Add UI test for issue 74933 --- src/test/ui/typeck/issue-74933.rs | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/ui/typeck/issue-74933.rs diff --git a/src/test/ui/typeck/issue-74933.rs b/src/test/ui/typeck/issue-74933.rs new file mode 100644 index 00000000000..4b6c173b8ce --- /dev/null +++ b/src/test/ui/typeck/issue-74933.rs @@ -0,0 +1,38 @@ +// check-pass +// +// rust-lang/rust#74933: Lifetime error when indexing with borrowed index + +use std::ops::{Index, IndexMut}; + +struct S(V); +struct K<'a>(&'a ()); +struct V; + +impl<'a> Index<&'a K<'a>> for S { + type Output = V; + + fn index(&self, _: &'a K<'a>) -> &V { + &self.0 + } +} + +impl<'a> IndexMut<&'a K<'a>> for S { + fn index_mut(&mut self, _: &'a K<'a>) -> &mut V { + &mut self.0 + } +} + +impl V { + fn foo(&mut self) {} +} + +fn test(s: &mut S, k: &K<'_>) { + s[k] = V; + s[k].foo(); +} + +fn main() { + let mut s = S(V); + let k = K(&()); + test(&mut s, &k); +}