diff options
| author | bors <bors@rust-lang.org> | 2018-11-10 09:38:10 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-11-10 09:38:10 +0000 |
| commit | 4cd3294a1d0c5b34020ac35cf7cc00044f7c3b19 (patch) | |
| tree | 564530c64dc26c9e033d79e216e7dc62a08719ab | |
| parent | 0366ccafa6f1740acc9c26797e08d7691d835393 (diff) | |
| parent | 1bbaa553416b67fd2de472829f465ca0b24186a2 (diff) | |
Auto merge of #55637 - pnkfelix:issue-55552-dont-attempt-to-ascribe-projections-out-of-a-ty-var, r=nikomatsakis
Do not attempt to ascribe projections out of a ty var If we encounter `_` ascribed to structural pattern like `(a, b)`, just skip relate_types. Fix #55552
| -rw-r--r-- | src/librustc/mir/tcx.rs | 19 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/type_check/mod.rs | 35 | ||||
| -rw-r--r-- | src/librustc_traits/type_op.rs | 30 | ||||
| -rw-r--r-- | src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs | 31 |
4 files changed, 93 insertions, 22 deletions
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 4b53235eab4..f773f46b6f5 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<Ty<'tcx>, ()> { 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<V, T>(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<V, T, E>( + self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + elem: &ProjectionElem<'tcx, V, T>, + mut handle_field: impl FnMut(&Self, &Field, &T) -> Result<Ty<'tcx>, E>) + -> Result<PlaceTy<'tcx>, 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 734ddbc3ab9..a057f2f45c0 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1021,20 +1021,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<PlaceTy, HitTyVar>; + + 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 2ed02a4cdab..e635bc9efc4 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<PlaceTy, HitTyVar>; + 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, 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 00000000000..6d91fd3508a --- /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<A, B, RA, RB>(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); +} |
