1
Fork 0

Rollup merge of #121563 - Jarcho:use_cf, r=petrochenkov

Use `ControlFlow` in visitors.

Follow up to #121256

This does have a few small behaviour changes in some diagnostic output where the visitor will now find the first match rather than the last match. The change in `find_anon_types.rs` has the only affected test. I don't see this being an issue as the last occurrence isn't any better of a choice than the first.
This commit is contained in:
Matthias Krüger 2024-03-08 13:22:26 +01:00 committed by GitHub
commit 3e634f8c5c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 240 additions and 270 deletions

View file

@ -1,4 +1,5 @@
use super::LoweringContext; use super::LoweringContext;
use core::ops::ControlFlow;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::visit::Visitor; use rustc_ast::visit::Visitor;
use rustc_ast::*; use rustc_ast::*;
@ -594,30 +595,32 @@ fn expand_format_args<'hir>(
} }
fn may_contain_yield_point(e: &ast::Expr) -> bool { fn may_contain_yield_point(e: &ast::Expr) -> bool {
struct MayContainYieldPoint(bool); struct MayContainYieldPoint;
impl Visitor<'_> for MayContainYieldPoint { impl Visitor<'_> for MayContainYieldPoint {
fn visit_expr(&mut self, e: &ast::Expr) { type Result = ControlFlow<()>;
fn visit_expr(&mut self, e: &ast::Expr) -> ControlFlow<()> {
if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind { if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
self.0 = true; ControlFlow::Break(())
} else { } else {
visit::walk_expr(self, e); visit::walk_expr(self, e);
ControlFlow::Continue(())
} }
} }
fn visit_mac_call(&mut self, _: &ast::MacCall) { fn visit_mac_call(&mut self, _: &ast::MacCall) -> ControlFlow<()> {
// Macros should be expanded at this point. // Macros should be expanded at this point.
unreachable!("unexpanded macro in ast lowering"); unreachable!("unexpanded macro in ast lowering");
} }
fn visit_item(&mut self, _: &ast::Item) { fn visit_item(&mut self, _: &ast::Item) -> ControlFlow<()> {
// Do not recurse into nested items. // Do not recurse into nested items.
ControlFlow::Continue(())
} }
} }
let mut visitor = MayContainYieldPoint(false); MayContainYieldPoint.visit_expr(e).is_break()
visitor.visit_expr(e);
visitor.0
} }
fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) { fn for_all_argument_indexes(template: &mut [FormatArgsPiece], mut f: impl FnMut(&mut usize)) {

View file

@ -1,6 +1,7 @@
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
use core::ops::ControlFlow;
use hir::ExprKind; use hir::ExprKind;
use rustc_errors::{Applicability, Diag}; use rustc_errors::{Applicability, Diag};
use rustc_hir as hir; use rustc_hir as hir;
@ -727,30 +728,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
_ => local_decl.source_info.span, _ => local_decl.source_info.span,
}; };
struct BindingFinder {
span: Span,
hir_id: Option<hir::HirId>,
}
impl<'tcx> Visitor<'tcx> for BindingFinder {
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
if let hir::StmtKind::Local(local) = s.kind {
if local.pat.span == self.span {
self.hir_id = Some(local.hir_id);
}
}
hir::intravisit::walk_stmt(self, s);
}
}
let def_id = self.body.source.def_id(); let def_id = self.body.source.def_id();
let hir_id = if let Some(local_def_id) = def_id.as_local() let hir_id = if let Some(local_def_id) = def_id.as_local()
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
{ {
let body = self.infcx.tcx.hir().body(body_id); let body = self.infcx.tcx.hir().body(body_id);
let mut v = BindingFinder { span: pat_span, hir_id: None }; BindingFinder { span: pat_span }.visit_body(body).break_value()
v.visit_body(body);
v.hir_id
} else { } else {
None None
}; };
@ -859,17 +842,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}; };
let hir_map = self.infcx.tcx.hir(); let hir_map = self.infcx.tcx.hir();
struct Finder<'tcx> { struct Finder {
span: Span, span: Span,
expr: Option<&'tcx Expr<'tcx>>,
} }
impl<'tcx> Visitor<'tcx> for Finder<'tcx> { impl<'tcx> Visitor<'tcx> for Finder {
fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) { type Result = ControlFlow<&'tcx Expr<'tcx>>;
if e.span == self.span && self.expr.is_none() { fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) -> Self::Result {
self.expr = Some(e); if e.span == self.span {
ControlFlow::Break(e)
} else {
hir::intravisit::walk_expr(self, e)
} }
hir::intravisit::walk_expr(self, e);
} }
} }
if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id()) if let Some(body_id) = hir_map.maybe_body_owned_by(self.mir_def_id())
@ -878,9 +862,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// `span` corresponds to the expression being iterated, find the `for`-loop desugared // `span` corresponds to the expression being iterated, find the `for`-loop desugared
// expression with that span in order to identify potential fixes when encountering a // expression with that span in order to identify potential fixes when encountering a
// read-only iterator that should be mutable. // read-only iterator that should be mutable.
let mut v = Finder { span, expr: None }; if let ControlFlow::Break(expr) = (Finder { span }).visit_block(block)
v.visit_block(block);
if let Some(expr) = v.expr
&& let Call(_, [expr]) = expr.kind && let Call(_, [expr]) = expr.kind
{ {
match expr.kind { match expr.kind {
@ -1179,29 +1161,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
); );
} }
Some((false, err_label_span, message)) => { Some((false, err_label_span, message)) => {
struct BindingFinder {
span: Span,
hir_id: Option<hir::HirId>,
}
impl<'tcx> Visitor<'tcx> for BindingFinder {
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
if let hir::StmtKind::Local(local) = s.kind {
if local.pat.span == self.span {
self.hir_id = Some(local.hir_id);
}
}
hir::intravisit::walk_stmt(self, s);
}
}
let def_id = self.body.source.def_id(); let def_id = self.body.source.def_id();
let hir_id = if let Some(local_def_id) = def_id.as_local() let hir_id = if let Some(local_def_id) = def_id.as_local()
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
{ {
let body = self.infcx.tcx.hir().body(body_id); let body = self.infcx.tcx.hir().body(body_id);
let mut v = BindingFinder { span: err_label_span, hir_id: None }; BindingFinder { span: err_label_span }.visit_body(body).break_value()
v.visit_body(body);
v.hir_id
} else { } else {
None None
}; };
@ -1333,6 +1298,23 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} }
} }
struct BindingFinder {
span: Span,
}
impl<'tcx> Visitor<'tcx> for BindingFinder {
type Result = ControlFlow<hir::HirId>;
fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) -> Self::Result {
if let hir::StmtKind::Local(local) = s.kind
&& local.pat.span == self.span
{
ControlFlow::Break(local.hir_id)
} else {
hir::intravisit::walk_stmt(self, s)
}
}
}
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool { pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());

