Auto merge of #78182 - LeSeulArtichaut:ty-visitor-contolflow, r=lcnr,oli-obk

TypeVisitor: use `std::ops::ControlFlow` instead of `bool`

Implements MCP rust-lang/compiler-team#374.

Blocked on FCP in rust-lang/compiler-team#374.
r? `@lcnr` cc `@jonas-schievink`
This commit is contained in:
bors 2020-10-30 22:53:55 +00:00
commit 0d033dee3e
38 changed files with 523 additions and 376 deletions

View File

@ -71,6 +71,7 @@ use rustc_middle::ty::{
}; };
use rustc_span::{BytePos, DesugaringKind, Pos, Span}; use rustc_span::{BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi; use rustc_target::spec::abi;
use std::ops::ControlFlow;
use std::{cmp, fmt}; use std::{cmp, fmt};
mod note; mod note;
@ -1497,7 +1498,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { 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) { if let Some((kind, def_id)) = TyCategory::from_ty(t) {
let span = self.tcx.def_span(def_id); let span = self.tcx.def_span(def_id);
// Avoid cluttering the output when the "found" and error span overlap: // Avoid cluttering the output when the "found" and error span overlap:

View File

@ -15,6 +15,8 @@ use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, T
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span}; use rustc_span::{MultiSpan, Span};
use std::ops::ControlFlow;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the return type is a static `impl Trait`, /// 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. /// `dyn Trait` or if a method call on a trait object introduces a static requirement.
@ -472,13 +474,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
struct TraitObjectVisitor(Vec<DefId>); struct TraitObjectVisitor(Vec<DefId>);
impl TypeVisitor<'_> for TraitObjectVisitor { impl TypeVisitor<'_> for TraitObjectVisitor {
fn visit_ty(&mut self, t: Ty<'_>) -> bool { fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> {
match t.kind() { match t.kind() {
ty::Dynamic(preds, RegionKind::ReStatic) => { ty::Dynamic(preds, RegionKind::ReStatic) => {
if let Some(def_id) = preds.principal_def_id() { if let Some(def_id) = preds.principal_def_id() {
self.0.push(def_id); self.0.push(def_id);
} }
false ControlFlow::CONTINUE
} }
_ => t.super_visit_with(self), _ => t.super_visit_with(self),
} }

View File

@ -30,6 +30,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
use std::fmt::Debug; use std::fmt::Debug;
use std::ops::ControlFlow;
#[derive(PartialEq)] #[derive(PartialEq)]
pub enum NormalizationStrategy { pub enum NormalizationStrategy {
@ -740,15 +741,15 @@ struct ScopeInstantiator<'me, 'tcx> {
} }
impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> {
self.target_index.shift_in(1); self.target_index.shift_in(1);
t.super_visit_with(self); t.super_visit_with(self);
self.target_index.shift_out(1); 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; let ScopeInstantiator { bound_region_scope, next_region, .. } = self;
match r { match r {
@ -759,7 +760,7 @@ impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
_ => {} _ => {}
} }
false ControlFlow::CONTINUE
} }
} }

View File

@ -3,6 +3,8 @@ use super::{FixupError, FixupResult, InferCtxt, Span};
use rustc_middle::ty::fold::{TypeFolder, TypeVisitor}; use rustc_middle::ty::fold::{TypeFolder, TypeVisitor};
use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
use std::ops::ControlFlow;
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// OPPORTUNISTIC VAR RESOLVER // OPPORTUNISTIC VAR RESOLVER
@ -121,7 +123,7 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { 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); let t = self.infcx.shallow_resolve(t);
if t.has_infer_types() { if t.has_infer_types() {
if let ty::Infer(infer_ty) = *t.kind() { if let ty::Infer(infer_ty) = *t.kind() {
@ -143,7 +145,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
None None
}; };
self.first_unresolved = Some((t, ty_var_span)); self.first_unresolved = Some((t, ty_var_span));
true // Halt visiting. ControlFlow::BREAK
} else { } else {
// Otherwise, visit its contents. // Otherwise, visit its contents.
t.super_visit_with(self) t.super_visit_with(self)
@ -151,7 +153,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
} else { } else {
// All type variables in inference types must already be resolved, // All type variables in inference types must already be resolved,
// - no need to visit the contents, continue visiting. // - no need to visit the contents, continue visiting.
false ControlFlow::CONTINUE
} }
} }
} }

View File

@ -22,6 +22,7 @@
#![feature(never_type)] #![feature(never_type)]
#![feature(or_patterns)] #![feature(or_patterns)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] // For rustdoc #![recursion_limit = "512"] // For rustdoc
#[macro_use] #[macro_use]

View File

@ -4,6 +4,7 @@ use rustc_middle::ty;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use std::fmt; use std::fmt;
use std::ops::ControlFlow;
// Structural impls for the structs in `traits`. // Structural impls for the structs in `traits`.
@ -68,7 +69,7 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.predicate.visit_with(visitor) self.predicate.visit_with(visitor)
} }
} }

View File

@ -37,6 +37,7 @@
#![feature(or_patterns)] #![feature(or_patterns)]
#![feature(half_open_range_patterns)] #![feature(half_open_range_patterns)]
#![feature(exclusive_range_pattern)] #![feature(exclusive_range_pattern)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"] #![recursion_limit = "256"]
#[macro_use] #[macro_use]

View File

@ -18,6 +18,7 @@ use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants};
use rustc_target::spec::abi::Abi as SpecAbi; use rustc_target::spec::abi::Abi as SpecAbi;
use std::cmp; use std::cmp;
use std::ops::ControlFlow;
use tracing::debug; use tracing::debug;
declare_lint! { declare_lint! {
@ -1135,11 +1136,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
}; };
impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for 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() { match ty.kind() {
ty::Opaque(..) => { ty::Opaque(..) => {
self.ty = Some(ty); self.ty = Some(ty);
true ControlFlow::BREAK
} }
// Consider opaque types within projections FFI-safe if they do not normalize // Consider opaque types within projections FFI-safe if they do not normalize
// to more opaque types. // to more opaque types.
@ -1148,7 +1149,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// If `ty` is a opaque type directly then `super_visit_with` won't invoke // If `ty` is a opaque type directly then `super_visit_with` won't invoke
// this function again. // 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), _ => ty.super_visit_with(self),
} }

