TypeVisitor: use ControlFlow in rustc_{mir,privacy,traits,typeck}

This commit is contained in:
LeSeulArtichaut 2020-10-21 14:26:34 +02:00
parent 4fe735b320
commit 61f8182cec
13 changed files with 171 additions and 122 deletions

View File

@ -1,6 +1,7 @@
use rustc_middle::mir::interpret::InterpResult; use rustc_middle::mir::interpret::InterpResult;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use std::convert::TryInto; use std::convert::TryInto;
use std::ops::ControlFlow;
/// Returns `true` if a used generic parameter requires substitution. /// Returns `true` if a used generic parameter requires substitution.
crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx> crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
@ -17,24 +18,24 @@ where
}; };
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
if !c.needs_subst() { if !c.needs_subst() {
return false; return ControlFlow::CONTINUE;
} }
match c.val { match c.val {
ty::ConstKind::Param(..) => true, ty::ConstKind::Param(..) => ControlFlow::BREAK,
_ => c.super_visit_with(self), _ => c.super_visit_with(self),
} }
} }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
if !ty.needs_subst() { if !ty.needs_subst() {
return false; return ControlFlow::CONTINUE;
} }
match *ty.kind() { match *ty.kind() {
ty::Param(_) => true, ty::Param(_) => ControlFlow::BREAK,
ty::Closure(def_id, substs) ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, ..) | ty::Generator(def_id, substs, ..)
| ty::FnDef(def_id, substs) => { | ty::FnDef(def_id, substs) => {
@ -50,11 +51,7 @@ where
match (is_used, subst.needs_subst()) { match (is_used, subst.needs_subst()) {
// Just in case there are closures or generators within this subst, // Just in case there are closures or generators within this subst,
// recurse. // recurse.
(true, true) if subst.super_visit_with(self) => { (true, true) => return subst.super_visit_with(self),
// Only return when we find a parameter so the remaining substs
// are not skipped.
return true;
}
// Confirm that polymorphization replaced the parameter with // Confirm that polymorphization replaced the parameter with
// `ty::Param`/`ty::ConstKind::Param`. // `ty::Param`/`ty::ConstKind::Param`.
(false, true) if cfg!(debug_assertions) => match subst.unpack() { (false, true) if cfg!(debug_assertions) => match subst.unpack() {
@ -69,7 +66,7 @@ where
_ => {} _ => {}
} }
} }
false ControlFlow::CONTINUE
} }
_ => ty.super_visit_with(self), _ => ty.super_visit_with(self),
} }
@ -77,7 +74,7 @@ where
} }
let mut vis = UsedParamsNeedSubstVisitor { tcx }; let mut vis = UsedParamsNeedSubstVisitor { tcx };
if ty.visit_with(&mut vis) { if ty.visit_with(&mut vis) == ControlFlow::BREAK {
throw_inval!(TooGeneric); throw_inval!(TooGeneric);
} else { } else {
Ok(()) Ok(())

View File

@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust.
#![feature(option_expect_none)] #![feature(option_expect_none)]
#![feature(or_patterns)] #![feature(or_patterns)]
#![feature(once_cell)] #![feature(once_cell)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -20,6 +20,7 @@ use rustc_middle::ty::{
}; };
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use std::convert::TryInto; use std::convert::TryInto;
use std::ops::ControlFlow;
/// Provide implementations of queries relating to polymorphization analysis. /// Provide implementations of queries relating to polymorphization analysis.
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
@ -138,7 +139,7 @@ fn mark_used_by_predicates<'tcx>(
// predicate is used. // predicate is used.
let any_param_used = { let any_param_used = {
let mut vis = HasUsedGenericParams { unused_parameters }; let mut vis = HasUsedGenericParams { unused_parameters };
predicate.visit_with(&mut vis) predicate.visit_with(&mut vis) == ControlFlow::BREAK
}; };
if any_param_used { if any_param_used {
@ -249,17 +250,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<(), ()> {
debug!("visit_const: c={:?}", c); debug!("visit_const: c={:?}", c);
if !c.has_param_types_or_consts() { if !c.has_param_types_or_consts() {
return false; return ControlFlow::CONTINUE;
} }
match c.val { match c.val {
ty::ConstKind::Param(param) => { ty::ConstKind::Param(param) => {
debug!("visit_const: param={:?}", param); debug!("visit_const: param={:?}", param);
self.unused_parameters.clear(param.index); self.unused_parameters.clear(param.index);
false ControlFlow::CONTINUE
} }
ty::ConstKind::Unevaluated(def, _, Some(p)) ty::ConstKind::Unevaluated(def, _, Some(p))
// Avoid considering `T` unused when constants are of the form: // Avoid considering `T` unused when constants are of the form:
@ -270,22 +271,22 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
// the generic parameters, instead, traverse the promoted MIR. // the generic parameters, instead, traverse the promoted MIR.
let promoted = self.tcx.promoted_mir(def.did); let promoted = self.tcx.promoted_mir(def.did);
self.visit_body(&promoted[p]); self.visit_body(&promoted[p]);
false ControlFlow::CONTINUE
} }
ty::ConstKind::Unevaluated(def, unevaluated_substs, None) ty::ConstKind::Unevaluated(def, unevaluated_substs, None)
if self.tcx.def_kind(def.did) == DefKind::AnonConst => if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
{ {
self.visit_child_body(def.did, unevaluated_substs); self.visit_child_body(def.did, unevaluated_substs);
false ControlFlow::CONTINUE
} }
_ => c.super_visit_with(self), _ => c.super_visit_with(self),
} }
} }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
debug!("visit_ty: ty={:?}", ty); debug!("visit_ty: ty={:?}", ty);
if !ty.has_param_types_or_consts() { if !ty.has_param_types_or_consts() {
return false; return ControlFlow::CONTINUE;
} }
match *ty.kind() { match *ty.kind() {
@ -293,18 +294,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
debug!("visit_ty: def_id={:?}", def_id); debug!("visit_ty: def_id={:?}", def_id);
// Avoid cycle errors with generators. // Avoid cycle errors with generators.
if def_id == self.def_id { if def_id == self.def_id {
return false; return ControlFlow::CONTINUE;
} }
// Consider any generic parameters used by any closures/generators as used in the // Consider any generic parameters used by any closures/generators as used in the
// parent. // parent.
self.visit_child_body(def_id, substs); self.visit_child_body(def_id, substs);
false ControlFlow::CONTINUE
} }
ty::Param(param) => { ty::Param(param) => {
debug!("visit_ty: param={:?}", param); debug!("visit_ty: param={:?}", param);
self.unused_parameters.clear(param.index); self.unused_parameters.clear(param.index);
false ControlFlow::CONTINUE
} }
_ => ty.super_visit_with(self), _ => ty.super_visit_with(self),
} }
@ -317,28 +318,38 @@ struct HasUsedGenericParams<'a> {
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<(), ()> {
debug!("visit_const: c={:?}", c); debug!("visit_const: c={:?}", c);
if !c.has_param_types_or_consts() { if !c.has_param_types_or_consts() {
return false; return ControlFlow::CONTINUE;
} }
match c.val { match c.val {
ty::ConstKind::Param(param) => { ty::ConstKind::Param(param) => {
!self.unused_parameters.contains(param.index).unwrap_or(false) if self.unused_parameters.contains(param.index).unwrap_or(false) {
ControlFlow::CONTINUE
} else {
ControlFlow::BREAK
}
} }
_ => c.super_visit_with(self), _ => c.super_visit_with(self),
} }
} }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
debug!("visit_ty: ty={:?}", ty); debug!("visit_ty: ty={:?}", ty);
if !ty.has_param_types_or_consts() { if !ty.has_param_types_or_consts() {
return false; return ControlFlow::CONTINUE;
} }
match ty.kind() { match ty.kind() {
ty::Param(param) => !self.unused_parameters.contains(param.index).unwrap_or(false), ty::Param(param) => {
if self.unused_parameters.contains(param.index).unwrap_or(false) {
ControlFlow::CONTINUE
} else {
ControlFlow::BREAK
}
}
_ => ty.super_visit_with(self), _ => ty.super_visit_with(self),
} }
} }