View file

@ -6,6 +6,7 @@
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(min_specialization)] #![feature(min_specialization)]
#![feature(never_type)] #![feature(never_type)]

View file

@ -1,5 +1,6 @@
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute}; use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
use core::ops::ControlFlow;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::mut_visit::MutVisitor; use rustc_ast::mut_visit::MutVisitor;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
@ -87,41 +88,40 @@ fn flat_map_annotatable(
} }
} }
struct CfgFinder { fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
has_cfg_or_cfg_attr: bool, struct CfgFinder;
}
impl CfgFinder { impl<'ast> visit::Visitor<'ast> for CfgFinder {
fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool { type Result = ControlFlow<()>;
let mut finder = CfgFinder { has_cfg_or_cfg_attr: false }; fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> {
match annotatable { if attr
Annotatable::Item(item) => finder.visit_item(item),
Annotatable::TraitItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Trait),
Annotatable::ImplItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Impl),
Annotatable::ForeignItem(item) => finder.visit_foreign_item(item),
Annotatable::Stmt(stmt) => finder.visit_stmt(stmt),
Annotatable::Expr(expr) => finder.visit_expr(expr),
Annotatable::Arm(arm) => finder.visit_arm(arm),
Annotatable::ExprField(field) => finder.visit_expr_field(field),
Annotatable::PatField(field) => finder.visit_pat_field(field),
Annotatable::GenericParam(param) => finder.visit_generic_param(param),
Annotatable::Param(param) => finder.visit_param(param),
Annotatable::FieldDef(field) => finder.visit_field_def(field),
Annotatable::Variant(variant) => finder.visit_variant(variant),
Annotatable::Crate(krate) => finder.visit_crate(krate),
};
finder.has_cfg_or_cfg_attr
}
}
impl<'ast> visit::Visitor<'ast> for CfgFinder {
fn visit_attribute(&mut self, attr: &'ast Attribute) {
// We want short-circuiting behavior, so don't use the '|=' operator.
self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr
|| attr
.ident() .ident()
.is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr); .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
{
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
} }
}
}
let res = match annotatable {
Annotatable::Item(item) => CfgFinder.visit_item(item),
Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait),
Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl),
Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
Annotatable::Arm(arm) => CfgFinder.visit_arm(arm),
Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field),
Annotatable::PatField(field) => CfgFinder.visit_pat_field(field),
Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param),
Annotatable::Param(param) => CfgFinder.visit_param(param),
Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field),
Annotatable::Variant(variant) => CfgFinder.visit_variant(variant),
Annotatable::Crate(krate) => CfgFinder.visit_crate(krate),
};
res.is_break()
} }
impl CfgEval<'_, '_> { impl CfgEval<'_, '_> {
@ -132,7 +132,7 @@ impl CfgEval<'_, '_> {
fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> { fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
// Tokenizing and re-parsing the `Annotatable` can have a significant // Tokenizing and re-parsing the `Annotatable` can have a significant
// performance impact, so try to avoid it if possible // performance impact, so try to avoid it if possible
if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) { if !has_cfg_or_cfg_attr(&annotatable) {
return Some(annotatable); return Some(annotatable);
} }

View file

@ -1,6 +1,7 @@
use crate::deriving::generic::ty::*; use crate::deriving::generic::ty::*;
use crate::deriving::generic::*; use crate::deriving::generic::*;
use crate::errors; use crate::errors;
use core::ops::ControlFlow;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::visit::walk_list; use rustc_ast::visit::walk_list;
use rustc_ast::{attr, EnumDef, VariantData}; use rustc_ast::{attr, EnumDef, VariantData};
@ -231,20 +232,19 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
} }
fn has_a_default_variant(item: &Annotatable) -> bool { fn has_a_default_variant(item: &Annotatable) -> bool {
struct HasDefaultAttrOnVariant { struct HasDefaultAttrOnVariant;
found: bool,
}
impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant { impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) { type Result = ControlFlow<()>;
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)) {
self.found = true; ControlFlow::Break(())
} } else {
// no need to subrecurse. // no need to subrecurse.
ControlFlow::Continue(())
}
} }
} }
let mut visitor = HasDefaultAttrOnVariant { found: false }; item.visit_with(&mut HasDefaultAttrOnVariant).is_break()
item.visit_with(&mut visitor);
visitor.found
} }