View File

@ -15,8 +15,12 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
} }
}) })
}); });
let body_visit = s.fold(false, |acc, bind| {
quote! { #acc || ::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder) } let body_visit = s.fold(quote!(), |acc, bind| {
quote! {
#acc
::rustc_middle::ty::fold::TypeFoldable::visit_with(#bind, __folder)?;
}
}); });
s.bound_impl( s.bound_impl(
@ -32,8 +36,9 @@ pub fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::
fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>( fn super_visit_with<__F: ::rustc_middle::ty::fold::TypeVisitor<'tcx>>(
&self, &self,
__folder: &mut __F __folder: &mut __F
) -> bool { ) -> ::std::ops::ControlFlow<()> {
match *self { #body_visit } match *self { #body_visit }
::std::ops::ControlFlow::CONTINUE
} }
}, },
) )

View File

@ -49,6 +49,7 @@
#![feature(int_error_matching)] #![feature(int_error_matching)]
#![feature(half_open_range_patterns)] #![feature(half_open_range_patterns)]
#![feature(exclusive_range_pattern)] #![feature(exclusive_range_pattern)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] #![recursion_limit = "512"]
#[macro_use] #[macro_use]

View File

@ -62,9 +62,9 @@ macro_rules! CloneTypeFoldableImpls {
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>( fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
&self, &self,
_: &mut F) _: &mut F)
-> bool -> ::std::ops::ControlFlow<()>
{ {
false ::std::ops::ControlFlow::CONTINUE
} }
} }
)+ )+
@ -105,7 +105,7 @@ macro_rules! EnumTypeFoldableImpl {
fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>( fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
&self, &self,
visitor: &mut V, visitor: &mut V,
) -> bool { ) -> ::std::ops::ControlFlow<()> {
EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output()) EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
} }
} }
@ -179,9 +179,10 @@ macro_rules! EnumTypeFoldableImpl {
input($($input)*) input($($input)*)
output( output(
$variant ( $($variant_arg),* ) => { $variant ( $($variant_arg),* ) => {
false $(|| $crate::ty::fold::TypeFoldable::visit_with( $($crate::ty::fold::TypeFoldable::visit_with(
$variant_arg, $visitor $variant_arg, $visitor
))* )?;)*
::std::ops::ControlFlow::CONTINUE
} }
$($output)* $($output)*
) )
@ -196,9 +197,10 @@ macro_rules! EnumTypeFoldableImpl {
input($($input)*) input($($input)*)
output( output(
$variant { $($variant_arg),* } => { $variant { $($variant_arg),* } => {
false $(|| $crate::ty::fold::TypeFoldable::visit_with( $($crate::ty::fold::TypeFoldable::visit_with(
$variant_arg, $visitor $variant_arg, $visitor
))* )?;)*
::std::ops::ControlFlow::CONTINUE
} }
$($output)* $($output)*
) )
@ -212,7 +214,7 @@ macro_rules! EnumTypeFoldableImpl {
@VisitVariants($this, $visitor) @VisitVariants($this, $visitor)
input($($input)*) input($($input)*)
output( output(
$variant => { false } $variant => { ::std::ops::ControlFlow::CONTINUE }
$($output)* $($output)*
) )
) )

View File

@ -32,7 +32,7 @@ use rustc_target::abi;
use rustc_target::asm::InlineAsmRegOrRegClass; use rustc_target::asm::InlineAsmRegOrRegClass;
use std::borrow::Cow; use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write}; use std::fmt::{self, Debug, Display, Formatter, Write};
use std::ops::{Index, IndexMut}; use std::ops::{ControlFlow, Index, IndexMut};
use std::slice; use std::slice;
use std::{iter, mem, option}; use std::{iter, mem, option};
@ -2489,7 +2489,7 @@ impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection {
UserTypeProjection { base, projs } UserTypeProjection { base, projs }
} }
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> {
self.base.visit_with(visitor) self.base.visit_with(visitor)
// Note: there's nothing in `self.proj` to visit. // Note: there's nothing in `self.proj` to visit.
} }

View File

