From 09edfb885cd0288edadb6493e8ee933f912a55c6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 3 Nov 2018 01:53:57 +0100 Subject: [PATCH 1/2] If we encounter `_` ascribed to structural pattern like `(a, b)`, just skip relate_types. --- src/librustc/mir/tcx.rs | 19 +++++----- .../borrow_check/nll/type_check/mod.rs | 35 ++++++++++++++----- src/librustc_traits/type_op.rs | 30 ++++++++++++---- 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 473730c548990..6958719536694 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -80,7 +80,8 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { elem: &PlaceElem<'tcx>) -> PlaceTy<'tcx> { - self.projection_ty_core(tcx, elem, |_, _, ty| ty) + self.projection_ty_core(tcx, elem, |_, _, ty| -> Result, ()> { Ok(ty) }) + .unwrap() } /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })` @@ -88,11 +89,12 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { /// `Ty` or downcast variant corresponding to that projection. /// The `handle_field` callback must map a `Field` to its `Ty`, /// (which should be trivial when `T` = `Ty`). - pub fn projection_ty_core(self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - elem: &ProjectionElem<'tcx, V, T>, - mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>) - -> PlaceTy<'tcx> + pub fn projection_ty_core( + self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + elem: &ProjectionElem<'tcx, V, T>, + mut handle_field: impl FnMut(&Self, &Field, &T) -> Result, E>) + -> Result, E> where V: ::std::fmt::Debug, T: ::std::fmt::Debug { @@ -142,10 +144,11 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { bug!("cannot downcast non-ADT type: `{:?}`", self) } }, - ProjectionElem::Field(ref f, ref fty) => PlaceTy::Ty { ty: handle_field(&self, f, fty) } + ProjectionElem::Field(ref f, ref fty) => + PlaceTy::Ty { ty: handle_field(&self, f, fty)? }, }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); - answer + Ok(answer) } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 3098acffa23dc..f1ebddfd6d658 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -991,20 +991,39 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let v1 = ty::Contravariant.xform(v); let tcx = self.infcx.tcx; - let mut projected_ty = PlaceTy::from_ty(ty); + let ty = self.normalize(ty, locations); + + // We need to follow any provided projetions into the type. + // + // if we hit a ty var as we descend, then just skip the + // attempt to relate the mir local with any type. + #[derive(Debug)] struct HitTyVar; + let mut curr_projected_ty: Result; + + curr_projected_ty = Ok(PlaceTy::from_ty(ty)); for proj in &user_ty.projs { - projected_ty = projected_ty.projection_ty_core( + let projected_ty = if let Ok(projected_ty) = curr_projected_ty { + projected_ty + } else { + break; + }; + curr_projected_ty = projected_ty.projection_ty_core( tcx, proj, |this, field, &()| { - let ty = this.field_ty(tcx, field); - self.normalize(ty, locations) + if this.to_ty(tcx).is_ty_var() { + Err(HitTyVar) + } else { + let ty = this.field_ty(tcx, field); + Ok(self.normalize(ty, locations)) + } }); } debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", - user_ty.base, ty, user_ty.projs, projected_ty); + user_ty.base, ty, user_ty.projs, curr_projected_ty); - let ty = projected_ty.to_ty(tcx); - - self.relate_types(ty, v1, a, locations, category)?; + if let Ok(projected_ty) = curr_projected_ty { + let ty = projected_ty.to_ty(tcx); + self.relate_types(ty, v1, a, locations, category)?; + } } UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { let ( diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 2ed02a4cdab1e..e635bc9efc45c 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -151,17 +151,35 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); let ty = self.normalize(ty); - let mut projected_ty = PlaceTy::from_ty(ty); + // We need to follow any provided projetions into the type. + // + // if we hit a ty var as we descend, then just skip the + // attempt to relate the mir local with any type. + + struct HitTyVar; + let mut curr_projected_ty: Result; + curr_projected_ty = Ok(PlaceTy::from_ty(ty)); for proj in projs { - projected_ty = projected_ty.projection_ty_core( + let projected_ty = if let Ok(projected_ty) = curr_projected_ty { + projected_ty + } else { + break; + }; + curr_projected_ty = projected_ty.projection_ty_core( tcx, proj, |this, field, &()| { - let ty = this.field_ty(tcx, field); - self.normalize(ty) + if this.to_ty(tcx).is_ty_var() { + Err(HitTyVar) + } else { + let ty = this.field_ty(tcx, field); + Ok(self.normalize(ty)) + } }); } - let ty = projected_ty.to_ty(tcx); - self.relate(mir_ty, variance, ty)?; + if let Ok(projected_ty) = curr_projected_ty { + let ty = projected_ty.to_ty(tcx); + self.relate(mir_ty, variance, ty)?; + } if let Some(UserSelfTy { impl_def_id, From 1bbaa553416b67fd2de472829f465ca0b24186a2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 3 Nov 2018 02:03:04 +0100 Subject: [PATCH 2/2] Regression test for issue 55552. --- ...-ascribe-wildcard-to-structured-pattern.rs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs diff --git a/src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs b/src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs new file mode 100644 index 0000000000000..6d91fd3508a86 --- /dev/null +++ b/src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs @@ -0,0 +1,31 @@ +// compile-pass + +// rust-lang/rust#55552: The strategy pnkfelix landed in PR #55274 +// (for ensuring that NLL respects user-provided lifetime annotations) +// did not handle the case where the ascribed type has some expliit +// wildcards (`_`) mixed in, and it caused an internal compiler error +// (ICE). +// +// This test is just checking that we do not ICE when such things +// occur. + +struct X; +struct Y; +struct Z; + +struct Pair { x: X, y: Y } + +pub fn join(oper_a: A, oper_b: B) -> (RA, RB) +where A: FnOnce() -> RA + Send, + B: FnOnce() -> RB + Send, + RA: Send, + RB: Send +{ + (oper_a(), oper_b()) +} + +fn main() { + let ((_x, _y), _z): (_, Z) = join(|| (X, Y), || Z); + + let (Pair { x: _x, y: _y }, Z): (_, Z) = join(|| Pair { x: X, y: Y }, || Z); +}