View file

@ -1,5 +1,6 @@
use super::potentially_plural_count; use super::potentially_plural_count;
use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture}; use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
use core::ops::ControlFlow;
use hir::def_id::{DefId, DefIdMap, LocalDefId}; use hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
@ -1565,24 +1566,24 @@ fn compare_synthetic_generics<'tcx>(
let (sig, _) = impl_m.expect_fn(); let (sig, _) = impl_m.expect_fn();
let input_tys = sig.decl.inputs; let input_tys = sig.decl.inputs;
struct Visitor(Option<Span>, hir::def_id::LocalDefId); struct Visitor(hir::def_id::LocalDefId);
impl<'v> intravisit::Visitor<'v> for Visitor { impl<'v> intravisit::Visitor<'v> for Visitor {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { type Result = ControlFlow<Span>;
intravisit::walk_ty(self, ty); fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) -> Self::Result {
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind
&& let Res::Def(DefKind::TyParam, def_id) = path.res && let Res::Def(DefKind::TyParam, def_id) = path.res
&& def_id == self.1.to_def_id() && def_id == self.0.to_def_id()
{ {
self.0 = Some(ty.span); ControlFlow::Break(ty.span)
} else {
intravisit::walk_ty(self, ty)
} }
} }
} }
let mut visitor = Visitor(None, impl_def_id); let span = input_tys.iter().find_map(|ty| {
for ty in input_tys { intravisit::Visitor::visit_ty(&mut Visitor(impl_def_id), ty).break_value()
intravisit::Visitor::visit_ty(&mut visitor, ty); })?;
}
let span = visitor.0?;
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds; let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds;
let bounds = bounds.first()?.span().to(bounds.last()?.span()); let bounds = bounds.first()?.span().to(bounds.last()?.span());

View file