@ -87,41 +87,46 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
Terminator { source_info: self.source_info, kind } Terminator { source_info: self.source_info, kind }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
use crate::mir::TerminatorKind::*; use crate::mir::TerminatorKind::*;
match self.kind { match self.kind {
SwitchInt { ref discr, switch_ty, .. } => { SwitchInt { ref discr, switch_ty, .. } => {
discr.visit_with(visitor) || switch_ty.visit_with(visitor) discr.visit_with(visitor)?;
switch_ty.visit_with(visitor)
} }
Drop { ref place, .. } => place.visit_with(visitor), Drop { ref place, .. } => place.visit_with(visitor),
DropAndReplace { ref place, ref value, .. } => { DropAndReplace { ref place, ref value, .. } => {
place.visit_with(visitor) || value.visit_with(visitor) place.visit_with(visitor)?;
value.visit_with(visitor)
} }
Yield { ref value, .. } => value.visit_with(visitor), Yield { ref value, .. } => value.visit_with(visitor),
Call { ref func, ref args, ref destination, .. } => { Call { ref func, ref args, ref destination, .. } => {
let dest = if let Some((ref loc, _)) = *destination { if let Some((ref loc, _)) = *destination {
loc.visit_with(visitor) loc.visit_with(visitor)?;
} else {
false
}; };
dest || func.visit_with(visitor) || args.visit_with(visitor) func.visit_with(visitor)?;
args.visit_with(visitor)
} }
Assert { ref cond, ref msg, .. } => { Assert { ref cond, ref msg, .. } => {
if cond.visit_with(visitor) { if cond.visit_with(visitor).is_break() {
use AssertKind::*; use AssertKind::*;
match msg { match msg {
BoundsCheck { ref len, ref index } => { BoundsCheck { ref len, ref index } => {
len.visit_with(visitor) || index.visit_with(visitor) len.visit_with(visitor)?;
index.visit_with(visitor)
}
Overflow(_, l, r) => {
l.visit_with(visitor)?;
r.visit_with(visitor)
} }
Overflow(_, l, r) => l.visit_with(visitor) || r.visit_with(visitor),
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => { OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
op.visit_with(visitor) op.visit_with(visitor)
} }
ResumedAfterReturn(_) | ResumedAfterPanic(_) => false, ResumedAfterReturn(_) | ResumedAfterPanic(_) => ControlFlow::CONTINUE,
} }
} else { } else {
false ControlFlow::CONTINUE
} }
} }
InlineAsm { ref operands, .. } => operands.visit_with(visitor), InlineAsm { ref operands, .. } => operands.visit_with(visitor),
@ -132,7 +137,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
| GeneratorDrop | GeneratorDrop
| Unreachable | Unreachable
| FalseEdge { .. } | FalseEdge { .. }
| FalseUnwind { .. } => false, | FalseUnwind { .. } => ControlFlow::CONTINUE,
} }
} }
} }
@ -142,8 +147,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
*self *self
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }
@ -152,8 +157,9 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) } Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.local.visit_with(visitor) || self.projection.visit_with(visitor) self.local.visit_with(visitor)?;
self.projection.visit_with(visitor)
} }
} }
@ -163,8 +169,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
folder.tcx().intern_place_elems(&v) folder.tcx().intern_place_elems(&v)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }
@ -213,32 +219,47 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
use crate::mir::Rvalue::*; use crate::mir::Rvalue::*;
match *self { match *self {
Use(ref op) => op.visit_with(visitor), Use(ref op) => op.visit_with(visitor),
Repeat(ref op, _) => op.visit_with(visitor), Repeat(ref op, _) => op.visit_with(visitor),
ThreadLocalRef(did) => did.visit_with(visitor), ThreadLocalRef(did) => did.visit_with(visitor),
Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), Ref(region, _, ref place) => {
region.visit_with(visitor)?;
place.visit_with(visitor)
}
AddressOf(_, ref place) => place.visit_with(visitor), AddressOf(_, ref place) => place.visit_with(visitor),
Len(ref place) => place.visit_with(visitor), Len(ref place) => place.visit_with(visitor),
Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), Cast(_, ref op, ty) => {
op.visit_with(visitor)?;
ty.visit_with(visitor)
}
BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
rhs.visit_with(visitor) || lhs.visit_with(visitor) rhs.visit_with(visitor)?;
lhs.visit_with(visitor)
} }
UnaryOp(_, ref val) => val.visit_with(visitor), UnaryOp(_, ref val) => val.visit_with(visitor),
Discriminant(ref place) => place.visit_with(visitor), Discriminant(ref place) => place.visit_with(visitor),
NullaryOp(_, ty) => ty.visit_with(visitor), NullaryOp(_, ty) => ty.visit_with(visitor),
Aggregate(ref kind, ref fields) => { Aggregate(ref kind, ref fields) => {
(match **kind { match **kind {
AggregateKind::Array(ty) => ty.visit_with(visitor), AggregateKind::Array(ty) => {
AggregateKind::Tuple => false, ty.visit_with(visitor)?;
AggregateKind::Adt(_, _, substs, user_ty, _) => {
substs.visit_with(visitor) || user_ty.visit_with(visitor)
} }
AggregateKind::Closure(_, substs) => substs.visit_with(visitor), AggregateKind::Tuple => {}
AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), AggregateKind::Adt(_, _, substs, user_ty, _) => {
}) || fields.visit_with(visitor) substs.visit_with(visitor)?;
user_ty.visit_with(visitor)?;
}
AggregateKind::Closure(_, substs) => {
substs.visit_with(visitor)?;
}
AggregateKind::Generator(_, substs, _) => {
substs.visit_with(visitor)?;
}
}
fields.visit_with(visitor)
} }
} }
} }
@ -253,7 +274,7 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
match *self { match *self {
Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
Operand::Constant(ref c) => c.visit_with(visitor), Operand::Constant(ref c) => c.visit_with(visitor),
@ -277,13 +298,13 @@ impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
} }
} }
fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool { fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> ControlFlow<()> {
use crate::mir::ProjectionElem::*; use crate::mir::ProjectionElem::*;
match self { match self {
Field(_, ty) => ty.visit_with(visitor), Field(_, ty) => ty.visit_with(visitor),
Index(v) => v.visit_with(visitor), Index(v) => v.visit_with(visitor),
_ => false, _ => ControlFlow::CONTINUE,
} }
} }
} }
@ -292,8 +313,8 @@ impl<'tcx> TypeFoldable<'tcx> for Field {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self *self
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }
@ -301,8 +322,8 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self *self
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }
@ -310,8 +331,8 @@ impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
self.clone() self.clone()
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }
@ -323,7 +344,7 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
literal: self.literal.fold_with(folder), literal: self.literal.fold_with(folder),
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.literal.visit_with(visitor) self.literal.visit_with(visitor)
} }
} }

View File

