Use ControlFlow
results for visitors that are only looking for a single value
This commit is contained in:
parent
d2e6cf7fa7
commit
7dca61b68b
@ -39,6 +39,7 @@
|
|||||||
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
use rustc_trait_selection::traits::error_reporting::FindExprBySpan;
|
||||||
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use crate::borrow_set::TwoPhaseActivation;
|
use crate::borrow_set::TwoPhaseActivation;
|
||||||
use crate::borrowck_errors;
|
use crate::borrowck_errors;
|
||||||
@ -784,20 +785,20 @@ fn suggest_hoisting_call_outside_loop(&self, err: &mut Diag<'_>, expr: &hir::Exp
|
|||||||
/// binding declaration within every scope we inspect.
|
/// binding declaration within every scope we inspect.
|
||||||
struct Finder {
|
struct Finder {
|
||||||
hir_id: hir::HirId,
|
hir_id: hir::HirId,
|
||||||
found: bool,
|
|
||||||
}
|
}
|
||||||
impl<'hir> Visitor<'hir> for Finder {
|
impl<'hir> Visitor<'hir> for Finder {
|
||||||
fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) {
|
type Result = ControlFlow<()>;
|
||||||
|
fn visit_pat(&mut self, pat: &'hir hir::Pat<'hir>) -> Self::Result {
|
||||||
if pat.hir_id == self.hir_id {
|
if pat.hir_id == self.hir_id {
|
||||||
self.found = true;
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_pat(self, pat);
|
hir::intravisit::walk_pat(self, pat)
|
||||||
}
|
}
|
||||||
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) -> Self::Result {
|
||||||
if ex.hir_id == self.hir_id {
|
if ex.hir_id == self.hir_id {
|
||||||
self.found = true;
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
hir::intravisit::walk_expr(self, ex);
|
hir::intravisit::walk_expr(self, ex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The immediate HIR parent of the moved expression. We'll look for it to be a call.
|
// The immediate HIR parent of the moved expression. We'll look for it to be a call.
|
||||||
@ -822,9 +823,7 @@ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
|||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
if let Some(&hir_id) = local_hir_id {
|
if let Some(&hir_id) = local_hir_id {
|
||||||
let mut finder = Finder { hir_id, found: false };
|
if (Finder { hir_id }).visit_expr(e).is_break() {
|
||||||
finder.visit_expr(e);
|
|
||||||
if finder.found {
|
|
||||||
// The current scope includes the declaration of the binding we're accessing, we
|
// The current scope includes the declaration of the binding we're accessing, we
|
||||||
// can't look up any further for loops.
|
// can't look up any further for loops.
|
||||||
break;
|
break;
|
||||||
@ -839,9 +838,7 @@ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
|
|||||||
hir::Node::Expr(hir::Expr {
|
hir::Node::Expr(hir::Expr {
|
||||||
kind: hir::ExprKind::If(cond, ..), ..
|
kind: hir::ExprKind::If(cond, ..), ..
|
||||||
}) => {
|
}) => {
|
||||||
let mut finder = Finder { hir_id: expr.hir_id, found: false };
|
if (Finder { hir_id: expr.hir_id }).visit_expr(cond).is_break() {
|
||||||
finder.visit_expr(cond);
|
|
||||||
if finder.found {
|
|
||||||
// The expression where the move error happened is in a `while let`
|
// The expression where the move error happened is in a `while let`
|
||||||
// condition Don't suggest clone as it will likely end in an
|
// condition Don't suggest clone as it will likely end in an
|
||||||
// infinite loop.
|
// infinite loop.
|
||||||
@ -1837,7 +1834,6 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
|
|||||||
|
|
||||||
pub struct Holds<'tcx> {
|
pub struct Holds<'tcx> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
holds: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
||||||
@ -1845,7 +1841,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Holds<'tcx> {
|
|||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||||
if t == self.ty {
|
if t == self.ty {
|
||||||
self.holds = true;
|
return ControlFlow::Break(());
|
||||||
}
|
}
|
||||||
t.super_visit_with(self)
|
t.super_visit_with(self)
|
||||||
}
|
}
|
||||||
@ -1863,9 +1859,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
|||||||
&& rcvr_ty == ty
|
&& rcvr_ty == ty
|
||||||
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
&& let ty::Ref(_, inner, _) = rcvr_ty.kind()
|
||||||
&& let inner = inner.peel_refs()
|
&& let inner = inner.peel_refs()
|
||||||
&& let mut v = (Holds { ty: inner, holds: false })
|
&& (Holds { ty: inner }).visit_ty(local_ty).is_break()
|
||||||
&& let _ = v.visit_ty(local_ty)
|
|
||||||
&& v.holds
|
|
||||||
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
&& let None = self.infcx.type_implements_trait_shallow(clone, inner, self.param_env)
|
||||||
{
|
{
|
||||||
err.span_label(
|
err.span_label(
|
||||||
@ -4325,15 +4319,14 @@ pub(crate) fn emit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Detect whether one of the provided spans is a statement nested within the top-most visited expr
|
/// Detect whether one of the provided spans is a statement nested within the top-most visited expr
|
||||||
struct ReferencedStatementsVisitor<'a>(&'a [Span], bool);
|
struct ReferencedStatementsVisitor<'a>(&'a [Span]);
|
||||||
|
|
||||||
impl<'a, 'v> Visitor<'v> for ReferencedStatementsVisitor<'a> {
|
impl<'v> Visitor<'v> for ReferencedStatementsVisitor<'_> {
|
||||||
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
|
type Result = ControlFlow<()>;
|
||||||
|
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
|
||||||
match s.kind {
|
match s.kind {
|
||||||
hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => {
|
hir::StmtKind::Semi(expr) if self.0.contains(&expr.span) => ControlFlow::Break(()),
|
||||||
self.1 = true;
|
_ => ControlFlow::Continue(()),
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4375,9 +4368,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
|||||||
hir::ExprKind::If(cond, body, None) => {
|
hir::ExprKind::If(cond, body, None) => {
|
||||||
// `if` expressions with no `else` that initialize the binding might be missing an
|
// `if` expressions with no `else` that initialize the binding might be missing an
|
||||||
// `else` arm.
|
// `else` arm.
|
||||||
let mut v = ReferencedStatementsVisitor(self.spans, false);
|
if ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break() {
|
||||||
v.visit_expr(body);
|
|
||||||
if v.1 {
|
|
||||||
self.errors.push((
|
self.errors.push((
|
||||||
cond.span,
|
cond.span,
|
||||||
format!(
|
format!(
|
||||||
@ -4394,11 +4385,9 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
|||||||
hir::ExprKind::If(cond, body, Some(other)) => {
|
hir::ExprKind::If(cond, body, Some(other)) => {
|
||||||
// `if` expressions where the binding is only initialized in one of the two arms
|
// `if` expressions where the binding is only initialized in one of the two arms
|
||||||
// might be missing a binding initialization.
|
// might be missing a binding initialization.
|
||||||
let mut a = ReferencedStatementsVisitor(self.spans, false);
|
let a = ReferencedStatementsVisitor(self.spans).visit_expr(body).is_break();
|
||||||
a.visit_expr(body);
|
let b = ReferencedStatementsVisitor(self.spans).visit_expr(other).is_break();
|
||||||
let mut b = ReferencedStatementsVisitor(self.spans, false);
|
match (a, b) {
|
||||||
b.visit_expr(other);
|
|
||||||
match (a.1, b.1) {
|
|
||||||
(true, true) | (false, false) => {}
|
(true, true) | (false, false) => {}
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
if other.span.is_desugaring(DesugaringKind::WhileLoop) {
|
if other.span.is_desugaring(DesugaringKind::WhileLoop) {
|
||||||
@ -4437,11 +4426,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
|
|||||||
// arms might be missing an initialization.
|
// arms might be missing an initialization.
|
||||||
let results: Vec<bool> = arms
|
let results: Vec<bool> = arms
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arm| {
|
.map(|arm| ReferencedStatementsVisitor(self.spans).visit_arm(arm).is_break())
|
||||||
let mut v = ReferencedStatementsVisitor(self.spans, false);
|
|
||||||
v.visit_arm(arm);
|
|
||||||
v.1
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
|
if results.iter().any(|x| *x) && !results.iter().all(|x| *x) {
|
||||||
for (arm, seen) in arms.iter().zip(results) {
|
for (arm, seen) in arms.iter().zip(results) {
|
||||||
|
@ -240,7 +240,7 @@ fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) -> ControlFlow<()> {
|
|||||||
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
|
||||||
ControlFlow::Break(())
|
ControlFlow::Break(())
|
||||||
} else {
|
} else {
|
||||||
// no need to subrecurse.
|
// no need to walk the variant, we are only looking for top level variants
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use crate::middle::resolve_bound_vars as rbv;
|
use crate::middle::resolve_bound_vars as rbv;
|
||||||
use hir::{
|
use hir::{
|
||||||
intravisit::{self, Visitor},
|
intravisit::{self, Visitor},
|
||||||
@ -87,14 +89,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
|||||||
let mut in_param_ty = false;
|
let mut in_param_ty = false;
|
||||||
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
||||||
if let Some(generics) = node.generics() {
|
if let Some(generics) = node.generics() {
|
||||||
let mut visitor = AnonConstInParamTyDetector {
|
let mut visitor = AnonConstInParamTyDetector { in_param_ty: false, ct: hir_id };
|
||||||
in_param_ty: false,
|
|
||||||
found_anon_const_in_param_ty: false,
|
|
||||||
ct: hir_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
visitor.visit_generics(generics);
|
in_param_ty = visitor.visit_generics(generics).is_break();
|
||||||
in_param_ty = visitor.found_anon_const_in_param_ty;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,50 +457,45 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
|||||||
struct LateBoundRegionsDetector<'tcx> {
|
struct LateBoundRegionsDetector<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
outer_index: ty::DebruijnIndex,
|
outer_index: ty::DebruijnIndex,
|
||||||
has_late_bound_regions: Option<Span>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
|
impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
|
||||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
|
type Result = ControlFlow<Span>;
|
||||||
if self.has_late_bound_regions.is_some() {
|
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) -> ControlFlow<Span> {
|
||||||
return;
|
|
||||||
}
|
|
||||||
match ty.kind {
|
match ty.kind {
|
||||||
hir::TyKind::BareFn(..) => {
|
hir::TyKind::BareFn(..) => {
|
||||||
self.outer_index.shift_in(1);
|
self.outer_index.shift_in(1);
|
||||||
intravisit::walk_ty(self, ty);
|
let res = intravisit::walk_ty(self, ty);
|
||||||
self.outer_index.shift_out(1);
|
self.outer_index.shift_out(1);
|
||||||
|
res
|
||||||
}
|
}
|
||||||
_ => intravisit::walk_ty(self, ty),
|
_ => intravisit::walk_ty(self, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) {
|
fn visit_poly_trait_ref(&mut self, tr: &'tcx hir::PolyTraitRef<'tcx>) -> ControlFlow<Span> {
|
||||||
if self.has_late_bound_regions.is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.outer_index.shift_in(1);
|
self.outer_index.shift_in(1);
|
||||||
intravisit::walk_poly_trait_ref(self, tr);
|
let res = intravisit::walk_poly_trait_ref(self, tr);
|
||||||
self.outer_index.shift_out(1);
|
self.outer_index.shift_out(1);
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) {
|
fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) -> ControlFlow<Span> {
|
||||||
if self.has_late_bound_regions.is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.tcx.named_bound_var(lt.hir_id) {
|
match self.tcx.named_bound_var(lt.hir_id) {
|
||||||
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {}
|
Some(rbv::ResolvedArg::StaticLifetime | rbv::ResolvedArg::EarlyBound(..)) => {
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
|
Some(rbv::ResolvedArg::LateBound(debruijn, _, _))
|
||||||
if debruijn < self.outer_index => {}
|
if debruijn < self.outer_index =>
|
||||||
|
{
|
||||||
|
ControlFlow::Continue(())
|
||||||
|
}
|
||||||
Some(
|
Some(
|
||||||
rbv::ResolvedArg::LateBound(..)
|
rbv::ResolvedArg::LateBound(..)
|
||||||
| rbv::ResolvedArg::Free(..)
|
| rbv::ResolvedArg::Free(..)
|
||||||
| rbv::ResolvedArg::Error(_),
|
| rbv::ResolvedArg::Error(_),
|
||||||
)
|
)
|
||||||
| None => {
|
| None => ControlFlow::Break(lt.ident.span),
|
||||||
self.has_late_bound_regions = Some(lt.ident.span);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -513,11 +505,7 @@ fn has_late_bound_regions<'tcx>(
|
|||||||
generics: &'tcx hir::Generics<'tcx>,
|
generics: &'tcx hir::Generics<'tcx>,
|
||||||
decl: &'tcx hir::FnDecl<'tcx>,
|
decl: &'tcx hir::FnDecl<'tcx>,
|
||||||
) -> Option<Span> {
|
) -> Option<Span> {
|
||||||
let mut visitor = LateBoundRegionsDetector {
|
let mut visitor = LateBoundRegionsDetector { tcx, outer_index: ty::INNERMOST };
|
||||||
tcx,
|
|
||||||
outer_index: ty::INNERMOST,
|
|
||||||
has_late_bound_regions: None,
|
|
||||||
};
|
|
||||||
for param in generics.params {
|
for param in generics.params {
|
||||||
if let GenericParamKind::Lifetime { .. } = param.kind {
|
if let GenericParamKind::Lifetime { .. } = param.kind {
|
||||||
if tcx.is_late_bound(param.hir_id) {
|
if tcx.is_late_bound(param.hir_id) {
|
||||||
@ -525,8 +513,7 @@ fn has_late_bound_regions<'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visitor.visit_fn_decl(decl);
|
visitor.visit_fn_decl(decl).break_value()
|
||||||
visitor.has_late_bound_regions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let decl = node.fn_decl()?;
|
let decl = node.fn_decl()?;
|
||||||
@ -536,26 +523,29 @@ fn has_late_bound_regions<'tcx>(
|
|||||||
|
|
||||||
struct AnonConstInParamTyDetector {
|
struct AnonConstInParamTyDetector {
|
||||||
in_param_ty: bool,
|
in_param_ty: bool,
|
||||||
found_anon_const_in_param_ty: bool,
|
|
||||||
ct: HirId,
|
ct: HirId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
|
impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
|
||||||
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
|
type Result = ControlFlow<()>;
|
||||||
|
|
||||||
|
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) -> Self::Result {
|
||||||
if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
|
if let GenericParamKind::Const { ty, default: _, is_host_effect: _, synthetic: _ } = p.kind
|
||||||
{
|
{
|
||||||
let prev = self.in_param_ty;
|
let prev = self.in_param_ty;
|
||||||
self.in_param_ty = true;
|
self.in_param_ty = true;
|
||||||
self.visit_ty(ty);
|
let res = self.visit_ty(ty);
|
||||||
self.in_param_ty = prev;
|
self.in_param_ty = prev;
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
ControlFlow::Continue(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
|
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) -> Self::Result {
|
||||||
if self.in_param_ty && self.ct == c.hir_id {
|
if self.in_param_ty && self.ct == c.hir_id {
|
||||||
self.found_anon_const_in_param_ty = true;
|
return ControlFlow::Break(());
|
||||||
} else {
|
|
||||||
intravisit::walk_anon_const(self, c)
|
|
||||||
}
|
}
|
||||||
|
intravisit::walk_anon_const(self, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,8 +104,6 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
|
impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
|
||||||
type Result = ();
|
|
||||||
|
|
||||||
fn span(&self) -> Span {
|
fn span(&self) -> Span {
|
||||||
self.root_cause.span
|
self.root_cause.span
|
||||||
}
|
}
|
||||||
|
@ -805,10 +805,11 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.contains(&data.trait_ref(self.tcx).def_id);
|
.contains(&data.trait_ref(self.tcx).def_id);
|
||||||
|
|
||||||
|
// only walk contained types if it's not a super trait
|
||||||
if is_supertrait_of_current_trait {
|
if is_supertrait_of_current_trait {
|
||||||
ControlFlow::Continue(()) // do not walk contained types, do not report error, do collect $200
|
ControlFlow::Continue(())
|
||||||
} else {
|
} else {
|
||||||
t.super_visit_with(self) // DO walk contained types, POSSIBLY reporting an error
|
t.super_visit_with(self) // POSSIBLY reporting an error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => t.super_visit_with(self), // walk contained types, if any
|
_ => t.super_visit_with(self), // walk contained types, if any
|
||||||
|
@ -640,8 +640,6 @@ fn from_object_ty(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
|
||||||
type Result = ();
|
|
||||||
|
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
|
||||||
debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
|
debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user