diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index a17984bbe41..a04b0a7ef61 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1128,26 +1128,20 @@ struct HasTypeFlagsVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { type BreakTy = FoundFlags; fn tcx_for_anon_const_substs(&self) -> Option> { - self.tcx + bug!("we shouldn't call this method as we manually look at ct substs"); } #[inline] fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { - debug!( - "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", - t, - t.flags(), - self.flags - ); - if t.flags().intersects(self.flags) { + let flags = t.flags(); + debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags); + if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) - } else if t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) - && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) - && self.tcx.is_some() - { - t.super_visit_with(self) } else { - ControlFlow::CONTINUE + match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, t), + _ => ControlFlow::CONTINUE, + } } } @@ -1168,13 +1162,11 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) - } else if flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) - && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) - && self.tcx.is_some() - { - c.super_visit_with(self) } else { - ControlFlow::CONTINUE + match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, c), + _ => ControlFlow::CONTINUE, + } } } @@ -1184,11 +1176,76 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags); if flags.intersects(self.flags) { ControlFlow::Break(FoundFlags) - } else if flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) - && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) - && self.tcx.is_some() - { - uv.super_visit_with(self) + } else { + match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, uv), + _ => ControlFlow::CONTINUE, + } + } + } + + #[inline] + fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { + let flags = predicate.inner.flags; + debug!( + "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}", + predicate, flags, self.flags + ); + if flags.intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, predicate), + _ => ControlFlow::CONTINUE, + } + } + } +} + +struct UnknownConstSubstsVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + flags: ty::TypeFlags, +} + +impl<'tcx> UnknownConstSubstsVisitor<'tcx> { + /// This is fairly cold and we don't want to + /// bloat the size of the `HasTypeFlagsVisitor`. + #[inline(never)] + pub fn search>( + visitor: &HasTypeFlagsVisitor<'tcx>, + v: T, + ) -> ControlFlow { + if visitor.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) { + v.super_visit_with(&mut UnknownConstSubstsVisitor { + tcx: visitor.tcx.unwrap(), + flags: visitor.flags, + }) + } else { + ControlFlow::CONTINUE + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for UnknownConstSubstsVisitor<'tcx> { + type BreakTy = FoundFlags; + fn tcx_for_anon_const_substs(&self) -> Option> { + bug!("we shouldn't call this method as we manually look at ct substs"); + } + + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { + if t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { + t.super_visit_with(self) + } else { + ControlFlow::CONTINUE + } + } + + #[inline] + fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow { + if uv.substs_.is_none() { + self.tcx + .default_anon_const_substs(uv.def.did) + .visit_with(&mut HasTypeFlagsVisitor { tcx: Some(self.tcx), flags: self.flags }) } else { ControlFlow::CONTINUE } @@ -1196,16 +1253,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { #[inline] fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow { - debug!( - "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", - predicate, predicate.inner.flags, self.flags - ); - if predicate.inner.flags.intersects(self.flags) { - ControlFlow::Break(FoundFlags) - } else if predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) - && self.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) - && self.tcx.is_some() - { + if predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { predicate.super_visit_with(self) } else { ControlFlow::CONTINUE