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:
bors 2020-10-30 22:53:55 +00:00
commit 0d033dee3e
38 changed files with 523 additions and 376 deletions

View file

@ -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
}
}
}