View File

@ -19,6 +19,7 @@ use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_target::abi::Size; use rustc_target::abi::Size;
use std::ops::ControlFlow;
const INDENT: &str = " "; const INDENT: &str = " ";
/// Alignment for lining up comments following MIR statements /// Alignment for lining up comments following MIR statements
@ -639,7 +640,7 @@ pub fn write_allocations<'tcx>(
} }
struct CollectAllocIds(BTreeSet<AllocId>); struct CollectAllocIds(BTreeSet<AllocId>);
impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
if let ty::ConstKind::Value(val) = c.val { if let ty::ConstKind::Value(val) = c.val {
self.0.extend(alloc_ids_from_const(val)); self.0.extend(alloc_ids_from_const(val));
} }

View File

@ -2,6 +2,8 @@
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(nll)] #![feature(nll)]
#![feature(or_patterns)] #![feature(or_patterns)]
#![feature(control_flow_enum)]
#![feature(try_blocks)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
use rustc_attr as attr; use rustc_attr as attr;
@ -26,6 +28,7 @@ use rustc_span::symbol::{kw, Ident};
use rustc_span::Span; use rustc_span::Span;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ops::ControlFlow;
use std::{cmp, fmt, mem}; use std::{cmp, fmt, mem};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -48,7 +51,12 @@ trait DefIdVisitor<'tcx> {
fn skip_assoc_tys(&self) -> bool { fn skip_assoc_tys(&self) -> bool {
false 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. /// Not overridden, but used to actually visit types and traits.
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> { fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
@ -58,13 +66,13 @@ trait DefIdVisitor<'tcx> {
dummy: Default::default(), 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()) 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) 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) self.skeleton().visit_predicates(predicates)
} }
} }
@ -79,25 +87,25 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
where where
V: DefIdVisitor<'tcx> + ?Sized, 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; 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.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
|| (!self.def_id_visitor.shallow() && substs.visit_with(self)) 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() { match predicate.skip_binders() {
ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => { ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => {
self.visit_trait(trait_ref) self.visit_trait(trait_ref)
} }
ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => { ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self) ty.visit_with(self)?;
|| self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx())) self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
} }
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => { ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
ty.visit_with(self) ty.visit_with(self)
} }
ty::PredicateAtom::RegionOutlives(..) => false, ty::PredicateAtom::RegionOutlives(..) => ControlFlow::CONTINUE,
ty::PredicateAtom::ConstEvaluatable(..) ty::PredicateAtom::ConstEvaluatable(..)
if self.def_id_visitor.tcx().features().const_evaluatable_checked => if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
{ {
@ -105,20 +113,15 @@ where
// private function we may have to do something here... // private function we may have to do something here...
// //
// For now, let's just pretend that everything is fine. // For now, let's just pretend that everything is fine.
false ControlFlow::CONTINUE
} }
_ => bug!("unexpected predicate: {:?}", predicate), _ => 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; let ty::GenericPredicates { parent: _, predicates } = predicates;
for &(predicate, _span) in predicates { predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate))
if self.visit_predicate(predicate) {
return true;
}
}
false
} }
} }
@ -126,7 +129,7 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V>
where where
V: DefIdVisitor<'tcx> + ?Sized, 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(); let tcx = self.def_id_visitor.tcx();
// InternalSubsts are not visited here because they are visited below in `super_visit_with`. // InternalSubsts are not visited here because they are visited below in `super_visit_with`.
match *ty.kind() { match *ty.kind() {
@ -135,19 +138,15 @@ where
| ty::FnDef(def_id, ..) | ty::FnDef(def_id, ..)
| ty::Closure(def_id, ..) | ty::Closure(def_id, ..)
| ty::Generator(def_id, ..) => { | ty::Generator(def_id, ..) => {
if self.def_id_visitor.visit_def_id(def_id, "type", &ty) { self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
return true;
}
if self.def_id_visitor.shallow() { if self.def_id_visitor.shallow() {
return false; return ControlFlow::CONTINUE;
} }
// Default type visitor doesn't visit signatures of fn types. // Default type visitor doesn't visit signatures of fn types.
// Something like `fn() -> Priv {my_func}` is considered a private type even if // Something like `fn() -> Priv {my_func}` is considered a private type even if
// `my_func` is public, so we need to visit signatures. // `my_func` is public, so we need to visit signatures.
if let ty::FnDef(..) = ty.kind() { if let ty::FnDef(..) = ty.kind() {
if tcx.fn_sig(def_id).visit_with(self) { tcx.fn_sig(def_id).visit_with(self)?;
return true;
}
} }
// Inherent static methods don't have self type in substs. // Inherent static methods don't have self type in substs.
// Something like `fn() {my_method}` type of the method // Something like `fn() {my_method}` type of the method
@ -155,9 +154,7 @@ where
// so we need to visit the self type additionally. // so we need to visit the self type additionally.
if let Some(assoc_item) = tcx.opt_associated_item(def_id) { if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
if let ty::ImplContainer(impl_def_id) = assoc_item.container { if let ty::ImplContainer(impl_def_id) = assoc_item.container {
if tcx.type_of(impl_def_id).visit_with(self) { tcx.type_of(impl_def_id).visit_with(self)?;
return true;
}
} }
} }
} }
@ -168,7 +165,7 @@ where
// as visible/reachable even if both `Type` and `Trait` are private. // as visible/reachable even if both `Type` and `Trait` are private.
// Ideally, associated types should be substituted in the same way as // Ideally, associated types should be substituted in the same way as
// free type aliases, but this isn't done yet. // 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. // This will also visit substs if necessary, so we don't need to recurse.
return self.visit_trait(proj.trait_ref(tcx)); return self.visit_trait(proj.trait_ref(tcx));
@ -185,9 +182,7 @@ where
} }
}; };
let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref; let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref;
if self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) { self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?;
return true;
}
} }
} }
ty::Opaque(def_id, ..) => { ty::Opaque(def_id, ..) => {
@ -200,12 +195,10 @@ where
// through the trait list (default type visitor doesn't visit those traits). // 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 // All traits in the list are considered the "primary" part of the type
// and are visited by shallow visitors. // and are visited by shallow visitors.
if self.visit_predicates(ty::GenericPredicates { self.visit_predicates(ty::GenericPredicates {
parent: None, parent: None,
predicates: tcx.explicit_item_bounds(def_id), predicates: tcx.explicit_item_bounds(def_id),
}) { })?;
return true;
}
} }
} }
// These types don't have their own def-ids (but may have subcomponents // 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 { fn skip_assoc_tys(&self) -> bool {
true 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); 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> { fn tcx(&self) -> TyCtxt<'tcx> {
self.ev.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 Some(def_id) = def_id.as_local() {
if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) = if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
(self.tcx().visibility(def_id.to_def_id()), self.access_level) (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); 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 { fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
self.span = span; self.span = span;
let typeck_results = self.typeck_results(); let typeck_results = self.typeck_results();
if self.visit(typeck_results.node_type(id)) || self.visit(typeck_results.node_substs(id)) { let result: ControlFlow<(), ()> = try {
return true; self.visit(typeck_results.node_type(id))?;
} self.visit(typeck_results.node_substs(id))?;
if let Some(adjustments) = typeck_results.adjustments().get(id) { if let Some(adjustments) = typeck_results.adjustments().get(id) {
for adjustment in adjustments { adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
if self.visit(adjustment.target) {
return true;
}
} }
} };
false result == ControlFlow::BREAK
} }
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { 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; self.span = hir_ty.span;
if let Some(typeck_results) = self.maybe_typeck_results { if let Some(typeck_results) = self.maybe_typeck_results {
// Types in bodies. // 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)) == ControlFlow::BREAK {
return; return;
} }
} else { } else {
// Types in signatures. // Types in signatures.
// FIXME: This is very ineffective. Ideally each HIR type should be converted // 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. // 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)) == ControlFlow::BREAK {
return; return;
} }
} }
@ -1153,15 +1157,16 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
); );
for (trait_predicate, _, _) in bounds.trait_bounds { for (trait_predicate, _, _) in bounds.trait_bounds {
if self.visit_trait(trait_predicate.skip_binder()) { if self.visit_trait(trait_predicate.skip_binder()) == ControlFlow::BREAK {
return; return;
} }
} }
for (poly_predicate, _) in bounds.projection_bounds { for (poly_predicate, _) in bounds.projection_bounds {
let tcx = self.tcx; let tcx = self.tcx;
if self.visit(poly_predicate.skip_binder().ty) if self.visit(poly_predicate.skip_binder().ty) == ControlFlow::BREAK
|| self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx)) || self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
== ControlFlow::BREAK
{ {
return; return;
} }
@ -1188,7 +1193,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
// Method calls have to be checked specially. // Method calls have to be checked specially.
self.span = span; self.span = span;
if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) { 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)) == ControlFlow::BREAK {
return; return;
} }
} else { } else {
@ -1286,8 +1291,17 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx self.tcx
} }
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { fn visit_def_id(
self.check_def_id(def_id, kind, descr) &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
}
} }
} }
@ -1777,8 +1791,17 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx self.tcx
} }
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool { fn visit_def_id(
self.check_def_id(def_id, kind, descr) &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
}
} }
} }

