1
Fork 0

TypeVisitor: use ControlFlow in rustc_{infer,lint,trait_selection}

This commit is contained in:
LeSeulArtichaut 2020-10-21 14:24:35 +02:00
parent 2c85b6fae0
commit 4fe735b320
13 changed files with 106 additions and 82 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

@ -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)
@ -861,6 +870,7 @@ 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 })
== ControlFlow::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) == ControlFlow::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
} }
} }