@ -37,6 +37,7 @@ use rustc_hir::def_id::DefId;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt; use std::fmt;
use std::ops::ControlFlow;
/// This trait is implemented for every type that can be folded. /// This trait is implemented for every type that can be folded.
/// Basically, every type that has a corresponding method in `TypeFolder`. /// Basically, every type that has a corresponding method in `TypeFolder`.
@ -48,8 +49,8 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
self.super_fold_with(folder) self.super_fold_with(folder)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool; fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()>;
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.super_visit_with(visitor) self.super_visit_with(visitor)
} }
@ -58,7 +59,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
/// If `binder` is `ty::INNERMOST`, this indicates whether /// If `binder` is `ty::INNERMOST`, this indicates whether
/// there are any late-bound regions that appear free. /// there are any late-bound regions that appear free.
fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }) self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
} }
/// Returns `true` if this `self` has any regions that escape `binder` (and /// Returns `true` if this `self` has any regions that escape `binder` (and
@ -72,7 +73,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
} }
fn has_type_flags(&self, flags: TypeFlags) -> bool { fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { flags }) self.visit_with(&mut HasTypeFlagsVisitor { flags }).is_break()
} }
fn has_projections(&self) -> bool { fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION) self.has_type_flags(TypeFlags::HAS_PROJECTION)
@ -143,11 +144,11 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
} }
/// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool { fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> ControlFlow<()>) -> ControlFlow<()> {
pub struct Visitor<F>(F); pub struct Visitor<F>(F);
impl<'tcx, F: FnMut(Ty<'tcx>) -> bool> TypeVisitor<'tcx> for Visitor<F> { impl<'tcx, F: FnMut(Ty<'tcx>) -> ControlFlow<()>> TypeVisitor<'tcx> for Visitor<F> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<()> {
self.0(ty) self.0(ty)
} }
} }
@ -160,8 +161,8 @@ impl TypeFoldable<'tcx> for hir::Constness {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
*self *self
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }
@ -194,23 +195,23 @@ pub trait TypeFolder<'tcx>: Sized {
} }
pub trait TypeVisitor<'tcx>: Sized { pub trait TypeVisitor<'tcx>: Sized {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool { fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<()> {
t.super_visit_with(self) t.super_visit_with(self)
} }
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
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<()> {
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<()> {
c.super_visit_with(self) c.super_visit_with(self)
} }
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> bool { fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<()> {
p.super_visit_with(self) p.super_visit_with(self)
} }
} }
@ -302,8 +303,6 @@ impl<'tcx> TyCtxt<'tcx> {
value: &impl TypeFoldable<'tcx>, value: &impl TypeFoldable<'tcx>,
callback: impl FnMut(ty::Region<'tcx>) -> bool, callback: impl FnMut(ty::Region<'tcx>) -> bool,
) -> bool { ) -> bool {
return value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback });
struct RegionVisitor<F> { struct RegionVisitor<F> {
/// The index of a binder *just outside* the things we have /// The index of a binder *just outside* the things we have
/// traversed. If we encounter a bound region bound by this /// traversed. If we encounter a bound region bound by this
@ -330,31 +329,39 @@ impl<'tcx> TyCtxt<'tcx> {
where where
F: FnMut(ty::Region<'tcx>) -> bool, F: FnMut(ty::Region<'tcx>) -> bool,
{ {
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.outer_index.shift_in(1); self.outer_index.shift_in(1);
let result = t.as_ref().skip_binder().visit_with(self); let result = t.as_ref().skip_binder().visit_with(self);
self.outer_index.shift_out(1); self.outer_index.shift_out(1);
result result
} }
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
match *r { match *r {
ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => {
false // ignore bound regions, keep visiting ControlFlow::CONTINUE
}
_ => {
if (self.callback)(r) {
ControlFlow::BREAK
} else {
ControlFlow::CONTINUE
}
} }
_ => (self.callback)(r),
} }
} }
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 // We're only interested in types involving regions
if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
ty.super_visit_with(self) ty.super_visit_with(self)
} else { } else {
false // keep visiting ControlFlow::CONTINUE
} }
} }
} }
value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
} }
} }
@ -670,7 +677,7 @@ impl<'tcx> TyCtxt<'tcx> {
{ {
let mut collector = LateBoundRegionsCollector::new(just_constraint); let mut collector = LateBoundRegionsCollector::new(just_constraint);
let result = value.as_ref().skip_binder().visit_with(&mut collector); let result = value.as_ref().skip_binder().visit_with(&mut collector);
assert!(!result); // should never have stopped early assert!(result.is_continue()); // should never have stopped early
collector.regions collector.regions
} }
@ -837,43 +844,55 @@ struct HasEscapingVarsVisitor {
} }
impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
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.outer_index.shift_in(1); self.outer_index.shift_in(1);
let result = t.super_visit_with(self); let result = t.super_visit_with(self);
self.outer_index.shift_out(1); self.outer_index.shift_out(1);
result result
} }
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
// If the outer-exclusive-binder is *strictly greater* than // If the outer-exclusive-binder is *strictly greater* than
// `outer_index`, that means that `t` contains some content // `outer_index`, that means that `t` contains some content
// bound at `outer_index` or above (because // bound at `outer_index` or above (because
// `outer_exclusive_binder` is always 1 higher than the // `outer_exclusive_binder` is always 1 higher than the
// content in `t`). Therefore, `t` has some escaping vars. // content in `t`). Therefore, `t` has some escaping vars.
t.outer_exclusive_binder > self.outer_index if t.outer_exclusive_binder > self.outer_index {
ControlFlow::BREAK
} else {
ControlFlow::CONTINUE
}
} }
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
// If the region is bound by `outer_index` or anything outside // If the region is bound by `outer_index` or anything outside
// of outer index, then it escapes the binders we have // of outer index, then it escapes the binders we have
// visited. // visited.
r.bound_at_or_above_binder(self.outer_index) if r.bound_at_or_above_binder(self.outer_index) {
ControlFlow::BREAK
} else {
ControlFlow::CONTINUE
}
} }
fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
// we don't have a `visit_infer_const` callback, so we have to // we don't have a `visit_infer_const` callback, so we have to
// hook in here to catch this case (annoying...), but // hook in here to catch this case (annoying...), but
// otherwise we do want to remember to visit the rest of the // otherwise we do want to remember to visit the rest of the
// const, as it has types/regions embedded in a lot of other // const, as it has types/regions embedded in a lot of other
// places. // places.
match ct.val { match ct.val {
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => true, ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => ControlFlow::BREAK,
_ => ct.super_visit_with(self), _ => ct.super_visit_with(self),
} }
} }
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> {
predicate.inner.outer_exclusive_binder > self.outer_index if predicate.inner.outer_exclusive_binder > self.outer_index {
ControlFlow::BREAK
} else {
ControlFlow::CONTINUE
}
} }
} }
@ -883,34 +902,38 @@ struct HasTypeFlagsVisitor {
} }
impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
fn visit_ty(&mut self, t: Ty<'_>) -> bool { fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<()> {
debug!( debug!(
"HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
t, t,
t.flags(), t.flags(),
self.flags self.flags
); );
t.flags().intersects(self.flags) if t.flags().intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
} }
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
let flags = r.type_flags(); let flags = r.type_flags();
debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags);
flags.intersects(self.flags) if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
} }
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<()> {
let flags = FlagComputation::for_const(c); let flags = FlagComputation::for_const(c);
debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags); debug!("HasTypeFlagsVisitor: c={:?} c.flags={:?} self.flags={:?}", c, flags, self.flags);
flags.intersects(self.flags) if flags.intersects(self.flags) { ControlFlow::BREAK } else { ControlFlow::CONTINUE }
} }
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<()> {
debug!( debug!(
"HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
predicate, predicate.inner.flags, self.flags predicate, predicate.inner.flags, self.flags
); );
predicate.inner.flags.intersects(self.flags) if predicate.inner.flags.intersects(self.flags) {
ControlFlow::BREAK
} else {
ControlFlow::CONTINUE
}
} }
} }
@ -941,45 +964,45 @@ impl LateBoundRegionsCollector {
} }
impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
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.current_index.shift_in(1); self.current_index.shift_in(1);
let result = t.super_visit_with(self); let result = t.super_visit_with(self);
self.current_index.shift_out(1); self.current_index.shift_out(1);
result result
} }
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<()> {
// if we are only looking for "constrained" region, we have to // if we are only looking for "constrained" region, we have to
// ignore the inputs to a projection, as they may not appear // ignore the inputs to a projection, as they may not appear
// in the normalized form // in the normalized form
if self.just_constrained { if self.just_constrained {
if let ty::Projection(..) | ty::Opaque(..) = t.kind() { if let ty::Projection(..) | ty::Opaque(..) = t.kind() {
return false; return ControlFlow::CONTINUE;
} }
} }
t.super_visit_with(self) t.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 we are only looking for "constrained" region, we have to // if we are only looking for "constrained" region, we have to
// ignore the inputs of an unevaluated const, as they may not appear // ignore the inputs of an unevaluated const, as they may not appear
// in the normalized form // in the normalized form
if self.just_constrained { if self.just_constrained {
if let ty::ConstKind::Unevaluated(..) = c.val { if let ty::ConstKind::Unevaluated(..) = c.val {
return false; return ControlFlow::CONTINUE;
} }
} }
c.super_visit_with(self) c.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::ReLateBound(debruijn, br) = *r { if let ty::ReLateBound(debruijn, br) = *r {
if debruijn == self.current_index { if debruijn == self.current_index {
self.regions.insert(br); self.regions.insert(br);
} }
} }
false ControlFlow::CONTINUE
} }
} }