View File

@ -42,6 +42,7 @@ use rustc_span::def_id::DefId;
use chalk_ir::{FnSig, ForeignDefId}; use chalk_ir::{FnSig, ForeignDefId};
use rustc_hir::Unsafety; use rustc_hir::Unsafety;
use std::collections::btree_map::{BTreeMap, Entry}; use std::collections::btree_map::{BTreeMap, Entry};
use std::ops::ControlFlow;
/// Essentially an `Into` with a `&RustInterner` parameter /// Essentially an `Into` with a `&RustInterner` parameter
crate trait LowerInto<'tcx, T> { crate trait LowerInto<'tcx, T> {
@ -897,14 +898,14 @@ impl<'tcx> BoundVarsCollector<'tcx> {
} }
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<(), ()> {
self.binder_index.shift_in(1); self.binder_index.shift_in(1);
let result = t.super_visit_with(self); let result = t.super_visit_with(self);
self.binder_index.shift_out(1); self.binder_index.shift_out(1);
result result
} }
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
match *t.kind() { match *t.kind() {
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
match self.parameters.entry(bound_ty.var.as_u32()) { match self.parameters.entry(bound_ty.var.as_u32()) {
@ -924,7 +925,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
t.super_visit_with(self) t.super_visit_with(self)
} }
fn visit_region(&mut self, r: Region<'tcx>) -> bool { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<(), ()> {
match r { match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br { ty::ReLateBound(index, br) if *index == self.binder_index => match br {
ty::BoundRegion::BrNamed(def_id, _name) => { ty::BoundRegion::BrNamed(def_id, _name) => {
@ -1114,7 +1115,7 @@ impl PlaceholdersCollector {
} }
impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
match t.kind() { match t.kind() {
ty::Placeholder(p) if p.universe == self.universe_index => { ty::Placeholder(p) if p.universe == self.universe_index => {
self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1);
@ -1126,7 +1127,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
t.super_visit_with(self) t.super_visit_with(self)
} }
fn visit_region(&mut self, r: Region<'tcx>) -> bool { fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<(), ()> {
match r { match r {
ty::RePlaceholder(p) if p.universe == self.universe_index => { ty::RePlaceholder(p) if p.universe == self.universe_index => {
if let ty::BoundRegion::BrAnon(anon) = p.name { if let ty::BoundRegion::BrAnon(anon) = p.name {

View File

@ -4,6 +4,7 @@
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(nll)] #![feature(nll)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -24,6 +24,8 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCauseCode}; use rustc_trait_selection::traits::{self, ObligationCauseCode};
use std::ops::ControlFlow;
pub fn check_wf_new(tcx: TyCtxt<'_>) { pub fn check_wf_new(tcx: TyCtxt<'_>) {
let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
tcx.hir().krate().par_visit_all_item_likes(&visit); tcx.hir().krate().par_visit_all_item_likes(&visit);
@ -448,30 +450,34 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
}; };
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
if t != self.opaque_identity_ty && t.super_visit_with(self) { if t != self.opaque_identity_ty && t.super_visit_with(self) == ControlFlow::BREAK {
self.ty = Some(t); self.ty = Some(t);
return true; return ControlFlow::BREAK;
} }
false ControlFlow::CONTINUE
} }
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<(), ()> {
debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
return *index < self.generics.parent_count as u32; if *index < self.generics.parent_count as u32 {
return ControlFlow::BREAK;
} else {
return ControlFlow::CONTINUE;
}
} }
r.super_visit_with(self) r.super_visit_with(self)
} }
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
if let ty::ConstKind::Unevaluated(..) = c.val { if let ty::ConstKind::Unevaluated(..) = c.val {
// FIXME(#72219) We currenctly don't detect lifetimes within substs // FIXME(#72219) We currenctly don't detect lifetimes within substs
// which would violate this check. Even though the particular substitution is not used // which would violate this check. Even though the particular substitution is not used
// within the const, this should still be fixed. // within the const, this should still be fixed.
return false; return ControlFlow::CONTINUE;
} }
c.super_visit_with(self) c.super_visit_with(self)
} }
@ -493,7 +499,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
let prohibit_opaque = tcx let prohibit_opaque = tcx
.explicit_item_bounds(def_id) .explicit_item_bounds(def_id)
.iter() .iter()
.any(|(predicate, _)| predicate.visit_with(&mut visitor)); .any(|(predicate, _)| predicate.visit_with(&mut visitor) == ControlFlow::BREAK);
debug!( debug!(
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
prohibit_opaque, visitor prohibit_opaque, visitor
@ -1449,11 +1455,11 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
{ {
struct VisitTypes(Vec<DefId>); struct VisitTypes(Vec<DefId>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
match *t.kind() { match *t.kind() {
ty::Opaque(def, _) => { ty::Opaque(def, _) => {
self.0.push(def); self.0.push(def);
false ControlFlow::CONTINUE
} }
_ => t.super_visit_with(self), _ => t.super_visit_with(self),
} }

View File

@ -19,6 +19,8 @@ use rustc_span::symbol::{sym, Ident};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::infer::InferCtxtExt;
use std::ops::ControlFlow;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Checks a `a <op>= b` /// Checks a `a <op>= b`
pub fn check_binop_assign( pub fn check_binop_assign(
@ -981,7 +983,7 @@ fn suggest_constraining_param(
struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>); struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
if let ty::Param(_) = ty.kind() { if let ty::Param(_) = ty.kind() {
self.0.push(ty); self.0.push(ty);
} }

View File

@ -24,6 +24,8 @@ use rustc_trait_selection::opaque_types::may_define_opaque_type;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
use std::ops::ControlFlow;
/// Helper type of a temporary returned by `.for_item(...)`. /// Helper type of a temporary returned by `.for_item(...)`.
/// This is necessary because we can't write the following bound: /// This is necessary because we can't write the following bound:
/// ///
@ -798,18 +800,18 @@ fn check_where_clauses<'tcx, 'fcx>(
params: FxHashSet<u32>, params: FxHashSet<u32>,
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
if let ty::Param(param) = t.kind() { if let ty::Param(param) = t.kind() {
self.params.insert(param.index); self.params.insert(param.index);
} }
t.super_visit_with(self) t.super_visit_with(self)
} }
fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<(), ()> {
true ControlFlow::BREAK
} }
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
if let ty::ConstKind::Param(param) = c.val { if let ty::ConstKind::Param(param) = c.val {
self.params.insert(param.index); self.params.insert(param.index);
} }
@ -817,7 +819,7 @@ fn check_where_clauses<'tcx, 'fcx>(
} }
} }
let mut param_count = CountParams::default(); let mut param_count = CountParams::default();
let has_region = pred.visit_with(&mut param_count); let has_region = pred.visit_with(&mut param_count) == ControlFlow::BREAK;
let substituted_pred = pred.subst(fcx.tcx, substs); let substituted_pred = pred.subst(fcx.tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes) // Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params. // or preds with multiple params.

View File

@ -50,6 +50,8 @@ use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi; use rustc_target::spec::abi;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use std::ops::ControlFlow;
mod item_bounds; mod item_bounds;
mod type_of; mod type_of;
@ -2060,14 +2062,14 @@ fn const_evaluatable_predicates_of<'tcx>(
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<(), ()> {
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
self.preds.insert(( self.preds.insert((
ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
self.span, self.span,
)); ));
} }
false ControlFlow::CONTINUE
} }
} }

View File

@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use std::ops::ControlFlow;
#[derive(Clone, PartialEq, Eq, Hash, Debug)] #[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Parameter(pub u32); pub struct Parameter(pub u32);
@ -56,11 +57,11 @@ struct ParameterCollector {
} }
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
match *t.kind() { match *t.kind() {
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
// projections are not injective // projections are not injective
return false; return ControlFlow::CONTINUE;
} }
ty::Param(data) => { ty::Param(data) => {
self.parameters.push(Parameter::from(data)); self.parameters.push(Parameter::from(data));
@ -71,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
t.super_visit_with(self) t.super_visit_with(self)
} }
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<(), ()> {
if let ty::ReEarlyBound(data) = *r { if let ty::ReEarlyBound(data) = *r {
self.parameters.push(Parameter::from(data)); self.parameters.push(Parameter::from(data));
} }
false ControlFlow::CONTINUE
} }
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
match c.val { match c.val {
ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
// Constant expressions are not injective // Constant expressions are not injective

View File

@ -66,6 +66,7 @@ This API is completely unstable and subject to change.
#![feature(try_blocks)] #![feature(try_blocks)]
#![feature(never_type)] #![feature(never_type)]
#![feature(slice_partition_dedup)] #![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]