@ -6,6 +6,7 @@
//! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file //! the types in HIR to identify late-bound lifetimes and assign their Debruijn indices. This file
//! is also responsible for assigning their semantics to implicit lifetimes in trait objects. //! is also responsible for assigning their semantics to implicit lifetimes in trait objects.
use core::ops::ControlFlow;
use rustc_ast::visit::walk_list; use rustc_ast::visit::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::{codes::*, struct_span_code_err}; use rustc_errors::{codes::*, struct_span_code_err};
@ -417,23 +418,18 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
{ {
if let &hir::ClosureBinder::For { span: for_sp, .. } = binder { if let &hir::ClosureBinder::For { span: for_sp, .. } = binder {
fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> { fn span_of_infer(ty: &hir::Ty<'_>) -> Option<Span> {
struct V(Option<Span>); struct V;
impl<'v> Visitor<'v> for V { impl<'v> Visitor<'v> for V {
fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { type Result = ControlFlow<Span>;
match t.kind { fn visit_ty(&mut self, t: &'v hir::Ty<'v>) -> Self::Result {
_ if self.0.is_some() => (), if matches!(t.kind, hir::TyKind::Infer) {
hir::TyKind::Infer => { ControlFlow::Break(t.span)
self.0 = Some(t.span); } else {
} intravisit::walk_ty(self, t)
_ => intravisit::walk_ty(self, t),
} }
} }
} }
V.visit_ty(ty).break_value()
let mut v = V(None);
v.visit_ty(ty);
v.0
} }
let infer_in_rt_sp = match fn_decl.output { let infer_in_rt_sp = match fn_decl.output {

View file

@ -1,3 +1,4 @@
use core::ops::ControlFlow;
use rustc_errors::{Applicability, StashKey}; use rustc_errors::{Applicability, StashKey};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
@ -675,19 +676,16 @@ pub fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
if tcx.features().lazy_type_alias { if tcx.features().lazy_type_alias {
return true; return true;
} }
struct HasTait { struct HasTait;
has_type_alias_impl_trait: bool,
}
impl<'tcx> Visitor<'tcx> for HasTait { impl<'tcx> Visitor<'tcx> for HasTait {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) -> Self::Result {
if let hir::TyKind::OpaqueDef(..) = t.kind { if let hir::TyKind::OpaqueDef(..) = t.kind {
self.has_type_alias_impl_trait = true; ControlFlow::Break(())
} else { } else {
hir::intravisit::walk_ty(self, t); hir::intravisit::walk_ty(self, t)
} }
} }
} }
let mut has_tait = HasTait { has_type_alias_impl_trait: false }; HasTait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break()
has_tait.visit_ty(tcx.hir().expect_item(def_id).expect_ty_alias().0);
has_tait.has_type_alias_impl_trait
} }

View file

@ -6,6 +6,7 @@
use crate::errors::{self, CandidateTraitNote, NoAssociatedItem}; use crate::errors::{self, CandidateTraitNote, NoAssociatedItem};
use crate::Expectation; use crate::Expectation;
use crate::FnCtxt; use crate::FnCtxt;
use core::ops::ControlFlow;
use rustc_ast::ast::Mutability; use rustc_ast::ast::Mutability;
use rustc_attr::parse_confusables; use rustc_attr::parse_confusables;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@ -2212,30 +2213,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let map = self.infcx.tcx.hir(); let map = self.infcx.tcx.hir();
let body_id = self.tcx.hir().body_owned_by(self.body_id); let body_id = self.tcx.hir().body_owned_by(self.body_id);
let body = map.body(body_id); let body = map.body(body_id);
struct LetVisitor<'a> { struct LetVisitor {
result: Option<&'a hir::Expr<'a>>,
ident_name: Symbol, ident_name: Symbol,
} }
// FIXME: This really should be taking scoping, etc into account. // FIXME: This really should be taking scoping, etc into account.
impl<'v> Visitor<'v> for LetVisitor<'v> { impl<'v> Visitor<'v> for LetVisitor {
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
if let hir::StmtKind::Local(hir::Local { pat, init, .. }) = &ex.kind fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
if let hir::StmtKind::Local(&hir::Local { pat, init, .. }) = ex.kind
&& let Binding(_, _, ident, ..) = pat.kind && let Binding(_, _, ident, ..) = pat.kind
&& ident.name == self.ident_name && ident.name == self.ident_name
{ {
self.result = *init; ControlFlow::Break(init)
} else { } else {
hir::intravisit::walk_stmt(self, ex); hir::intravisit::walk_stmt(self, ex)
} }
} }
} }
let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
visitor.visit_body(body);
if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id) if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
&& let Some(expr) = visitor.result && let ControlFlow::Break(Some(expr)) =
(LetVisitor { ident_name: seg1.ident.name }).visit_body(body)
&& let Some(self_ty) = self.node_ty_opt(expr.hir_id) && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
{ {
let probe = self.lookup_probe_for_diagnostic( let probe = self.lookup_probe_for_diagnostic(

View file

@ -79,7 +79,7 @@ use rustc_middle::ty::{
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span}; use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi; use rustc_target::spec::abi;
use std::borrow::Cow; use std::borrow::Cow;
use std::ops::Deref; use std::ops::{ControlFlow, Deref};
use std::path::PathBuf; use std::path::PathBuf;
use std::{cmp, fmt, iter}; use std::{cmp, fmt, iter};
@ -2129,15 +2129,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let tykind = match self.tcx.opt_hir_node_by_def_id(trace.cause.body_id) { let tykind = match self.tcx.opt_hir_node_by_def_id(trace.cause.body_id) {
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => { Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) => {
let body = hir.body(*body_id); let body = hir.body(*body_id);
struct LetVisitor<'v> { struct LetVisitor {
span: Span, span: Span,
result: Option<&'v hir::Ty<'v>>,
}
impl<'v> Visitor<'v> for LetVisitor<'v> {
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) {
if self.result.is_some() {
return;
} }
impl<'v> Visitor<'v> for LetVisitor {
type Result = ControlFlow<&'v hir::TyKind<'v>>;
fn visit_stmt(&mut self, s: &'v hir::Stmt<'v>) -> Self::Result {
// Find a local statement where the initializer has // Find a local statement where the initializer has
// the same span as the error and the type is specified. // the same span as the error and the type is specified.
if let hir::Stmt { if let hir::Stmt {
@ -2151,13 +2148,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
} = s } = s
&& init_span == &self.span && init_span == &self.span
{ {
self.result = Some(*array_ty); ControlFlow::Break(&array_ty.peel_refs().kind)
} else {
ControlFlow::Continue(())
} }
} }
} }
let mut visitor = LetVisitor { span, result: None }; LetVisitor { span }.visit_body(body).break_value()
visitor.visit_body(body);
visitor.result.map(|r| &r.peel_refs().kind)
} }
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => { Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => {
Some(&ty.peel_refs().kind) Some(&ty.peel_refs().kind)

View file

@ -1,3 +1,4 @@
use core::ops::ControlFlow;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
@ -43,14 +44,9 @@ fn find_component_for_bound_region<'tcx>(
arg: &'tcx hir::Ty<'tcx>, arg: &'tcx hir::Ty<'tcx>,
br: &ty::BoundRegionKind, br: &ty::BoundRegionKind,
) -> Option<&'tcx hir::Ty<'tcx>> { ) -> Option<&'tcx hir::Ty<'tcx>> {
let mut nested_visitor = FindNestedTypeVisitor { FindNestedTypeVisitor { tcx, bound_region: *br, current_index: ty::INNERMOST }
tcx, .visit_ty(arg)
bound_region: *br, .break_value()
found_type: None,
current_index: ty::INNERMOST,
};
nested_visitor.visit_ty(arg);
nested_visitor.found_type
} }
// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the // The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
@ -65,26 +61,24 @@ struct FindNestedTypeVisitor<'tcx> {
// The bound_region corresponding to the Refree(freeregion) // The bound_region corresponding to the Refree(freeregion)
// associated with the anonymous region we are looking for. // associated with the anonymous region we are looking for.
bound_region: ty::BoundRegionKind, bound_region: ty::BoundRegionKind,
// The type where the anonymous lifetime appears
// for e.g., Vec<`&u8`> and <`&u8`>
found_type: Option<&'tcx hir::Ty<'tcx>>,
current_index: ty::DebruijnIndex, current_index: ty::DebruijnIndex,
} }
impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
type Result = ControlFlow<&'tcx hir::Ty<'tcx>>;
type NestedFilter = nested_filter::OnlyBodies; type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Self::Map { fn nested_visit_map(&mut self) -> Self::Map {
self.tcx.hir() self.tcx.hir()
} }
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
match arg.kind { match arg.kind {
hir::TyKind::BareFn(_) => { hir::TyKind::BareFn(_) => {
self.current_index.shift_in(1); self.current_index.shift_in(1);
intravisit::walk_ty(self, arg); intravisit::walk_ty(self, arg);
self.current_index.shift_out(1); self.current_index.shift_out(1);
return; return ControlFlow::Continue(());
} }
hir::TyKind::TraitObject(bounds, ..) => { hir::TyKind::TraitObject(bounds, ..) => {
@ -105,8 +99,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id); debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id { if id == def_id {
self.found_type = Some(arg); return ControlFlow::Break(arg);
return; // we can stop visiting now
} }
} }
@ -123,8 +116,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
); );
debug!("LateBound id={:?} def_id={:?}", id, def_id); debug!("LateBound id={:?} def_id={:?}", id, def_id);
if debruijn_index == self.current_index && id == def_id { if debruijn_index == self.current_index && id == def_id {
self.found_type = Some(arg); return ControlFlow::Break(arg);
return; // we can stop visiting now
} }
} }
@ -145,23 +137,30 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
} }
// Checks if it is of type `hir::TyKind::Path` which corresponds to a struct. // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
hir::TyKind::Path(_) => { hir::TyKind::Path(_) => {
let subvisitor = &mut TyPathVisitor { // Prefer using the lifetime in type arguments rather than lifetime arguments.
intravisit::walk_ty(self, arg)?;
// Call `walk_ty` as `visit_ty` is empty.
return if intravisit::walk_ty(
&mut TyPathVisitor {
tcx: self.tcx, tcx: self.tcx,
found_it: false,
bound_region: self.bound_region, bound_region: self.bound_region,
current_index: self.current_index, current_index: self.current_index,
},
arg,
)
.is_break()
{
ControlFlow::Break(arg)
} else {
ControlFlow::Continue(())
}; };
intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
// this will visit only outermost type
if subvisitor.found_it {
self.found_type = Some(arg);
}
} }
_ => {} _ => {}
} }
// walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
// go on to visit `&Foo` // go on to visit `&Foo`
intravisit::walk_ty(self, arg); intravisit::walk_ty(self, arg)
} }
} }
@ -173,26 +172,25 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
// specific part of the type in the error message. // specific part of the type in the error message.
struct TyPathVisitor<'tcx> { struct TyPathVisitor<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
found_it: bool,
bound_region: ty::BoundRegionKind, bound_region: ty::BoundRegionKind,
current_index: ty::DebruijnIndex, current_index: ty::DebruijnIndex,
} }
impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
type Result = ControlFlow<()>;
type NestedFilter = nested_filter::OnlyBodies; type NestedFilter = nested_filter::OnlyBodies;
fn nested_visit_map(&mut self) -> Map<'tcx> { fn nested_visit_map(&mut self) -> Map<'tcx> {
self.tcx.hir() self.tcx.hir()
} }
fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result {
match (self.tcx.named_bound_var(lifetime.hir_id), self.bound_region) { match (self.tcx.named_bound_var(lifetime.hir_id), self.bound_region) {
// the lifetime of the TyPath! // the lifetime of the TyPath!
(Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => {
debug!("EarlyBound id={:?} def_id={:?}", id, def_id); debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
if id == def_id { if id == def_id {
self.found_it = true; return ControlFlow::Break(());
return; // we can stop visiting now
} }
} }
@ -201,8 +199,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
debug!("id={:?}", id); debug!("id={:?}", id);
debug!("def_id={:?}", def_id); debug!("def_id={:?}", def_id);
if debruijn_index == self.current_index && id == def_id { if debruijn_index == self.current_index && id == def_id {
self.found_it = true; return ControlFlow::Break(());
return; // we can stop visiting now
} }
} }
@ -220,9 +217,10 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
debug!("no arg found"); debug!("no arg found");
} }
} }
ControlFlow::Continue(())
} }
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) -> Self::Result {
// ignore nested types // ignore nested types
// //
// If you have a type like `Foo<'a, &Ty>` we // If you have a type like `Foo<'a, &Ty>` we
@ -231,5 +229,6 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
// Making `visit_ty` empty will ignore the `&Ty` embedded // Making `visit_ty` empty will ignore the `&Ty` embedded
// inside, it will get reached by the outer visitor. // inside, it will get reached by the outer visitor.
debug!("`Ty` corresponding to a struct is {:?}", arg); debug!("`Ty` corresponding to a struct is {:?}", arg);
ControlFlow::Continue(())
} }
} }