View File

@ -46,7 +46,7 @@ use std::cell::RefCell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::Range; use std::ops::{ControlFlow, Range};
use std::ptr; use std::ptr;
use std::str; use std::str;
@ -1776,8 +1776,9 @@ impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> {
ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor) self.caller_bounds().visit_with(visitor)?;
self.reveal().visit_with(visitor)
} }
} }

View File

@ -22,7 +22,7 @@ use std::cell::Cell;
use std::char; use std::char;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fmt::{self, Write as _}; use std::fmt::{self, Write as _};
use std::ops::{Deref, DerefMut}; use std::ops::{ControlFlow, Deref, DerefMut};
// `pretty` is a separate module only for organization. // `pretty` is a separate module only for organization.
use super::*; use super::*;
@ -1803,7 +1803,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
{ {
struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>); struct LateBoundRegionNameCollector<'a>(&'a mut FxHashSet<Symbol>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_> {
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<()> {
if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r { if let ty::ReLateBound(_, ty::BrNamed(_, name)) = *r {
self.0.insert(name); self.0.insert(name);
} }

View File

@ -14,6 +14,7 @@ use rustc_index::vec::{Idx, IndexVec};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::fmt; use std::fmt;
use std::ops::ControlFlow;
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
@ -727,8 +728,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
*self *self
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }
@ -737,8 +738,9 @@ impl<'tcx, T: TypeFoldable<'tcx>, U: TypeFoldable<'tcx>> TypeFoldable<'tcx> for
(self.0.fold_with(folder), self.1.fold_with(folder)) (self.0.fold_with(folder), self.1.fold_with(folder))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.0.visit_with(visitor) || self.1.visit_with(visitor) self.0.visit_with(visitor)?;
self.1.visit_with(visitor)
} }
} }
@ -749,8 +751,10 @@ impl<'tcx, A: TypeFoldable<'tcx>, B: TypeFoldable<'tcx>, C: TypeFoldable<'tcx>>
(self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder)) (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.0.visit_with(visitor) || self.1.visit_with(visitor) || self.2.visit_with(visitor) self.0.visit_with(visitor)?;
self.1.visit_with(visitor)?;
self.2.visit_with(visitor)
} }
} }
@ -773,7 +777,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
Rc::new((**self).fold_with(folder)) Rc::new((**self).fold_with(folder))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
(**self).visit_with(visitor) (**self).visit_with(visitor)
} }
} }
@ -783,7 +787,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Arc<T> {
Arc::new((**self).fold_with(folder)) Arc::new((**self).fold_with(folder))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
(**self).visit_with(visitor) (**self).visit_with(visitor)
} }
} }
@ -794,7 +798,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<T> {
box content box content
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
(**self).visit_with(visitor) (**self).visit_with(visitor)
} }
} }
@ -804,8 +808,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> {
self.iter().map(|t| t.fold_with(folder)).collect() self.iter().map(|t| t.fold_with(folder)).collect()
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }
@ -814,8 +818,8 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Box<[T]> {
self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice() self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>().into_boxed_slice()
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }
@ -828,11 +832,11 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
folder.fold_binder(self) folder.fold_binder(self)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.as_ref().skip_binder().visit_with(visitor) self.as_ref().skip_binder().visit_with(visitor)
} }
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
visitor.visit_binder(self) visitor.visit_binder(self)
} }
} }
@ -842,8 +846,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>>
fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v)) fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|p| p.visit_with(visitor)) self.iter().try_for_each(|p| p.visit_with(visitor))
} }
} }
@ -852,8 +856,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v)) fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }
@ -862,8 +866,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
fold_list(*self, folder, |tcx, v| tcx.intern_projs(v)) fold_list(*self, folder, |tcx, v| tcx.intern_projs(v))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }
@ -888,20 +892,24 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
use crate::ty::InstanceDef::*; use crate::ty::InstanceDef::*;
self.substs.visit_with(visitor) self.substs.visit_with(visitor)?;
|| match self.def { match self.def {
Item(def) => def.visit_with(visitor), Item(def) => def.visit_with(visitor),
VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => { VtableShim(did) | ReifyShim(did) | Intrinsic(did) | Virtual(did, _) => {
did.visit_with(visitor) did.visit_with(visitor)
}
FnPtrShim(did, ty) | CloneShim(did, ty) => {
did.visit_with(visitor) || ty.visit_with(visitor)
}
DropGlue(did, ty) => did.visit_with(visitor) || ty.visit_with(visitor),
ClosureOnceShim { call_once } => call_once.visit_with(visitor),
} }
FnPtrShim(did, ty) | CloneShim(did, ty) => {
did.visit_with(visitor)?;
ty.visit_with(visitor)
}
DropGlue(did, ty) => {
did.visit_with(visitor)?;
ty.visit_with(visitor)
}
ClosureOnceShim { call_once } => call_once.visit_with(visitor),
}
} }
} }
@ -910,7 +918,7 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> {
Self { instance: self.instance.fold_with(folder), promoted: self.promoted } Self { instance: self.instance.fold_with(folder), promoted: self.promoted }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.instance.visit_with(visitor) self.instance.visit_with(visitor)
} }
} }
@ -959,19 +967,26 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
folder.fold_ty(*self) folder.fold_ty(*self)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
match self.kind() { match self.kind() {
ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::RawPtr(ref tm) => tm.visit_with(visitor),
ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), ty::Array(typ, sz) => {
typ.visit_with(visitor)?;
sz.visit_with(visitor)
}
ty::Slice(typ) => typ.visit_with(visitor), ty::Slice(typ) => typ.visit_with(visitor),
ty::Adt(_, substs) => substs.visit_with(visitor), ty::Adt(_, substs) => substs.visit_with(visitor),
ty::Dynamic(ref trait_ty, ref reg) => { ty::Dynamic(ref trait_ty, ref reg) => {
trait_ty.visit_with(visitor) || reg.visit_with(visitor) trait_ty.visit_with(visitor)?;
reg.visit_with(visitor)
} }
ty::Tuple(ts) => ts.visit_with(visitor), ty::Tuple(ts) => ts.visit_with(visitor),
ty::FnDef(_, substs) => substs.visit_with(visitor), ty::FnDef(_, substs) => substs.visit_with(visitor),
ty::FnPtr(ref f) => f.visit_with(visitor), ty::FnPtr(ref f) => f.visit_with(visitor),
ty::Ref(r, ty, _) => r.visit_with(visitor) || ty.visit_with(visitor), ty::Ref(r, ty, _) => {
r.visit_with(visitor)?;
ty.visit_with(visitor)
}
ty::Generator(_did, ref substs, _) => substs.visit_with(visitor), ty::Generator(_did, ref substs, _) => substs.visit_with(visitor),
ty::GeneratorWitness(ref types) => types.visit_with(visitor), ty::GeneratorWitness(ref types) => types.visit_with(visitor),
ty::Closure(_did, ref substs) => substs.visit_with(visitor), ty::Closure(_did, ref substs) => substs.visit_with(visitor),
@ -990,11 +1005,11 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> {
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::Param(..) | ty::Param(..)
| ty::Never | ty::Never
| ty::Foreign(..) => false, | ty::Foreign(..) => ControlFlow::CONTINUE,
} }
} }
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
visitor.visit_ty(self) visitor.visit_ty(self)
} }
} }
@ -1008,11 +1023,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
folder.fold_region(*self) folder.fold_region(*self)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
visitor.visit_region(*self) visitor.visit_region(*self)
} }
} }
@ -1023,11 +1038,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
folder.tcx().reuse_or_mk_predicate(*self, new) folder.tcx().reuse_or_mk_predicate(*self, new)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
ty::PredicateKind::super_visit_with(&self.inner.kind, visitor) ty::PredicateKind::super_visit_with(&self.inner.kind, visitor)
} }
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
visitor.visit_predicate(*self) visitor.visit_predicate(*self)
} }
@ -1045,8 +1060,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v)) fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|p| p.visit_with(visitor)) self.iter().try_for_each(|p| p.visit_with(visitor))
} }
} }
@ -1055,8 +1070,8 @@ impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T>
self.iter().map(|x| x.fold_with(folder)).collect() self.iter().map(|x| x.fold_with(folder)).collect()
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }
@ -1075,11 +1090,12 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
folder.fold_const(*self) folder.fold_const(*self)
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.ty.visit_with(visitor) || self.val.visit_with(visitor) self.ty.visit_with(visitor)?;
self.val.visit_with(visitor)
} }
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
visitor.visit_const(self) visitor.visit_const(self)
} }
} }
@ -1099,7 +1115,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
match *self { match *self {
ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
ty::ConstKind::Param(p) => p.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor),
@ -1107,7 +1123,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
ty::ConstKind::Value(_) ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..) | ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_) | ty::ConstKind::Placeholder(_)
| ty::ConstKind::Error(_) => false, | ty::ConstKind::Error(_) => ControlFlow::CONTINUE,
} }
} }
} }
@ -1117,8 +1133,8 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
*self *self
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> ControlFlow<()> {
false ControlFlow::CONTINUE
} }
} }

