Auto merge of #78182 - LeSeulArtichaut:ty-visitor-contolflow, r=lcnr,oli-obk
TypeVisitor: use `std::ops::ControlFlow` instead of `bool` Implements MCP rust-lang/compiler-team#374. Blocked on FCP in rust-lang/compiler-team#374. r? `@lcnr` cc `@jonas-schievink`
This commit is contained in:
commit
0d033dee3e
38 changed files with 523 additions and 376 deletions
|
@ -2,6 +2,8 @@
|
|||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use rustc_attr as attr;
|
||||
|
@ -26,6 +28,7 @@ use rustc_span::symbol::{kw, Ident};
|
|||
use rustc_span::Span;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::ControlFlow;
|
||||
use std::{cmp, fmt, mem};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -48,7 +51,12 @@ trait DefIdVisitor<'tcx> {
|
|||
fn skip_assoc_tys(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool;
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
kind: &str,
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<()>;
|
||||
|
||||
/// Not overridden, but used to actually visit types and traits.
|
||||
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
|
||||
|
@ -58,13 +66,13 @@ trait DefIdVisitor<'tcx> {
|
|||
dummy: Default::default(),
|
||||
}
|
||||
}
|
||||
fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> bool {
|
||||
fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<()> {
|
||||
ty_fragment.visit_with(&mut self.skeleton())
|
||||
}
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> {
|
||||
self.skeleton().visit_trait(trait_ref)
|
||||
}
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> {
|
||||
self.skeleton().visit_predicates(predicates)
|
||||
}
|
||||
}
|
||||
|
@ -79,25 +87,25 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
|
|||
where
|
||||
V: DefIdVisitor<'tcx> + ?Sized,
|
||||
{
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<()> {
|
||||
let TraitRef { def_id, substs } = trait_ref;
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())
|
||||
|| (!self.def_id_visitor.shallow() && substs.visit_with(self))
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
|
||||
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
|
||||
}
|
||||
|
||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
|
||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> {
|
||||
match predicate.skip_binders() {
|
||||
ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => {
|
||||
self.visit_trait(trait_ref)
|
||||
}
|
||||
ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
||||
ty.visit_with(self)
|
||||
|| self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
|
||||
ty.visit_with(self)?;
|
||||
self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
|
||||
}
|
||||
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
|
||||
ty.visit_with(self)
|
||||
}
|
||||
ty::PredicateAtom::RegionOutlives(..) => false,
|
||||
ty::PredicateAtom::RegionOutlives(..) => ControlFlow::CONTINUE,
|
||||
ty::PredicateAtom::ConstEvaluatable(..)
|
||||
if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
|
||||
{
|
||||
|
@ -105,20 +113,15 @@ where
|
|||
// private function we may have to do something here...
|
||||
//
|
||||
// For now, let's just pretend that everything is fine.
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => bug!("unexpected predicate: {:?}", predicate),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<()> {
|
||||
let ty::GenericPredicates { parent: _, predicates } = predicates;
|
||||
for &(predicate, _span) in predicates {
|
||||
if self.visit_predicate(predicate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +129,7 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V>
|
|||
where
|
||||
V: DefIdVisitor<'tcx> + ?Sized,
|
||||
{
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
|
||||
let tcx = self.def_id_visitor.tcx();
|
||||
// InternalSubsts are not visited here because they are visited below in `super_visit_with`.
|
||||
match *ty.kind() {
|
||||
|
@ -135,19 +138,15 @@ where
|
|||
| ty::FnDef(def_id, ..)
|
||||
| ty::Closure(def_id, ..)
|
||||
| ty::Generator(def_id, ..) => {
|
||||
if self.def_id_visitor.visit_def_id(def_id, "type", &ty) {
|
||||
return true;
|
||||
}
|
||||
self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
|
||||
if self.def_id_visitor.shallow() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
// Default type visitor doesn't visit signatures of fn types.
|
||||
// Something like `fn() -> Priv {my_func}` is considered a private type even if
|
||||
// `my_func` is public, so we need to visit signatures.
|
||||
if let ty::FnDef(..) = ty.kind() {
|
||||
if tcx.fn_sig(def_id).visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
tcx.fn_sig(def_id).visit_with(self)?;
|
||||
}
|
||||
// Inherent static methods don't have self type in substs.
|
||||
// Something like `fn() {my_method}` type of the method
|
||||
|
@ -155,9 +154,7 @@ where
|
|||
// so we need to visit the self type additionally.
|
||||
if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
|
||||
if let ty::ImplContainer(impl_def_id) = assoc_item.container {
|
||||
if tcx.type_of(impl_def_id).visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
tcx.type_of(impl_def_id).visit_with(self)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +165,7 @@ where
|
|||
// as visible/reachable even if both `Type` and `Trait` are private.
|
||||
// Ideally, associated types should be substituted in the same way as
|
||||
// free type aliases, but this isn't done yet.
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
// This will also visit substs if necessary, so we don't need to recurse.
|
||||
return self.visit_trait(proj.trait_ref(tcx));
|
||||
|
@ -185,9 +182,7 @@ where
|
|||
}
|
||||
};
|
||||
let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref;
|
||||
if self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) {
|
||||
return true;
|
||||
}
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?;
|
||||
}
|
||||
}
|
||||
ty::Opaque(def_id, ..) => {
|
||||
|
@ -200,12 +195,10 @@ where
|
|||
// through the trait list (default type visitor doesn't visit those traits).
|
||||
// All traits in the list are considered the "primary" part of the type
|
||||
// and are visited by shallow visitors.
|
||||
if self.visit_predicates(ty::GenericPredicates {
|
||||
self.visit_predicates(ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: tcx.explicit_item_bounds(def_id),
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
})?;
|
||||
}
|
||||
}
|
||||
// These types don't have their own def-ids (but may have subcomponents
|
||||
|
@ -231,7 +224,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
!self.def_id_visitor.shallow() && ty.super_visit_with(self)
|
||||
if self.def_id_visitor.shallow() {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,9 +278,14 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
|
|||
fn skip_assoc_tys(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
_kind: &str,
|
||||
_descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<()> {
|
||||
self.min = VL::new_min(self, def_id);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -895,7 +897,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
|
|||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.ev.tcx
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
_kind: &str,
|
||||
_descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<()> {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
|
||||
(self.tcx().visibility(def_id.to_def_id()), self.access_level)
|
||||
|
@ -904,7 +911,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
|
|||
self.ev.update(hir_id, self.access_level);
|
||||
}
|
||||
}
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1072,17 +1079,14 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
|
|||
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
|
||||
self.span = span;
|
||||
let typeck_results = self.typeck_results();
|
||||
if self.visit(typeck_results.node_type(id)) || self.visit(typeck_results.node_substs(id)) {
|
||||
return true;
|
||||
}
|
||||
if let Some(adjustments) = typeck_results.adjustments().get(id) {
|
||||
for adjustment in adjustments {
|
||||
if self.visit(adjustment.target) {
|
||||
return true;
|
||||
}
|
||||
let result: ControlFlow<()> = try {
|
||||
self.visit(typeck_results.node_type(id))?;
|
||||
self.visit(typeck_results.node_substs(id))?;
|
||||
if let Some(adjustments) = typeck_results.adjustments().get(id) {
|
||||
adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
result.is_break()
|
||||
}
|
||||
|
||||
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
|
@ -1124,14 +1128,14 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
|||
self.span = hir_ty.span;
|
||||
if let Some(typeck_results) = self.maybe_typeck_results {
|
||||
// Types in bodies.
|
||||
if self.visit(typeck_results.node_type(hir_ty.hir_id)) {
|
||||
if self.visit(typeck_results.node_type(hir_ty.hir_id)).is_break() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Types in signatures.
|
||||
// FIXME: This is very ineffective. Ideally each HIR type should be converted
|
||||
// into a semantic type only once and the result should be cached somehow.
|
||||
if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)) {
|
||||
if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)).is_break() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1153,15 +1157,17 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
|||
);
|
||||
|
||||
for (trait_predicate, _, _) in bounds.trait_bounds {
|
||||
if self.visit_trait(trait_predicate.skip_binder()) {
|
||||
if self.visit_trait(trait_predicate.skip_binder()).is_break() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (poly_predicate, _) in bounds.projection_bounds {
|
||||
let tcx = self.tcx;
|
||||
if self.visit(poly_predicate.skip_binder().ty)
|
||||
|| self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
|
||||
if self.visit(poly_predicate.skip_binder().ty).is_break()
|
||||
|| self
|
||||
.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
|
||||
.is_break()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -1188,7 +1194,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
|||
// Method calls have to be checked specially.
|
||||
self.span = span;
|
||||
if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
if self.visit(self.tcx.type_of(def_id)) {
|
||||
if self.visit(self.tcx.type_of(def_id)).is_break() {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -1288,8 +1294,17 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
|||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
self.check_def_id(def_id, kind, descr)
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
kind: &str,
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<()> {
|
||||
if self.check_def_id(def_id, kind, descr) {
|
||||
ControlFlow::BREAK
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1779,8 +1794,17 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
|||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
self.check_def_id(def_id, kind, descr)
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
kind: &str,
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<()> {
|
||||
if self.check_def_id(def_id, kind, descr) {
|
||||
ControlFlow::BREAK
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue