Auto merge of #79773 - lcnr:type-visitor, r=oli-obk
small `TypeVisitor` refactor cc `@LeSeulArtichaut` `@scottmcm` adds `ControlFlow::map_break`
This commit is contained in:
commit
b5ff9c3d05
@ -13,12 +13,13 @@ where
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
struct FoundParam;
|
||||
struct UsedParamsNeedSubstVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
|
||||
type BreakTy = ();
|
||||
type BreakTy = FoundParam;
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if !c.needs_subst() {
|
||||
@ -26,7 +27,7 @@ where
|
||||
}
|
||||
|
||||
match c.val {
|
||||
ty::ConstKind::Param(..) => ControlFlow::BREAK,
|
||||
ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
@ -37,7 +38,7 @@ where
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
ty::Param(_) => ControlFlow::BREAK,
|
||||
ty::Param(_) => ControlFlow::Break(FoundParam),
|
||||
ty::Closure(def_id, substs)
|
||||
| ty::Generator(def_id, substs, ..)
|
||||
| ty::FnDef(def_id, substs) => {
|
||||
@ -76,7 +77,7 @@ where
|
||||
}
|
||||
|
||||
let mut vis = UsedParamsNeedSubstVisitor { tcx };
|
||||
if ty.visit_with(&mut vis).is_break() {
|
||||
if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) {
|
||||
throw_inval!(TooGeneric);
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -462,39 +462,25 @@ pub(super) fn check_opaque<'tcx>(
|
||||
|
||||
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
|
||||
/// in "inheriting lifetimes".
|
||||
#[instrument(skip(tcx, span))]
|
||||
pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
span: Span,
|
||||
) {
|
||||
let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id));
|
||||
debug!(
|
||||
"check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}",
|
||||
def_id, span, item
|
||||
);
|
||||
debug!(?item, ?span);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ProhibitOpaqueVisitor<'tcx> {
|
||||
opaque_identity_ty: Ty<'tcx>,
|
||||
generics: &'tcx ty::Generics,
|
||||
}
|
||||
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
|
||||
type BreakTy = Option<Ty<'tcx>>;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
|
||||
if t != self.opaque_identity_ty && t.super_visit_with(self).is_break() {
|
||||
return ControlFlow::Break(Some(t));
|
||||
}
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
struct FoundParentLifetime;
|
||||
struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
|
||||
type BreakTy = FoundParentLifetime;
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
|
||||
debug!("FindParentLifetimeVisitor: r={:?}", r);
|
||||
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
|
||||
if *index < self.generics.parent_count as u32 {
|
||||
return ControlFlow::Break(None);
|
||||
if *index < self.0.parent_count as u32 {
|
||||
return ControlFlow::Break(FoundParentLifetime);
|
||||
} else {
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
@ -505,7 +491,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
if let ty::ConstKind::Unevaluated(..) = c.val {
|
||||
// FIXME(#72219) We currenctly don't detect lifetimes within substs
|
||||
// FIXME(#72219) We currently don't detect lifetimes within substs
|
||||
// which would violate this check. Even though the particular substitution is not used
|
||||
// within the const, this should still be fixed.
|
||||
return ControlFlow::CONTINUE;
|
||||
@ -514,6 +500,26 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ProhibitOpaqueVisitor<'tcx> {
|
||||
opaque_identity_ty: Ty<'tcx>,
|
||||
generics: &'tcx ty::Generics,
|
||||
}
|
||||
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
|
||||
type BreakTy = Ty<'tcx>;
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
|
||||
if t == self.opaque_identity_ty {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
|
||||
.map_break(|FoundParentLifetime| t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let ItemKind::OpaqueTy(hir::OpaqueTy {
|
||||
origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
|
||||
..
|
||||
@ -555,14 +561,12 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
|
||||
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) {
|
||||
if snippet == "Self" {
|
||||
if let Some(ty) = ty {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider spelling out the type instead",
|
||||
format!("{:?}", ty),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
err.span_suggestion(
|
||||
span,
|
||||
"consider spelling out the type instead",
|
||||
format!("{:?}", ty),
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
err.emit();
|
||||
|
@ -56,6 +56,20 @@ impl<B, C> ControlFlow<B, C> {
|
||||
ControlFlow::Break(x) => Some(x),
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps `ControlFlow<B, C>` to `ControlFlow<T, C>` by applying a function
|
||||
/// to the break value in case it exists.
|
||||
#[inline]
|
||||
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
|
||||
pub fn map_break<T, F>(self, f: F) -> ControlFlow<T, C>
|
||||
where
|
||||
F: FnOnce(B) -> T,
|
||||
{
|
||||
match self {
|
||||
ControlFlow::Continue(x) => ControlFlow::Continue(x),
|
||||
ControlFlow::Break(x) => ControlFlow::Break(f(x)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Try> ControlFlow<R, R::Ok> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user