View File

@ -17,6 +17,7 @@ use std::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::ops::ControlFlow;
/// An entity in the Rust type system, which can be one of /// An entity in the Rust type system, which can be one of
/// several kinds (types, lifetimes, and consts). /// several kinds (types, lifetimes, and consts).
@ -159,7 +160,7 @@ impl<'tcx> TypeFoldable<'tcx> for GenericArg<'tcx> {
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
match self.unpack() { match self.unpack() {
GenericArgKind::Lifetime(lt) => lt.visit_with(visitor), GenericArgKind::Lifetime(lt) => lt.visit_with(visitor),
GenericArgKind::Type(ty) => ty.visit_with(visitor), GenericArgKind::Type(ty) => ty.visit_with(visitor),
@ -391,8 +392,8 @@ impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
} }
} }
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<()> {
self.iter().any(|t| t.visit_with(visitor)) self.iter().try_for_each(|t| t.visit_with(visitor))
} }
} }

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).is_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).is_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.is_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)).is_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)).is_break() {
return; return;
} }
} }
@ -1153,15 +1157,17 @@ 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()).is_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).is_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))
.is_break()
{ {
return; return;
} }
@ -1188,7 +1194,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)).is_break() {
return; return;
} }
} else { } else {
@ -1288,8 +1294,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
}
} }
} }
@ -1779,8 +1794,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

@ -19,6 +19,7 @@
#![feature(never_type)] #![feature(never_type)]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(or_patterns)] #![feature(or_patterns)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] // For rustdoc #![recursion_limit = "512"] // For rustdoc
#[macro_use] #[macro_use]

View File

