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::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(())

View File

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

View File

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

View File

@ -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<AllocId>);
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));
}

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

View File

@ -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<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);
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 {

View File

@ -4,6 +4,7 @@
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
#[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::{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<DefId>);
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),
}

View File

@ -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 <op>= b`
pub fn check_binop_assign(
@ -981,7 +983,7 @@ fn suggest_constraining_param(
struct TypeParamVisitor<'tcx>(Vec<Ty<'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() {
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::{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<u32>,
}
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.

View File

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

View File

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

View File

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