diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 1402f70c220..535b722cb37 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -71,6 +71,7 @@ }; use rustc_span::{BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; +use std::ops::ControlFlow; use std::{cmp, fmt}; mod note; @@ -1497,7 +1498,7 @@ fn add_labels_for_types( } impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> { if let Some((kind, def_id)) = TyCategory::from_ty(t) { let span = self.tcx.def_span(def_id); // Avoid cluttering the output when the "found" and error span overlap: diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index e9d5ebad7de..3ac72295d91 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -15,6 +15,8 @@ use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; +use std::ops::ControlFlow; + impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static `impl Trait`, /// `dyn Trait` or if a method call on a trait object introduces a static requirement. @@ -472,13 +474,13 @@ fn suggest_constrain_dyn_trait_in_impl( struct TraitObjectVisitor(Vec); impl TypeVisitor<'_> for TraitObjectVisitor { - fn visit_ty(&mut self, t: Ty<'_>) -> bool { + fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<(), ()> { match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { self.0.push(def_id); } - false + ControlFlow::CONTINUE } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index abdd6edea90..2f5b44e7c17 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -30,6 +30,7 @@ use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use std::fmt::Debug; +use std::ops::ControlFlow; #[derive(PartialEq)] pub enum NormalizationStrategy { @@ -740,15 +741,15 @@ struct ScopeInstantiator<'me, 'tcx> { } impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder>(&mut self, t: &ty::Binder) -> bool { + fn visit_binder>(&mut self, t: &ty::Binder) -> ControlFlow<(), ()> { self.target_index.shift_in(1); t.super_visit_with(self); self.target_index.shift_out(1); - false + ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<(), ()> { let ScopeInstantiator { bound_region_scope, next_region, .. } = self; match r { @@ -759,7 +760,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { _ => {} } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 337772d70b8..e4145045b92 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -3,6 +3,8 @@ use rustc_middle::ty::fold::{TypeFolder, TypeVisitor}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use std::ops::ControlFlow; + /////////////////////////////////////////////////////////////////////////// // OPPORTUNISTIC VAR RESOLVER @@ -121,7 +123,7 @@ pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { } impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { if let ty::Infer(infer_ty) = *t.kind() { @@ -143,7 +145,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { None }; self.first_unresolved = Some((t, ty_var_span)); - true // Halt visiting. + ControlFlow::BREAK } else { // Otherwise, visit its contents. t.super_visit_with(self) @@ -151,7 +153,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { } else { // All type variables in inference types must already be resolved, // - no need to visit the contents, continue visiting. - false + ControlFlow::CONTINUE } } } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index ea9a4661348..3690a88c0d9 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -22,6 +22,7 @@ #![feature(never_type)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] +#![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index c48e58c0482..046bc11801a 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use std::fmt; +use std::ops::ControlFlow; // Structural impls for the structs in `traits`. @@ -68,7 +69,7 @@ fn super_fold_with>(&self, folder: &mut F) -> Self { } } - fn super_visit_with>(&self, visitor: &mut V) -> bool { + fn super_visit_with>(&self, visitor: &mut V) -> ControlFlow<(), ()> { self.predicate.visit_with(visitor) } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 2ecdff1a18d..7297a6de420 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -37,6 +37,7 @@ #![feature(or_patterns)] #![feature(half_open_range_patterns)] #![feature(exclusive_range_pattern)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index bd025030567..2bfa17b1219 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -18,6 +18,7 @@ use rustc_target::spec::abi::Abi as SpecAbi; use std::cmp; +use std::ops::ControlFlow; use tracing::debug; declare_lint! { @@ -1135,11 +1136,11 @@ struct ProhibitOpaqueTypes<'a, 'tcx> { }; impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> { match ty.kind() { ty::Opaque(..) => { self.ty = Some(ty); - true + ControlFlow::BREAK } // Consider opaque types within projections FFI-safe if they do not normalize // to more opaque types. @@ -1148,7 +1149,11 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // If `ty` is a opaque type directly then `super_visit_with` won't invoke // this function again. - if ty.has_opaque_types() { self.visit_ty(ty) } else { false } + if ty.has_opaque_types() { + self.visit_ty(ty) + } else { + ControlFlow::CONTINUE + } } _ => ty.super_visit_with(self), } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 406e8936e6e..42509cd8975 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -19,6 +19,7 @@ #![feature(never_type)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] +#![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index ecaafee77e2..f1efec07e08 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -15,6 +15,8 @@ use rustc_session::config::nightly_options; use rustc_span::Span; +use std::ops::ControlFlow; + pub type OpaqueTypeMap<'tcx> = DefIdMap>; /// Information about the opaque types whose values we @@ -691,26 +693,26 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor where OP: FnMut(ty::Region<'tcx>), { - fn visit_binder>(&mut self, t: &ty::Binder) -> bool { + fn visit_binder>(&mut self, t: &ty::Binder) -> ControlFlow<(), ()> { t.as_ref().skip_binder().visit_with(self); - false // keep visiting + ControlFlow::CONTINUE } - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<(), ()> { match *r { // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => false, + ty::ReLateBound(_, _) => ControlFlow::CONTINUE, _ => { (self.op)(r); - false + ControlFlow::CONTINUE } } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> { // We're only interested in types involving regions if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return false; // keep visiting + return ControlFlow::CONTINUE; } match ty.kind() { @@ -745,7 +747,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { } } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 5f6d8ac751e..10ddcf35b30 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -24,6 +24,7 @@ use rustc_span::Span; use std::cmp; +use std::ops::ControlFlow; /// Check if a given constant can be evaluated. pub fn is_const_evaluatable<'cx, 'tcx>( @@ -86,9 +87,11 @@ enum FailureKind { failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); } - false + ControlFlow::CONTINUE + } + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE } - Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => false, }); match failure_kind { @@ -564,29 +567,33 @@ pub(super) fn try_unify_abstract_consts<'tcx>( // on `ErrorReported`. } -// FIXME: Use `std::ops::ControlFlow` instead of `bool` here. -pub fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) -> bool +pub fn walk_abstract_const<'tcx, F>( + tcx: TyCtxt<'tcx>, + ct: AbstractConst<'tcx>, + mut f: F, +) -> ControlFlow<(), ()> where - F: FnMut(Node<'tcx>) -> bool, + F: FnMut(Node<'tcx>) -> ControlFlow<(), ()>, { fn recurse<'tcx>( tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, - f: &mut dyn FnMut(Node<'tcx>) -> bool, - ) -> bool { + f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<(), ()>, + ) -> ControlFlow<(), ()> { let root = ct.root(); - f(root) - || match root { - Node::Leaf(_) => false, - Node::Binop(_, l, r) => { - recurse(tcx, ct.subtree(l), f) || recurse(tcx, ct.subtree(r), f) - } - Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), - Node::FunctionCall(func, args) => { - recurse(tcx, ct.subtree(func), f) - || args.iter().any(|&arg| recurse(tcx, ct.subtree(arg), f)) - } + f(root)?; + match root { + Node::Leaf(_) => ControlFlow::CONTINUE, + Node::Binop(_, l, r) => { + recurse(tcx, ct.subtree(l), f)?; + recurse(tcx, ct.subtree(r), f) } + Node::UnaryOp(_, v) => recurse(tcx, ct.subtree(v), f), + Node::FunctionCall(func, args) => { + recurse(tcx, ct.subtree(func), f)?; + args.iter().try_for_each(|&arg| recurse(tcx, ct.subtree(arg), f)) + } + } } recurse(tcx, ct, &mut f) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index c52fd0b5786..5bbad7aab0c 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -27,6 +27,7 @@ use std::array; use std::iter; +use std::ops::ControlFlow; pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; @@ -770,9 +771,15 @@ struct IllegalSelfTypeVisitor<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> { match t.kind() { - ty::Param(_) => t == self.tcx.types.self_param, + ty::Param(_) => { + if t == self.tcx.types.self_param { + ControlFlow::BREAK + } else { + ControlFlow::CONTINUE + } + } ty::Projection(ref data) => { // This is a projected type `::X`. @@ -796,7 +803,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 + ControlFlow::CONTINUE // do not walk contained types, do not report error, do collect $200 } else { t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error } @@ -805,11 +812,9 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { } } - fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> ControlFlow<(), ()> { // First check if the type of this constant references `Self`. - if self.visit_ty(ct.ty) { - return true; - } + self.visit_ty(ct.ty)?; // Constants can only influence object safety if they reference `Self`. // This is only possible for unevaluated constants, so we walk these here. @@ -830,14 +835,16 @@ fn visit_const(&mut self, ct: &ty::Const<'tcx>) -> bool { let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } else { - false + ControlFlow::CONTINUE } } - fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> bool { + fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<(), ()> { if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() { // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to @@ -849,10 +856,12 @@ fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> bool { let leaf = leaf.subst(self.tcx, ct.substs); self.visit_const(leaf) } - Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, + Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => { + ControlFlow::CONTINUE + } }) } else { - false + ControlFlow::CONTINUE } } else { pred.super_visit_with(self) @@ -861,6 +870,7 @@ fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> bool { } value.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) + == ControlFlow::BREAK } pub fn provide(providers: &mut ty::query::Providers) { diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index 4f7fa2c3988..c15cb9a7d12 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -8,6 +8,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::Span; +use std::ops::ControlFlow; #[derive(Debug)] pub enum NonStructuralMatchTy<'tcx> { @@ -134,38 +135,38 @@ fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { } impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> { debug!("Search visiting ty: {:?}", ty); let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { self.found = Some(NonStructuralMatchTy::Param); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Dynamic(..) => { self.found = Some(NonStructuralMatchTy::Dynamic); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Foreign(_) => { self.found = Some(NonStructuralMatchTy::Foreign); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Opaque(..) => { self.found = Some(NonStructuralMatchTy::Opaque); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Projection(..) => { self.found = Some(NonStructuralMatchTy::Projection); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Generator(..) | ty::GeneratorWitness(..) => { self.found = Some(NonStructuralMatchTy::Generator); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::Closure(..) => { self.found = Some(NonStructuralMatchTy::Closure); - return true; // Stop visiting. + return ControlFlow::BREAK; } ty::RawPtr(..) => { // structural-match ignores substructure of @@ -182,39 +183,31 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // Even though `NonStructural` does not implement `PartialEq`, // structural equality on `T` does not recur into the raw // pointer. Therefore, one can still use `C` in a pattern. - - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::FnDef(..) | ty::FnPtr(..) => { // Types of formals and return in `fn(_) -> _` are also irrelevant; // so we do not recur into them via `super_visit_with` - // - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::Array(_, n) if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => { // rust-lang/rust#62336: ignore type of contents // for empty array. - // - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { // These primitive types are always structural match. // // `Never` is kind of special here, but as it is not inhabitable, this should be fine. - // - // (But still tell the caller to continue search.) - return false; + return ControlFlow::CONTINUE; } ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. ty.super_visit_with(self); - return false; + return ControlFlow::CONTINUE; } ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { bug!("unexpected type during structural-match checking: {:?}", ty); @@ -223,22 +216,19 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); // We still want to check other types after encountering an error, // as this may still emit relevant errors. - // - // So we continue searching here. - return false; + return ControlFlow::CONTINUE; } }; if !self.seen.insert(adt_def.did) { debug!("Search already seen adt_def: {:?}", adt_def); - // Let caller continue its search. - return false; + return ControlFlow::CONTINUE; } if !self.type_marked_structural(ty) { debug!("Search found ty: {:?}", ty); self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return true; // Halt visiting! + return ControlFlow::BREAK; } // structural-match does not care about the @@ -258,16 +248,16 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); - if ty.visit_with(self) { + if ty.visit_with(self) == ControlFlow::BREAK { // found an ADT without structural-match; halt visiting! assert!(self.found.is_some()); - return true; + return ControlFlow::BREAK; } } // Even though we do not want to recur on substs, we do // want our caller to continue its own search. - false + ControlFlow::CONTINUE } }