@ -15,6 +15,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::nightly_options; use rustc_session::config::nightly_options;
use rustc_span::Span; use rustc_span::Span;
use std::ops::ControlFlow;
pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>; pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
/// Information about the opaque types whose values we /// Information about the opaque types whose values we
@ -691,26 +693,26 @@ impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
where where
OP: FnMut(ty::Region<'tcx>), OP: FnMut(ty::Region<'tcx>),
{ {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> ControlFlow<()> {
t.as_ref().skip_binder().visit_with(self); 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 { match *r {
// ignore bound regions, keep visiting // ignore bound regions, keep visiting
ty::ReLateBound(_, _) => false, ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
_ => { _ => {
(self.op)(r); (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 // We're only interested in types involving regions
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
return false; // keep visiting return ControlFlow::CONTINUE;
} }
match ty.kind() { match ty.kind() {
@ -745,7 +747,7 @@ where
} }
} }
false ControlFlow::CONTINUE
} }
} }

View File

@ -24,6 +24,7 @@ use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span; use rustc_span::Span;
use std::cmp; use std::cmp;
use std::ops::ControlFlow;
/// Check if a given constant can be evaluated. /// Check if a given constant can be evaluated.
pub fn is_const_evaluatable<'cx, 'tcx>( pub fn is_const_evaluatable<'cx, 'tcx>(
@ -86,9 +87,11 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); 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 { match failure_kind {
@ -564,29 +567,33 @@ pub(super) fn try_unify_abstract_consts<'tcx>(
// on `ErrorReported`. // on `ErrorReported`.
} }
// FIXME: Use `std::ops::ControlFlow` instead of `bool` here. pub fn walk_abstract_const<'tcx, F>(
pub fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) -> bool tcx: TyCtxt<'tcx>,
ct: AbstractConst<'tcx>,
mut f: F,
) -> ControlFlow<()>
where where
F: FnMut(Node<'tcx>) -> bool, F: FnMut(Node<'tcx>) -> ControlFlow<()>,
{ {
fn recurse<'tcx>( fn recurse<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
ct: AbstractConst<'tcx>, ct: AbstractConst<'tcx>,
f: &mut dyn FnMut(Node<'tcx>) -> bool, f: &mut dyn FnMut(Node<'tcx>) -> ControlFlow<()>,
) -> bool { ) -> ControlFlow<()> {
let root = ct.root(); let root = ct.root();
f(root) f(root)?;
|| match root { match root {
Node::Leaf(_) => false, Node::Leaf(_) => ControlFlow::CONTINUE,
Node::Binop(_, l, r) => { Node::Binop(_, l, r) => {
recurse(tcx, ct.subtree(l), f) || recurse(tcx, ct.subtree(r), f) 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))
}
} }
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) recurse(tcx, ct, &mut f)

View File

