TypeVisitor: use ControlFlow
in rustc_{mir,privacy,traits,typeck}
This commit is contained in:
parent
4fe735b320
commit
61f8182cec
@ -1,6 +1,7 @@
|
||||
use rustc_middle::mir::interpret::InterpResult;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
|
||||
use std::convert::TryInto;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// Returns `true` if a used generic parameter requires substitution.
|
||||
crate fn ensure_monomorphic_enough<'tcx, T>(tcx: TyCtxt<'tcx>, ty: T) -> InterpResult<'tcx>
|
||||
@ -17,24 +18,24 @@ where
|
||||
};
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
if !c.needs_subst() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match c.val {
|
||||
ty::ConstKind::Param(..) => true,
|
||||
ty::ConstKind::Param(..) => ControlFlow::BREAK,
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
if !ty.needs_subst() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
ty::Param(_) => true,
|
||||
ty::Param(_) => ControlFlow::BREAK,
|
||||
ty::Closure(def_id, substs)
|
||||
| ty::Generator(def_id, substs, ..)
|
||||
| ty::FnDef(def_id, substs) => {
|
||||
@ -50,11 +51,7 @@ where
|
||||
match (is_used, subst.needs_subst()) {
|
||||
// Just in case there are closures or generators within this subst,
|
||||
// recurse.
|
||||
(true, true) if subst.super_visit_with(self) => {
|
||||
// Only return when we find a parameter so the remaining substs
|
||||
// are not skipped.
|
||||
return true;
|
||||
}
|
||||
(true, true) => return subst.super_visit_with(self),
|
||||
// Confirm that polymorphization replaced the parameter with
|
||||
// `ty::Param`/`ty::ConstKind::Param`.
|
||||
(false, true) if cfg!(debug_assertions) => match subst.unpack() {
|
||||
@ -69,7 +66,7 @@ where
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
@ -77,7 +74,7 @@ where
|
||||
}
|
||||
|
||||
let mut vis = UsedParamsNeedSubstVisitor { tcx };
|
||||
if ty.visit_with(&mut vis) {
|
||||
if ty.visit_with(&mut vis) == ControlFlow::BREAK {
|
||||
throw_inval!(TooGeneric);
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -27,6 +27,7 @@ Rust MIR: a lowered representation of Rust.
|
||||
#![feature(option_expect_none)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -20,6 +20,7 @@ use rustc_middle::ty::{
|
||||
};
|
||||
use rustc_span::symbol::sym;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// Provide implementations of queries relating to polymorphization analysis.
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
@ -138,7 +139,7 @@ fn mark_used_by_predicates<'tcx>(
|
||||
// predicate is used.
|
||||
let any_param_used = {
|
||||
let mut vis = HasUsedGenericParams { unused_parameters };
|
||||
predicate.visit_with(&mut vis)
|
||||
predicate.visit_with(&mut vis) == ControlFlow::BREAK
|
||||
};
|
||||
|
||||
if any_param_used {
|
||||
@ -249,17 +250,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
debug!("visit_const: c={:?}", c);
|
||||
if !c.has_param_types_or_consts() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match c.val {
|
||||
ty::ConstKind::Param(param) => {
|
||||
debug!("visit_const: param={:?}", param);
|
||||
self.unused_parameters.clear(param.index);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ty::ConstKind::Unevaluated(def, _, Some(p))
|
||||
// Avoid considering `T` unused when constants are of the form:
|
||||
@ -270,22 +271,22 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
// the generic parameters, instead, traverse the promoted MIR.
|
||||
let promoted = self.tcx.promoted_mir(def.did);
|
||||
self.visit_body(&promoted[p]);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ty::ConstKind::Unevaluated(def, unevaluated_substs, None)
|
||||
if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
|
||||
{
|
||||
self.visit_child_body(def.did, unevaluated_substs);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
debug!("visit_ty: ty={:?}", ty);
|
||||
if !ty.has_param_types_or_consts() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match *ty.kind() {
|
||||
@ -293,18 +294,18 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
||||
debug!("visit_ty: def_id={:?}", def_id);
|
||||
// Avoid cycle errors with generators.
|
||||
if def_id == self.def_id {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
// Consider any generic parameters used by any closures/generators as used in the
|
||||
// parent.
|
||||
self.visit_child_body(def_id, substs);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
ty::Param(param) => {
|
||||
debug!("visit_ty: param={:?}", param);
|
||||
self.unused_parameters.clear(param.index);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
@ -317,28 +318,38 @@ struct HasUsedGenericParams<'a> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
|
||||
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
debug!("visit_const: c={:?}", c);
|
||||
if !c.has_param_types_or_consts() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match c.val {
|
||||
ty::ConstKind::Param(param) => {
|
||||
!self.unused_parameters.contains(param.index).unwrap_or(false)
|
||||
if self.unused_parameters.contains(param.index).unwrap_or(false) {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
ControlFlow::BREAK
|
||||
}
|
||||
}
|
||||
_ => c.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
debug!("visit_ty: ty={:?}", ty);
|
||||
if !ty.has_param_types_or_consts() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
|
||||
match ty.kind() {
|
||||
ty::Param(param) => !self.unused_parameters.contains(param.index).unwrap_or(false),
|
||||
ty::Param(param) => {
|
||||
if self.unused_parameters.contains(param.index).unwrap_or(false) {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
ControlFlow::BREAK
|
||||
}
|
||||
}
|
||||
_ => ty.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitor};
|
||||
use rustc_target::abi::Size;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
const INDENT: &str = " ";
|
||||
/// Alignment for lining up comments following MIR statements
|
||||
@ -639,7 +640,7 @@ pub fn write_allocations<'tcx>(
|
||||
}
|
||||
struct CollectAllocIds(BTreeSet<AllocId>);
|
||||
impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::ConstKind::Value(val) = c.val {
|
||||
self.0.extend(alloc_ids_from_const(val));
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(try_blocks)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use rustc_attr as attr;
|
||||
@ -26,6 +28,7 @@ use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::ControlFlow;
|
||||
use std::{cmp, fmt, mem};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -48,7 +51,12 @@ trait DefIdVisitor<'tcx> {
|
||||
fn skip_assoc_tys(&self) -> bool {
|
||||
false
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool;
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
kind: &str,
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<(), ()>;
|
||||
|
||||
/// Not overridden, but used to actually visit types and traits.
|
||||
fn skeleton(&mut self) -> DefIdVisitorSkeleton<'_, 'tcx, Self> {
|
||||
@ -58,13 +66,13 @@ trait DefIdVisitor<'tcx> {
|
||||
dummy: Default::default(),
|
||||
}
|
||||
}
|
||||
fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> bool {
|
||||
fn visit(&mut self, ty_fragment: impl TypeFoldable<'tcx>) -> ControlFlow<(), ()> {
|
||||
ty_fragment.visit_with(&mut self.skeleton())
|
||||
}
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<(), ()> {
|
||||
self.skeleton().visit_trait(trait_ref)
|
||||
}
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<(), ()> {
|
||||
self.skeleton().visit_predicates(predicates)
|
||||
}
|
||||
}
|
||||
@ -79,25 +87,25 @@ impl<'tcx, V> DefIdVisitorSkeleton<'_, 'tcx, V>
|
||||
where
|
||||
V: DefIdVisitor<'tcx> + ?Sized,
|
||||
{
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
|
||||
fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> ControlFlow<(), ()> {
|
||||
let TraitRef { def_id, substs } = trait_ref;
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())
|
||||
|| (!self.def_id_visitor.shallow() && substs.visit_with(self))
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref.print_only_trait_path())?;
|
||||
if self.def_id_visitor.shallow() { ControlFlow::CONTINUE } else { substs.visit_with(self) }
|
||||
}
|
||||
|
||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
|
||||
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<(), ()> {
|
||||
match predicate.skip_binders() {
|
||||
ty::PredicateAtom::Trait(ty::TraitPredicate { trait_ref }, _) => {
|
||||
self.visit_trait(trait_ref)
|
||||
}
|
||||
ty::PredicateAtom::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
|
||||
ty.visit_with(self)
|
||||
|| self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
|
||||
ty.visit_with(self)?;
|
||||
self.visit_trait(projection_ty.trait_ref(self.def_id_visitor.tcx()))
|
||||
}
|
||||
ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
|
||||
ty.visit_with(self)
|
||||
}
|
||||
ty::PredicateAtom::RegionOutlives(..) => false,
|
||||
ty::PredicateAtom::RegionOutlives(..) => ControlFlow::CONTINUE,
|
||||
ty::PredicateAtom::ConstEvaluatable(..)
|
||||
if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
|
||||
{
|
||||
@ -105,20 +113,15 @@ where
|
||||
// private function we may have to do something here...
|
||||
//
|
||||
// For now, let's just pretend that everything is fine.
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => bug!("unexpected predicate: {:?}", predicate),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> bool {
|
||||
fn visit_predicates(&mut self, predicates: ty::GenericPredicates<'tcx>) -> ControlFlow<(), ()> {
|
||||
let ty::GenericPredicates { parent: _, predicates } = predicates;
|
||||
for &(predicate, _span) in predicates {
|
||||
if self.visit_predicate(predicate) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
predicates.iter().try_for_each(|&(predicate, _span)| self.visit_predicate(predicate))
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,7 +129,7 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V>
|
||||
where
|
||||
V: DefIdVisitor<'tcx> + ?Sized,
|
||||
{
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
let tcx = self.def_id_visitor.tcx();
|
||||
// InternalSubsts are not visited here because they are visited below in `super_visit_with`.
|
||||
match *ty.kind() {
|
||||
@ -135,19 +138,15 @@ where
|
||||
| ty::FnDef(def_id, ..)
|
||||
| ty::Closure(def_id, ..)
|
||||
| ty::Generator(def_id, ..) => {
|
||||
if self.def_id_visitor.visit_def_id(def_id, "type", &ty) {
|
||||
return true;
|
||||
}
|
||||
self.def_id_visitor.visit_def_id(def_id, "type", &ty)?;
|
||||
if self.def_id_visitor.shallow() {
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
// Default type visitor doesn't visit signatures of fn types.
|
||||
// Something like `fn() -> Priv {my_func}` is considered a private type even if
|
||||
// `my_func` is public, so we need to visit signatures.
|
||||
if let ty::FnDef(..) = ty.kind() {
|
||||
if tcx.fn_sig(def_id).visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
tcx.fn_sig(def_id).visit_with(self)?;
|
||||
}
|
||||
// Inherent static methods don't have self type in substs.
|
||||
// Something like `fn() {my_method}` type of the method
|
||||
@ -155,9 +154,7 @@ where
|
||||
// so we need to visit the self type additionally.
|
||||
if let Some(assoc_item) = tcx.opt_associated_item(def_id) {
|
||||
if let ty::ImplContainer(impl_def_id) = assoc_item.container {
|
||||
if tcx.type_of(impl_def_id).visit_with(self) {
|
||||
return true;
|
||||
}
|
||||
tcx.type_of(impl_def_id).visit_with(self)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,7 +165,7 @@ where
|
||||
// as visible/reachable even if both `Type` and `Trait` are private.
|
||||
// Ideally, associated types should be substituted in the same way as
|
||||
// free type aliases, but this isn't done yet.
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
// This will also visit substs if necessary, so we don't need to recurse.
|
||||
return self.visit_trait(proj.trait_ref(tcx));
|
||||
@ -185,9 +182,7 @@ where
|
||||
}
|
||||
};
|
||||
let ty::ExistentialTraitRef { def_id, substs: _ } = trait_ref;
|
||||
if self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) {
|
||||
return true;
|
||||
}
|
||||
self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref)?;
|
||||
}
|
||||
}
|
||||
ty::Opaque(def_id, ..) => {
|
||||
@ -200,12 +195,10 @@ where
|
||||
// through the trait list (default type visitor doesn't visit those traits).
|
||||
// All traits in the list are considered the "primary" part of the type
|
||||
// and are visited by shallow visitors.
|
||||
if self.visit_predicates(ty::GenericPredicates {
|
||||
self.visit_predicates(ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: tcx.explicit_item_bounds(def_id),
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
})?;
|
||||
}
|
||||
}
|
||||
// These types don't have their own def-ids (but may have subcomponents
|
||||
@ -231,7 +224,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
!self.def_id_visitor.shallow() && ty.super_visit_with(self)
|
||||
if self.def_id_visitor.shallow() {
|
||||
ControlFlow::CONTINUE
|
||||
} else {
|
||||
ty.super_visit_with(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,9 +278,14 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'tcx> for FindMin<'a, 'tcx, VL>
|
||||
fn skip_assoc_tys(&self) -> bool {
|
||||
true
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
_kind: &str,
|
||||
_descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<(), ()> {
|
||||
self.min = VL::new_min(self, def_id);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
@ -895,7 +897,12 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.ev.tcx
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
_kind: &str,
|
||||
_descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<(), ()> {
|
||||
if let Some(def_id) = def_id.as_local() {
|
||||
if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
|
||||
(self.tcx().visibility(def_id.to_def_id()), self.access_level)
|
||||
@ -904,7 +911,7 @@ impl DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
|
||||
self.ev.update(hir_id, self.access_level);
|
||||
}
|
||||
}
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
@ -1072,17 +1079,14 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
|
||||
fn check_expr_pat_type(&mut self, id: hir::HirId, span: Span) -> bool {
|
||||
self.span = span;
|
||||
let typeck_results = self.typeck_results();
|
||||
if self.visit(typeck_results.node_type(id)) || self.visit(typeck_results.node_substs(id)) {
|
||||
return true;
|
||||
}
|
||||
if let Some(adjustments) = typeck_results.adjustments().get(id) {
|
||||
for adjustment in adjustments {
|
||||
if self.visit(adjustment.target) {
|
||||
return true;
|
||||
}
|
||||
let result: ControlFlow<(), ()> = try {
|
||||
self.visit(typeck_results.node_type(id))?;
|
||||
self.visit(typeck_results.node_substs(id))?;
|
||||
if let Some(adjustments) = typeck_results.adjustments().get(id) {
|
||||
adjustments.iter().try_for_each(|adjustment| self.visit(adjustment.target))?;
|
||||
}
|
||||
}
|
||||
false
|
||||
};
|
||||
result == ControlFlow::BREAK
|
||||
}
|
||||
|
||||
fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
@ -1124,14 +1128,14 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||
self.span = hir_ty.span;
|
||||
if let Some(typeck_results) = self.maybe_typeck_results {
|
||||
// Types in bodies.
|
||||
if self.visit(typeck_results.node_type(hir_ty.hir_id)) {
|
||||
if self.visit(typeck_results.node_type(hir_ty.hir_id)) == ControlFlow::BREAK {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Types in signatures.
|
||||
// FIXME: This is very ineffective. Ideally each HIR type should be converted
|
||||
// into a semantic type only once and the result should be cached somehow.
|
||||
if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)) {
|
||||
if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, hir_ty)) == ControlFlow::BREAK {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1153,15 +1157,16 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||
);
|
||||
|
||||
for (trait_predicate, _, _) in bounds.trait_bounds {
|
||||
if self.visit_trait(trait_predicate.skip_binder()) {
|
||||
if self.visit_trait(trait_predicate.skip_binder()) == ControlFlow::BREAK {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (poly_predicate, _) in bounds.projection_bounds {
|
||||
let tcx = self.tcx;
|
||||
if self.visit(poly_predicate.skip_binder().ty)
|
||||
if self.visit(poly_predicate.skip_binder().ty) == ControlFlow::BREAK
|
||||
|| self.visit_trait(poly_predicate.skip_binder().projection_ty.trait_ref(tcx))
|
||||
== ControlFlow::BREAK
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -1188,7 +1193,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||
// Method calls have to be checked specially.
|
||||
self.span = span;
|
||||
if let Some(def_id) = self.typeck_results().type_dependent_def_id(expr.hir_id) {
|
||||
if self.visit(self.tcx.type_of(def_id)) {
|
||||
if self.visit(self.tcx.type_of(def_id)) == ControlFlow::BREAK {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -1286,8 +1291,17 @@ impl DefIdVisitor<'tcx> for TypePrivacyVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
self.check_def_id(def_id, kind, descr)
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
kind: &str,
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<(), ()> {
|
||||
if self.check_def_id(def_id, kind, descr) {
|
||||
ControlFlow::BREAK
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1777,8 +1791,17 @@ impl DefIdVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'tcx> {
|
||||
fn tcx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
|
||||
self.check_def_id(def_id, kind, descr)
|
||||
fn visit_def_id(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
kind: &str,
|
||||
descr: &dyn fmt::Display,
|
||||
) -> ControlFlow<(), ()> {
|
||||
if self.check_def_id(def_id, kind, descr) {
|
||||
ControlFlow::BREAK
|
||||
} else {
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ use rustc_span::def_id::DefId;
|
||||
use chalk_ir::{FnSig, ForeignDefId};
|
||||
use rustc_hir::Unsafety;
|
||||
use std::collections::btree_map::{BTreeMap, Entry};
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// Essentially an `Into` with a `&RustInterner` parameter
|
||||
crate trait LowerInto<'tcx, T> {
|
||||
@ -897,14 +898,14 @@ impl<'tcx> BoundVarsCollector<'tcx> {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
|
||||
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> ControlFlow<(), ()> {
|
||||
self.binder_index.shift_in(1);
|
||||
let result = t.super_visit_with(self);
|
||||
self.binder_index.shift_out(1);
|
||||
result
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
match *t.kind() {
|
||||
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
|
||||
match self.parameters.entry(bound_ty.var.as_u32()) {
|
||||
@ -924,7 +925,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: Region<'tcx>) -> bool {
|
||||
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<(), ()> {
|
||||
match r {
|
||||
ty::ReLateBound(index, br) if *index == self.binder_index => match br {
|
||||
ty::BoundRegion::BrNamed(def_id, _name) => {
|
||||
@ -1114,7 +1115,7 @@ impl PlaceholdersCollector {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
match t.kind() {
|
||||
ty::Placeholder(p) if p.universe == self.universe_index => {
|
||||
self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1);
|
||||
@ -1126,7 +1127,7 @@ impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: Region<'tcx>) -> bool {
|
||||
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<(), ()> {
|
||||
match r {
|
||||
ty::RePlaceholder(p) if p.universe == self.universe_index => {
|
||||
if let ty::BoundRegion::BrAnon(anon) = p.name {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(nll)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -24,6 +24,8 @@ use rustc_trait_selection::opaque_types::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
pub fn check_wf_new(tcx: TyCtxt<'_>) {
|
||||
let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
|
||||
tcx.hir().krate().par_visit_all_item_likes(&visit);
|
||||
@ -448,30 +450,34 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
};
|
||||
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
|
||||
if t != self.opaque_identity_ty && t.super_visit_with(self) {
|
||||
if t != self.opaque_identity_ty && t.super_visit_with(self) == ControlFlow::BREAK {
|
||||
self.ty = Some(t);
|
||||
return true;
|
||||
return ControlFlow::BREAK;
|
||||
}
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<(), ()> {
|
||||
debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r);
|
||||
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
|
||||
return *index < self.generics.parent_count as u32;
|
||||
if *index < self.generics.parent_count as u32 {
|
||||
return ControlFlow::BREAK;
|
||||
} else {
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
r.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::ConstKind::Unevaluated(..) = c.val {
|
||||
// FIXME(#72219) We currenctly don't detect lifetimes within substs
|
||||
// which would violate this check. Even though the particular substitution is not used
|
||||
// within the const, this should still be fixed.
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
c.super_visit_with(self)
|
||||
}
|
||||
@ -493,7 +499,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
|
||||
let prohibit_opaque = tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter()
|
||||
.any(|(predicate, _)| predicate.visit_with(&mut visitor));
|
||||
.any(|(predicate, _)| predicate.visit_with(&mut visitor) == ControlFlow::BREAK);
|
||||
debug!(
|
||||
"check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}",
|
||||
prohibit_opaque, visitor
|
||||
@ -1449,11 +1455,11 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
|
||||
{
|
||||
struct VisitTypes(Vec<DefId>);
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
match *t.kind() {
|
||||
ty::Opaque(def, _) => {
|
||||
self.0.push(def);
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
_ => t.super_visit_with(self),
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Checks a `a <op>= b`
|
||||
pub fn check_binop_assign(
|
||||
@ -981,7 +983,7 @@ fn suggest_constraining_param(
|
||||
struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::Param(_) = ty.kind() {
|
||||
self.0.push(ty);
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ use rustc_trait_selection::opaque_types::may_define_opaque_type;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
/// Helper type of a temporary returned by `.for_item(...)`.
|
||||
/// This is necessary because we can't write the following bound:
|
||||
///
|
||||
@ -798,18 +800,18 @@ fn check_where_clauses<'tcx, 'fcx>(
|
||||
params: FxHashSet<u32>,
|
||||
}
|
||||
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::Param(param) = t.kind() {
|
||||
self.params.insert(param.index);
|
||||
}
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool {
|
||||
true
|
||||
fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<(), ()> {
|
||||
ControlFlow::BREAK
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::ConstKind::Param(param) = c.val {
|
||||
self.params.insert(param.index);
|
||||
}
|
||||
@ -817,7 +819,7 @@ fn check_where_clauses<'tcx, 'fcx>(
|
||||
}
|
||||
}
|
||||
let mut param_count = CountParams::default();
|
||||
let has_region = pred.visit_with(&mut param_count);
|
||||
let has_region = pred.visit_with(&mut param_count) == ControlFlow::BREAK;
|
||||
let substituted_pred = pred.subst(fcx.tcx, substs);
|
||||
// Don't check non-defaulted params, dependent defaults (including lifetimes)
|
||||
// or preds with multiple params.
|
||||
|
@ -50,6 +50,8 @@ use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
|
||||
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
mod item_bounds;
|
||||
mod type_of;
|
||||
|
||||
@ -2060,14 +2062,14 @@ fn const_evaluatable_predicates_of<'tcx>(
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> {
|
||||
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val {
|
||||
self.preds.insert((
|
||||
ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx),
|
||||
self.span,
|
||||
));
|
||||
}
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_span::source_map::Span;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub struct Parameter(pub u32);
|
||||
@ -56,11 +57,11 @@ struct ParameterCollector {
|
||||
}
|
||||
|
||||
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
|
||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<(), ()> {
|
||||
match *t.kind() {
|
||||
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
|
||||
// projections are not injective
|
||||
return false;
|
||||
return ControlFlow::CONTINUE;
|
||||
}
|
||||
ty::Param(data) => {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
@ -71,14 +72,14 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
|
||||
t.super_visit_with(self)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<(), ()> {
|
||||
if let ty::ReEarlyBound(data) = *r {
|
||||
self.parameters.push(Parameter::from(data));
|
||||
}
|
||||
false
|
||||
ControlFlow::CONTINUE
|
||||
}
|
||||
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
|
||||
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<(), ()> {
|
||||
match c.val {
|
||||
ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
|
||||
// Constant expressions are not injective
|
||||
|
@ -66,6 +66,7 @@ This API is completely unstable and subject to change.
|
||||
#![feature(try_blocks)]
|
||||
#![feature(never_type)]
|
||||
#![feature(slice_partition_dedup)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
Loading…
Reference in New Issue
Block a user