View file

@ -1,4 +1,5 @@
use crate::infer::error_reporting::hir::Path; use crate::infer::error_reporting::hir::Path;
use core::ops::ControlFlow;
use hir::def::CtorKind; use hir::def::CtorKind;
use hir::intravisit::{walk_expr, walk_stmt, Visitor}; use hir::intravisit::{walk_expr, walk_stmt, Visitor};
use hir::{Local, QPath}; use hir::{Local, QPath};
@ -563,33 +564,27 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
cause: &ObligationCause<'_>, cause: &ObligationCause<'_>,
span: Span, span: Span,
) -> Option<TypeErrorAdditionalDiags> { ) -> Option<TypeErrorAdditionalDiags> {
let hir = self.tcx.hir();
if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(cause.body_id) {
let body = hir.body(body_id);
/// Find the if expression with given span /// Find the if expression with given span
struct IfVisitor { struct IfVisitor {
pub result: bool,
pub found_if: bool, pub found_if: bool,
pub err_span: Span, pub err_span: Span,
} }
impl<'v> Visitor<'v> for IfVisitor { impl<'v> Visitor<'v> for IfVisitor {
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { type Result = ControlFlow<()>;
if self.result { fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
return;
}
match ex.kind { match ex.kind {
hir::ExprKind::If(cond, _, _) => { hir::ExprKind::If(cond, _, _) => {
self.found_if = true; self.found_if = true;
walk_expr(self, cond); walk_expr(self, cond)?;
self.found_if = false; self.found_if = false;
ControlFlow::Continue(())
} }
_ => walk_expr(self, ex), _ => walk_expr(self, ex),
} }
} }
fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) { fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
if let hir::StmtKind::Local(hir::Local { if let hir::StmtKind::Local(hir::Local {
span, span,
pat: hir::Pat { .. }, pat: hir::Pat { .. },
@ -600,25 +595,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
&& self.found_if && self.found_if
&& span.eq(&self.err_span) && span.eq(&self.err_span)
{ {
self.result = true; ControlFlow::Break(())
} } else {
walk_stmt(self, ex); walk_stmt(self, ex)
}
fn visit_body(&mut self, body: &'v hir::Body<'v>) {
hir::intravisit::walk_body(self, body);
} }
} }
let mut visitor = IfVisitor { err_span: span, found_if: false, result: false }; fn visit_body(&mut self, body: &'v hir::Body<'v>) -> Self::Result {
visitor.visit_body(body); hir::intravisit::walk_body(self, body)
if visitor.result {
return Some(TypeErrorAdditionalDiags::AddLetForLetChains {
span: span.shrink_to_lo(),
});
} }
} }
None
self.tcx.hir().maybe_body_owned_by(cause.body_id).and_then(|body_id| {
let body = self.tcx.hir().body(body_id);
IfVisitor { err_span: span, found_if: false }
.visit_body(body)
.is_break()
.then(|| TypeErrorAdditionalDiags::AddLetForLetChains { span: span.shrink_to_lo() })
})
} }
/// For "one type is more general than the other" errors on closures, suggest changing the lifetime /// For "one type is more general than the other" errors on closures, suggest changing the lifetime