@ -27,6 +27,7 @@ use smallvec::SmallVec;
use std::array; use std::array;
use std::iter; use std::iter;
use std::ops::ControlFlow;
pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation}; pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
@ -770,9 +771,15 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
} }
impl<'tcx> TypeVisitor<'tcx> for 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() { 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) => { ty::Projection(ref data) => {
// This is a projected type `<Foo as SomeTrait>::X`. // This is a projected type `<Foo as SomeTrait>::X`.
@ -796,7 +803,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
self.supertraits.as_ref().unwrap().contains(&projection_trait_ref); self.supertraits.as_ref().unwrap().contains(&projection_trait_ref);
if is_supertrait_of_current_trait { 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 { } else {
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
} }
@ -805,11 +812,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
} }
} }
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`. // First check if the type of this constant references `Self`.
if self.visit_ty(ct.ty) { self.visit_ty(ct.ty)?;
return true;
}
// Constants can only influence object safety if they reference `Self`. // Constants can only influence object safety if they reference `Self`.
// This is only possible for unevaluated constants, so we walk these here. // This is only possible for unevaluated constants, so we walk these here.
@ -830,14 +835,16 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
let leaf = leaf.subst(self.tcx, ct.substs); let leaf = leaf.subst(self.tcx, ct.substs);
self.visit_const(leaf) self.visit_const(leaf)
} }
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
}) })
} else { } 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() { if let ty::PredicateAtom::ConstEvaluatable(def, substs) = pred.skip_binders() {
// FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
// `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
@ -849,10 +856,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
let leaf = leaf.subst(self.tcx, ct.substs); let leaf = leaf.subst(self.tcx, ct.substs);
self.visit_const(leaf) self.visit_const(leaf)
} }
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => false, Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
}) })
} else { } else {
false ControlFlow::CONTINUE
} }
} else { } else {
pred.super_visit_with(self) pred.super_visit_with(self)
@ -860,7 +869,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
} }
} }
value.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None }) value
.visit_with(&mut IllegalSelfTypeVisitor { tcx, trait_def_id, supertraits: None })
.is_break()
} }
pub fn provide(providers: &mut ty::query::Providers) { pub fn provide(providers: &mut ty::query::Providers) {

View File

@ -8,6 +8,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span; use rustc_span::Span;
use std::ops::ControlFlow;
#[derive(Debug)] #[derive(Debug)]
pub enum NonStructuralMatchTy<'tcx> { pub enum NonStructuralMatchTy<'tcx> {
@ -134,38 +135,38 @@ impl Search<'a, 'tcx> {
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { 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); debug!("Search visiting ty: {:?}", ty);
let (adt_def, substs) = match *ty.kind() { let (adt_def, substs) = match *ty.kind() {
ty::Adt(adt_def, substs) => (adt_def, substs), ty::Adt(adt_def, substs) => (adt_def, substs),
ty::Param(_) => { ty::Param(_) => {
self.found = Some(NonStructuralMatchTy::Param); self.found = Some(NonStructuralMatchTy::Param);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::Dynamic(..) => { ty::Dynamic(..) => {
self.found = Some(NonStructuralMatchTy::Dynamic); self.found = Some(NonStructuralMatchTy::Dynamic);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::Foreign(_) => { ty::Foreign(_) => {
self.found = Some(NonStructuralMatchTy::Foreign); self.found = Some(NonStructuralMatchTy::Foreign);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::Opaque(..) => { ty::Opaque(..) => {
self.found = Some(NonStructuralMatchTy::Opaque); self.found = Some(NonStructuralMatchTy::Opaque);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::Projection(..) => { ty::Projection(..) => {
self.found = Some(NonStructuralMatchTy::Projection); self.found = Some(NonStructuralMatchTy::Projection);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::Generator(..) | ty::GeneratorWitness(..) => { ty::Generator(..) | ty::GeneratorWitness(..) => {
self.found = Some(NonStructuralMatchTy::Generator); self.found = Some(NonStructuralMatchTy::Generator);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::Closure(..) => { ty::Closure(..) => {
self.found = Some(NonStructuralMatchTy::Closure); self.found = Some(NonStructuralMatchTy::Closure);
return true; // Stop visiting. return ControlFlow::BREAK;
} }
ty::RawPtr(..) => { ty::RawPtr(..) => {
// structural-match ignores substructure of // structural-match ignores substructure of
@ -182,39 +183,31 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
// Even though `NonStructural` does not implement `PartialEq`, // Even though `NonStructural` does not implement `PartialEq`,
// structural equality on `T` does not recur into the raw // structural equality on `T` does not recur into the raw
// pointer. Therefore, one can still use `C` in a pattern. // pointer. Therefore, one can still use `C` in a pattern.
return ControlFlow::CONTINUE;
// (But still tell the caller to continue search.)
return false;
} }
ty::FnDef(..) | ty::FnPtr(..) => { ty::FnDef(..) | ty::FnPtr(..) => {
// Types of formals and return in `fn(_) -> _` are also irrelevant; // Types of formals and return in `fn(_) -> _` are also irrelevant;
// so we do not recur into them via `super_visit_with` // so we do not recur into them via `super_visit_with`
// return ControlFlow::CONTINUE;
// (But still tell the caller to continue search.)
return false;
} }
ty::Array(_, n) ty::Array(_, n)
if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } =>
{ {
// rust-lang/rust#62336: ignore type of contents // rust-lang/rust#62336: ignore type of contents
// for empty array. // for empty array.
// return ControlFlow::CONTINUE;
// (But still tell the caller to continue search.)
return false;
} }
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
// These primitive types are always structural match. // These primitive types are always structural match.
// //
// `Never` is kind of special here, but as it is not inhabitable, this should be fine. // `Never` is kind of special here, but as it is not inhabitable, this should be fine.
// return ControlFlow::CONTINUE;
// (But still tell the caller to continue search.)
return false;
} }
ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => {
// First check all contained types and then tell the caller to continue searching. // First check all contained types and then tell the caller to continue searching.
ty.super_visit_with(self); ty.super_visit_with(self);
return false; return ControlFlow::CONTINUE;
} }
ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => { ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
bug!("unexpected type during structural-match checking: {:?}", ty); bug!("unexpected type during structural-match checking: {:?}", ty);
@ -223,22 +216,19 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
self.tcx().sess.delay_span_bug(self.span, "ty::Error in structural-match check"); 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, // We still want to check other types after encountering an error,
// as this may still emit relevant errors. // as this may still emit relevant errors.
// return ControlFlow::CONTINUE;
// So we continue searching here.
return false;
} }
}; };
if !self.seen.insert(adt_def.did) { if !self.seen.insert(adt_def.did) {
debug!("Search already seen adt_def: {:?}", adt_def); debug!("Search already seen adt_def: {:?}", adt_def);
// Let caller continue its search. return ControlFlow::CONTINUE;
return false;
} }
if !self.type_marked_structural(ty) { if !self.type_marked_structural(ty) {
debug!("Search found ty: {:?}", ty); debug!("Search found ty: {:?}", ty);
self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); self.found = Some(NonStructuralMatchTy::Adt(&adt_def));
return true; // Halt visiting! return ControlFlow::BREAK;
} }
// structural-match does not care about the // structural-match does not care about the
@ -258,16 +248,16 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty); let ty = self.tcx().normalize_erasing_regions(ty::ParamEnv::empty(), field_ty);
debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty); debug!("structural-match ADT: field_ty={:?}, ty={:?}", field_ty, ty);
if ty.visit_with(self) { if ty.visit_with(self).is_break() {
// found an ADT without structural-match; halt visiting! // found an ADT without structural-match; halt visiting!
assert!(self.found.is_some()); assert!(self.found.is_some());
return true; return ControlFlow::BREAK;
} }
} }
// Even though we do not want to recur on substs, we do // Even though we do not want to recur on substs, we do
// want our caller to continue its own search. // want our caller to continue its own search.
false 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).is_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).is_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).is_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]

View File

@ -11,6 +11,7 @@
#![feature(or_patterns)] #![feature(or_patterns)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(stmt_expr_attributes)] #![feature(stmt_expr_attributes)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] #![recursion_limit = "512"]
#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)] #![allow(clippy::missing_docs_in_private_items, clippy::must_use_candidate)]

View File

@ -18,6 +18,7 @@ use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, Re
use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::{BytePos, Span}; use rustc_span::source_map::{BytePos, Span};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ops::ControlFlow;
macro_rules! unwrap_or_continue { macro_rules! unwrap_or_continue {
($x:expr) => { ($x:expr) => {
@ -517,7 +518,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
self.possible_borrower.add(borrowed.local, lhs); self.possible_borrower.add(borrowed.local, lhs);
}, },
other => { other => {
if !ContainsRegion.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) { if ContainsRegion.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty).is_continue() {
return; return;
} }
rvalue_locals(other, |rhs| { rvalue_locals(other, |rhs| {
@ -539,7 +540,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
// If the call returns something with lifetimes, // If the call returns something with lifetimes,
// let's conservatively assume the returned value contains lifetime of all the arguments. // let's conservatively assume the returned value contains lifetime of all the arguments.
// For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`. // For example, given `let y: Foo<'a> = foo(x)`, `y` is considered to be a possible borrower of `x`.
if !ContainsRegion.visit_ty(&self.body.local_decls[*dest].ty) { if ContainsRegion.visit_ty(&self.body.local_decls[*dest].ty).is_continue() {
return; return;
} }
@ -558,8 +559,8 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> {
struct ContainsRegion; struct ContainsRegion;
impl TypeVisitor<'_> for ContainsRegion { impl TypeVisitor<'_> for ContainsRegion {
fn visit_region(&mut self, _: ty::Region<'_>) -> bool { fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<()> {
true ControlFlow::BREAK
} }
} }