From 61f8182cecd0451abaa0fabad1f96abf88742ba6 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Wed, 21 Oct 2020 14:26:34 +0200 Subject: [PATCH] TypeVisitor: use `ControlFlow` in rustc_{mir,privacy,traits,typeck} --- compiler/rustc_mir/src/interpret/util.rs | 23 ++- compiler/rustc_mir/src/lib.rs | 1 + .../src/monomorphize/polymorphize.rs | 45 ++++-- compiler/rustc_mir/src/util/pretty.rs | 3 +- compiler/rustc_privacy/src/lib.rs | 147 ++++++++++-------- compiler/rustc_traits/src/chalk/lowering.rs | 11 +- compiler/rustc_traits/src/lib.rs | 1 + compiler/rustc_typeck/src/check/check.rs | 28 ++-- compiler/rustc_typeck/src/check/op.rs | 4 +- compiler/rustc_typeck/src/check/wfcheck.rs | 12 +- compiler/rustc_typeck/src/collect.rs | 6 +- .../src/constrained_generic_params.rs | 11 +- compiler/rustc_typeck/src/lib.rs | 1 + 13 files changed, 171 insertions(+), 122 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs index fc5a25ffbf2..4c52f8eeaff 100644 --- a/compiler/rustc_mir/src/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -1,6 +1,7 @@ use rustc_middle::mir::interpret::InterpResult; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use std::convert::TryInto; +use std::ops::ControlFlow; /// Returns `true` if a used generic parameter requires substitution. 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> { - 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() { - return false; + return ControlFlow::CONTINUE; } match c.val { - ty::ConstKind::Param(..) => true, + ty::ConstKind::Param(..) => ControlFlow::BREAK, _ => 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() { - return false; + return ControlFlow::CONTINUE; } match *ty.kind() { - ty::Param(_) => true, + ty::Param(_) => ControlFlow::BREAK, ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) | ty::FnDef(def_id, substs) => { @@ -50,11 +51,7 @@ where match (is_used, subst.needs_subst()) { // Just in case there are closures or generators within this subst, // recurse. - (true, true) if subst.super_visit_with(self) => { - // Only return when we find a parameter so the remaining substs - // are not skipped. - return true; - } + (true, true) => return subst.super_visit_with(self), // Confirm that polymorphization replaced the parameter with // `ty::Param`/`ty::ConstKind::Param`. (false, true) if cfg!(debug_assertions) => match subst.unpack() { @@ -69,7 +66,7 @@ where _ => {} } } - false + ControlFlow::CONTINUE } _ => ty.super_visit_with(self), } @@ -77,7 +74,7 @@ where } let mut vis = UsedParamsNeedSubstVisitor { tcx }; - if ty.visit_with(&mut vis) { + if ty.visit_with(&mut vis) == ControlFlow::BREAK { throw_inval!(TooGeneric); } else { Ok(()) diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index c00c6860903..2ed115b1297 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust. #![feature(option_expect_none)] #![feature(or_patterns)] #![feature(once_cell)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_mir/src/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs index 3f6f117acdc..5eb60a550de 100644 --- a/compiler/rustc_mir/src/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{ }; use rustc_span::symbol::sym; use std::convert::TryInto; +use std::ops::ControlFlow; /// Provide implementations of queries relating to polymorphization analysis. pub fn provide(providers: &mut Providers) { @@ -138,7 +139,7 @@ fn mark_used_by_predicates<'tcx>( // predicate is used. let any_param_used = { let mut vis = HasUsedGenericParams { unused_parameters }; - predicate.visit_with(&mut vis) + predicate.visit_with(&mut vis) == ControlFlow::BREAK }; 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> { - 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); if !c.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match c.val { ty::ConstKind::Param(param) => { debug!("visit_const: param={:?}", param); self.unused_parameters.clear(param.index); - false + ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(def, _, Some(p)) // 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. let promoted = self.tcx.promoted_mir(def.did); self.visit_body(&promoted[p]); - false + ControlFlow::CONTINUE } ty::ConstKind::Unevaluated(def, unevaluated_substs, None) if self.tcx.def_kind(def.did) == DefKind::AnonConst => { self.visit_child_body(def.did, unevaluated_substs); - false + ControlFlow::CONTINUE } _ => 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); if !ty.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match *ty.kind() { @@ -293,18 +294,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { debug!("visit_ty: def_id={:?}", def_id); // Avoid cycle errors with generators. if def_id == self.def_id { - return false; + return ControlFlow::CONTINUE; } // Consider any generic parameters used by any closures/generators as used in the // parent. self.visit_child_body(def_id, substs); - false + ControlFlow::CONTINUE } ty::Param(param) => { debug!("visit_ty: param={:?}", param); self.unused_parameters.clear(param.index); - false + ControlFlow::CONTINUE } _ => ty.super_visit_with(self), } @@ -317,28 +318,38 @@ struct 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); if !c.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } match c.val { 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), } } - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> { debug!("visit_ty: ty={:?}", ty); if !ty.has_param_types_or_consts() { - return false; + return ControlFlow::CONTINUE; } 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), } } diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs index ac4d6563d6c..4065401731a 100644 --- a/compiler/rustc_mir/src/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -19,6 +19,7 @@ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_target::abi::Size; +use std::ops::ControlFlow; const INDENT: &str = " "; /// Alignment for lining up comments following MIR statements @@ -639,7 +640,7 @@ pub fn write_allocations<'tcx>( } struct CollectAllocIds(BTreeSet); 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 { self.0.extend(alloc_ids_from_const(val)); } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 851e0dfbe0d..a05da06bed7 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -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 == ControlFlow::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)) == ControlFlow::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)) == ControlFlow::BREAK { return; } } @@ -1153,15 +1157,16 @@ 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()) == ControlFlow::BREAK { return; } } for (poly_predicate, _) in bounds.projection_bounds { 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)) + == ControlFlow::BREAK { return; } @@ -1188,7 +1193,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)) == ControlFlow::BREAK { return; } } else { @@ -1286,8 +1291,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 + } } } @@ -1777,8 +1791,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 + } } } diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index 5ca0fc0c88b..9862bc297be 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -42,6 +42,7 @@ use rustc_span::def_id::DefId; use chalk_ir::{FnSig, ForeignDefId}; use rustc_hir::Unsafety; use std::collections::btree_map::{BTreeMap, Entry}; +use std::ops::ControlFlow; /// Essentially an `Into` with a `&RustInterner` parameter crate trait LowerInto<'tcx, T> { @@ -897,14 +898,14 @@ impl<'tcx> BoundVarsCollector<'tcx> { } impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { - fn visit_binder>(&mut self, t: &Binder) -> bool { + fn visit_binder>(&mut self, t: &Binder) -> ControlFlow<(), ()> { self.binder_index.shift_in(1); let result = t.super_visit_with(self); self.binder_index.shift_out(1); result } - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> { match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { 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) } - fn visit_region(&mut self, r: Region<'tcx>) -> bool { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<(), ()> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { ty::BoundRegion::BrNamed(def_id, _name) => { @@ -1114,7 +1115,7 @@ impl 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() { ty::Placeholder(p) if p.universe == self.universe_index => { 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) } - fn visit_region(&mut self, r: Region<'tcx>) -> bool { + fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<(), ()> { match r { ty::RePlaceholder(p) if p.universe == self.universe_index => { if let ty::BoundRegion::BrAnon(anon) = p.name { diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index d0b05beb4e6..7b688cd3e21 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -4,6 +4,7 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 6dd8a143ec0..4d3c899e58d 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -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::{self, ObligationCauseCode}; +use std::ops::ControlFlow; + pub fn check_wf_new(tcx: TyCtxt<'_>) { let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); 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> { - 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); - 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); - 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); 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) } - 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 { // FIXME(#72219) We currenctly 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 false; + return ControlFlow::CONTINUE; } c.super_visit_with(self) } @@ -493,7 +499,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes( let prohibit_opaque = tcx .explicit_item_bounds(def_id) .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor)); + .any(|(predicate, _)| predicate.visit_with(&mut visitor) == ControlFlow::BREAK); debug!( "check_opaque_for_inheriting_lifetimes: 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); 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() { ty::Opaque(def, _) => { self.0.push(def); - false + ControlFlow::CONTINUE } _ => t.super_visit_with(self), } diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 02268b11a7a..2344c956182 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -19,6 +19,8 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; +use std::ops::ControlFlow; + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Checks a `a = b` pub fn check_binop_assign( @@ -981,7 +983,7 @@ fn suggest_constraining_param( struct TypeParamVisitor<'tcx>(Vec>); 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() { self.0.push(ty); } diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index b4e950ab6e9..c41e5f83e7b 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -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::{self, ObligationCause, ObligationCauseCode}; +use std::ops::ControlFlow; + /// Helper type of a temporary returned by `.for_item(...)`. /// This is necessary because we can't write the following bound: /// @@ -798,18 +800,18 @@ fn check_where_clauses<'tcx, 'fcx>( params: FxHashSet, } 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() { self.params.insert(param.index); } t.super_visit_with(self) } - fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { - true + fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<(), ()> { + 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 { self.params.insert(param.index); } @@ -817,7 +819,7 @@ fn check_where_clauses<'tcx, 'fcx>( } } 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); // Don't check non-defaulted params, dependent defaults (including lifetimes) // or preds with multiple params. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 136867d78f5..b32fcad636d 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -50,6 +50,8 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi; use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName; +use std::ops::ControlFlow; + mod item_bounds; mod type_of; @@ -2060,14 +2062,14 @@ fn const_evaluatable_predicates_of<'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 { self.preds.insert(( ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), self.span, )); } - false + ControlFlow::CONTINUE } } diff --git a/compiler/rustc_typeck/src/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs index 09b5a9b0a65..0cd3718ca7b 100644 --- a/compiler/rustc_typeck/src/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::source_map::Span; +use std::ops::ControlFlow; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Parameter(pub u32); @@ -56,11 +57,11 @@ struct 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() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective - return false; + return ControlFlow::CONTINUE; } ty::Param(data) => { self.parameters.push(Parameter::from(data)); @@ -71,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { 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 { 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 { ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => { // Constant expressions are not injective diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index c1fa39e96eb..30904091c1b 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -66,6 +66,7 @@ This API is completely unstable and subject to change. #![feature(try_blocks)] #![feature(never_type)] #![feature(slice_partition_dedup)] +#![feature(control_flow_enum)] #![recursion_limit = "256"] #[macro_use]