View file

@ -20,6 +20,7 @@
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![feature(associated_type_bounds)] #![feature(associated_type_bounds)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(control_flow_enum)]
#![feature(extend_one)] #![feature(extend_one)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(if_let_guard)] #![feature(if_let_guard)]

View file

@ -20,6 +20,7 @@ use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span}; use rustc_span::{BytePos, Span};
use std::iter; use std::iter;
use std::ops::ControlFlow;
declare_lint! { declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as /// The `unused_must_use` lint detects unused result of a type flagged as
@ -753,21 +754,18 @@ trait UnusedDelimLint {
// fn f(){(print!(á // fn f(){(print!(á
// ``` // ```
use rustc_ast::visit::{walk_expr, Visitor}; use rustc_ast::visit::{walk_expr, Visitor};
struct ErrExprVisitor { struct ErrExprVisitor;
has_error: bool,
}
impl<'ast> Visitor<'ast> for ErrExprVisitor { impl<'ast> Visitor<'ast> for ErrExprVisitor {
fn visit_expr(&mut self, expr: &'ast ast::Expr) { type Result = ControlFlow<()>;
fn visit_expr(&mut self, expr: &'ast ast::Expr) -> ControlFlow<()> {
if let ExprKind::Err(_) = expr.kind { if let ExprKind::Err(_) = expr.kind {
self.has_error = true; ControlFlow::Break(())
return; } else {
}
walk_expr(self, expr) walk_expr(self, expr)
} }
} }
let mut visitor = ErrExprVisitor { has_error: false }; }
visitor.visit_expr(value); if ErrExprVisitor.visit_expr(value).is_break() {
if visitor.has_error {
return; return;
} }
let spans = match value.kind { let spans = match value.kind {

View file

@ -13,13 +13,14 @@ use ast::mut_visit::{noop_visit_expr, MutVisitor};
use ast::token::IdentIsRaw; use ast::token::IdentIsRaw;
use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment}; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, Pat, Path, PathSegment};
use core::mem; use core::mem;
use core::ops::ControlFlow;
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::token::{self, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::Spacing; use rustc_ast::tokenstream::Spacing;
use rustc_ast::util::case::Case; use rustc_ast::util::case::Case;
use rustc_ast::util::classify; use rustc_ast::util::classify;
use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity};
use rustc_ast::visit::Visitor; use rustc_ast::visit::{walk_expr, Visitor};
use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID}; use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, UnOp, DUMMY_NODE_ID};
use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind}; use rustc_ast::{AnonConst, BinOp, BinOpKind, FnDecl, FnRetTy, MacCall, Param, Ty, TyKind};
use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits}; use rustc_ast::{Arm, BlockCheckMode, Expr, ExprKind, Label, Movability, RangeLimits};
@ -1703,19 +1704,20 @@ impl<'a> Parser<'a> {
let span = expr.span; let span = expr.span;
let found_labeled_breaks = { let found_labeled_breaks = {
struct FindLabeledBreaksVisitor(bool); struct FindLabeledBreaksVisitor;
impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor { impl<'ast> Visitor<'ast> for FindLabeledBreaksVisitor {
fn visit_expr_post(&mut self, ex: &'ast Expr) { type Result = ControlFlow<()>;
fn visit_expr(&mut self, ex: &'ast Expr) -> ControlFlow<()> {
if let ExprKind::Break(Some(_label), _) = ex.kind { if let ExprKind::Break(Some(_label), _) = ex.kind {
self.0 = true; ControlFlow::Break(())
} else {
walk_expr(self, ex)
} }
} }
} }
let mut vis = FindLabeledBreaksVisitor(false); FindLabeledBreaksVisitor.visit_expr(&expr).is_break()
vis.visit_expr(&expr);
vis.0
}; };
// Suggestion involves adding a labeled block. // Suggestion involves adding a labeled block.

View file

@ -19,6 +19,7 @@ use crate::traits::{
ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation, ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation,
SelectionError, SignatureMismatch, TraitNotObjectSafe, SelectionError, SignatureMismatch, TraitNotObjectSafe,
}; };
use core::ops::ControlFlow;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::codes::*; use rustc_errors::codes::*;
use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart}; use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
@ -1126,32 +1127,30 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
err: &mut Diag<'_>, err: &mut Diag<'_>,
) -> bool { ) -> bool {
let span = obligation.cause.span; let span = obligation.cause.span;
struct V<'v> { struct V {
search_span: Span, search_span: Span,
found: Option<&'v hir::Expr<'v>>,
} }
impl<'v> Visitor<'v> for V<'v> { impl<'v> Visitor<'v> for V {
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { type Result = ControlFlow<&'v hir::Expr<'v>>;
fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) -> Self::Result {
if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind if let hir::ExprKind::Match(expr, _arms, hir::MatchSource::TryDesugar(_)) = ex.kind
&& ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span)
&& let hir::ExprKind::Call(_, [expr, ..]) = expr.kind
{ {
if ex.span.with_lo(ex.span.hi() - BytePos(1)).source_equal(self.search_span) { ControlFlow::Break(expr)
if let hir::ExprKind::Call(_, [expr, ..]) = expr.kind { } else {
self.found = Some(expr); hir::intravisit::walk_expr(self, ex)
return;
} }
} }
} }
hir::intravisit::walk_expr(self, ex);
}
}
let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
let body_id = match self.tcx.hir_node(hir_id) { let body_id = match self.tcx.hir_node(hir_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => body_id, hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) => body_id,
_ => return false, _ => return false,
}; };
let mut v = V { search_span: span, found: None }; let ControlFlow::Break(expr) =
v.visit_body(self.tcx.hir().body(*body_id)); (V { search_span: span }).visit_body(self.tcx.hir().body(*body_id))
let Some(expr) = v.found else { else {
return false; return false;
}; };
let Some(typeck) = &self.typeck_results else { let Some(typeck) = &self.typeck_results else {

View file

@ -4,11 +4,11 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) { LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: first, the lifetime cannot outlive the anonymous lifetime defined here... note: first, the lifetime cannot outlive the anonymous lifetime as defined here...
--> $DIR/issue-20831-debruijn.rs:28:58 --> $DIR/issue-20831-debruijn.rs:28:18
| |
LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) { LL | fn subscribe(&mut self, t : Box<dyn Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^
note: ...but the lifetime must also be valid for the lifetime `'a` as defined here... note: ...but the lifetime must also be valid for the lifetime `'a` as defined here...
--> $DIR/issue-20831-debruijn.rs:26:6 --> $DIR/issue-20831-debruijn.rs:26:6
| |