diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs index 5a9887e4af4..a54d977a517 100644 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -280,6 +280,8 @@ struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { indices: FxHashMap, BoundVar>, canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode, needs_canonical_flags: TypeFlags, + + binder_index: ty::DebruijnIndex, } impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { @@ -287,11 +289,23 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> self.tcx } + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + where T: TypeFoldable<'tcx> + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(..) => { - // leave bound regions alone - r + ty::ReLateBound(index, ..) => { + if index >= self.binder_index { + bug!("escaping late bound region during canonicalization") + } else { + r + } } ty::ReVar(vid) => { @@ -337,8 +351,12 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> bug!("encountered a fresh type during canonicalization") } - ty::Bound(_) => { - bug!("encountered a bound type during canonicalization") + ty::Bound(bound_ty) => { + if bound_ty.index >= self.binder_index { + bug!("escaping bound type during canonicalization") + } else { + t + } } ty::Closure(..) @@ -422,6 +440,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { variables: SmallVec::new(), query_state, indices: FxHashMap::default(), + binder_index: ty::INNERMOST, }; let out_value = value.fold_with(&mut canonicalizer); @@ -567,7 +586,7 @@ impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { kind: CanonicalVarKind::Ty(ty_kind), }; let var = self.canonical_var(info, ty_var.into()); - self.tcx().mk_ty(ty::Bound(BoundTy::new(ty::INNERMOST, var))) + self.tcx().mk_ty(ty::Bound(BoundTy::new(self.binder_index, var))) } } } diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 6e17eabdbb7..06e97a71ce5 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -433,6 +433,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { UnpackedKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... if let ty::Bound(b) = result_value.sty { + assert_eq!(b.index, ty::INNERMOST); // in which case we would set `canonical_vars[0]` to `Some(?U)`. opt_values[b.var] = Some(*original_value); } diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs index 80a2497bbf6..5b2e758d816 100644 --- a/src/librustc/infer/canonical/substitute.rs +++ b/src/librustc/infer/canonical/substitute.rs @@ -69,13 +69,18 @@ where } else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { value.clone() } else { - value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values }) + value.fold_with(&mut CanonicalVarValuesSubst { + tcx, + var_values, + binder_index: ty::INNERMOST, + }) } } struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> { tcx: TyCtxt<'cx, 'gcx, 'tcx>, var_values: &'cx CanonicalVarValues<'tcx>, + binder_index: ty::DebruijnIndex, } impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> { @@ -83,12 +88,29 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'g self.tcx } + fn fold_binder(&mut self, t: &ty::Binder) -> ty::Binder + where T: TypeFoldable<'tcx> + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { match t.sty { ty::Bound(b) => { - match self.var_values.var_values[b.var].unpack() { - UnpackedKind::Type(ty) => ty, - r => bug!("{:?} is a type but value is {:?}", b, r), + if b.index == self.binder_index { + match self.var_values.var_values[b.var].unpack() { + UnpackedKind::Type(ty) => ty::fold::shift_vars( + self.tcx, + self.binder_index.index() as u32, + &ty + ), + r => bug!("{:?} is a type but value is {:?}", b, r), + } + } else { + t } } _ => { diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index fd26b263efb..6bdbeb8f604 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -556,7 +556,10 @@ impl CanonicalUserSubsts<'tcx> { self.value.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { UnpackedKind::Type(ty) => match ty.sty { - ty::Bound(ref b) => cvar == b.var, + ty::Bound(ref b) => { + assert_eq!(b.index, ty::INNERMOST); + cvar == b.var + } _ => false, },