diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 7e63826647835..1f195916c774a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -668,11 +668,10 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let params = arena_vec![self; param]; + let coroutine_kind = + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, async_coroutine_source); let body = self.lower_body(move |this| { - this.coroutine_kind = Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - async_coroutine_source, - )); + this.coroutine_kind = Some(coroutine_kind); let old_ctx = this.task_context; this.task_context = Some(task_context_hid); @@ -691,7 +690,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(span), fn_arg_span: None, - movability: Some(hir::Movability::Static), + kind: hir::ClosureKind::Coroutine(coroutine_kind), constness: hir::Constness::NotConst, })) } @@ -725,11 +724,10 @@ impl<'hir> LoweringContext<'_, 'hir> { lifetime_elision_allowed: false, }); + let coroutine_kind = + hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, coroutine_source); let body = self.lower_body(move |this| { - this.coroutine_kind = Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - coroutine_source, - )); + this.coroutine_kind = Some(coroutine_kind); let res = body(this); (&[], res) @@ -745,7 +743,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(span), fn_arg_span: None, - movability: Some(Movability::Movable), + kind: hir::ClosureKind::Coroutine(coroutine_kind), constness: hir::Constness::NotConst, })) } @@ -806,11 +804,12 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let params = arena_vec![self; param]; + let coroutine_kind = hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + async_coroutine_source, + ); let body = self.lower_body(move |this| { - this.coroutine_kind = Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - async_coroutine_source, - )); + this.coroutine_kind = Some(coroutine_kind); let old_ctx = this.task_context; this.task_context = Some(task_context_hid); @@ -829,7 +828,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(span), fn_arg_span: None, - movability: Some(hir::Movability::Static), + kind: hir::ClosureKind::Coroutine(coroutine_kind), constness: hir::Constness::NotConst, })) } @@ -898,7 +897,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let is_async_gen = match self.coroutine_kind { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, - Some(hir::CoroutineKind::Coroutine) + Some(hir::CoroutineKind::Coroutine(_)) | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) | None => { return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks { @@ -1086,7 +1085,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let (binder_clause, generic_params) = self.lower_closure_binder(binder); - let (body_id, coroutine_option) = self.with_new_scopes(fn_decl_span, move |this| { + let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| { let mut coroutine_kind = None; let body_id = this.lower_fn_body(decl, |this| { let e = this.lower_expr_mut(body); @@ -1094,7 +1093,7 @@ impl<'hir> LoweringContext<'_, 'hir> { e }); let coroutine_option = - this.coroutine_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); + this.closure_movability_for_fn(decl, fn_decl_span, coroutine_kind, movability); (body_id, coroutine_option) }); @@ -1111,26 +1110,26 @@ impl<'hir> LoweringContext<'_, 'hir> { body: body_id, fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), - movability: coroutine_option, + kind: closure_kind, constness: self.lower_constness(constness), }); hir::ExprKind::Closure(c) } - fn coroutine_movability_for_fn( + fn closure_movability_for_fn( &mut self, decl: &FnDecl, fn_decl_span: Span, coroutine_kind: Option, movability: Movability, - ) -> Option { + ) -> hir::ClosureKind { match coroutine_kind { - Some(hir::CoroutineKind::Coroutine) => { + Some(hir::CoroutineKind::Coroutine(_)) => { if decl.inputs.len() > 1 { self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span }); } - Some(movability) + hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(movability)) } Some( hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) @@ -1143,7 +1142,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if movability == Movability::Static { self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span }); } - None + hir::ClosureKind::Closure } } } @@ -1235,7 +1234,7 @@ impl<'hir> LoweringContext<'_, 'hir> { body, fn_decl_span: self.lower_span(fn_decl_span), fn_arg_span: Some(self.lower_span(fn_arg_span)), - movability: None, + kind: hir::ClosureKind::Closure, constness: hir::Constness::NotConst, }); hir::ExprKind::Closure(c) @@ -1655,7 +1654,19 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(AsyncCoroutinesNotSupported { span }), ); } - Some(hir::CoroutineKind::Coroutine) | None => { + Some(hir::CoroutineKind::Coroutine(_)) => { + if !self.tcx.features().coroutines { + rustc_session::parse::feature_err( + &self.tcx.sess.parse_sess, + sym::coroutines, + span, + "yield syntax is experimental", + ) + .emit(); + } + false + } + None => { if !self.tcx.features().coroutines { rustc_session::parse::feature_err( &self.tcx.sess.parse_sess, @@ -1665,7 +1676,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) .emit(); } - self.coroutine_kind = Some(hir::CoroutineKind::Coroutine); + self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable)); false } }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 81457018b37af..b70b935622635 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -952,11 +952,7 @@ impl<'hir> LoweringContext<'_, 'hir> { params: &'hir [hir::Param<'hir>], value: hir::Expr<'hir>, ) -> hir::BodyId { - let body = hir::Body { - coroutine_kind: self.coroutine_kind, - params, - value: self.arena.alloc(value), - }; + let body = hir::Body { params, value: self.arena.alloc(value) }; let id = body.id(); debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); self.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index da6fffc167c72..ca65488375ce3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -848,8 +848,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { move_spans.var_subdiag(None, &mut err, None, |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { - Some(_) => MoveUseInCoroutine { var_span }, - None => MoveUseInClosure { var_span }, + hir::ClosureKind::Coroutine(_) => MoveUseInCoroutine { var_span }, + hir::ClosureKind::Closure => MoveUseInClosure { var_span }, } }); @@ -893,10 +893,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let place = &borrow.borrowed_place; let desc_place = self.describe_any_place(place.as_ref()); match kind { - Some(_) => { + hir::ClosureKind::Coroutine(_) => { BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true } } - None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true }, + hir::ClosureKind::Closure => { + BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true } + } } }); @@ -1040,12 +1042,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { - Some(_) => BorrowUsePlaceCoroutine { + hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: true, }, - None => BorrowUsePlaceClosure { + hir::ClosureKind::Closure => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true, @@ -1124,12 +1126,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { - Some(_) => BorrowUsePlaceCoroutine { + hir::ClosureKind::Coroutine(_) => BorrowUsePlaceCoroutine { place: desc_place, var_span, is_single_var: false, }, - None => { + hir::ClosureKind::Closure => { BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false } } } @@ -1144,10 +1146,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let borrow_place = &issued_borrow.borrowed_place; let borrow_place_desc = self.describe_any_place(borrow_place.as_ref()); match kind { - Some(_) => { + hir::ClosureKind::Coroutine(_) => { FirstBorrowUsePlaceCoroutine { place: borrow_place_desc, var_span } } - None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span }, + hir::ClosureKind::Closure => { + FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span } + } } }, ); @@ -1159,8 +1163,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { - Some(_) => SecondBorrowUsePlaceCoroutine { place: desc_place, var_span }, - None => SecondBorrowUsePlaceClosure { place: desc_place, var_span }, + hir::ClosureKind::Coroutine(_) => { + SecondBorrowUsePlaceCoroutine { place: desc_place, var_span } + } + hir::ClosureKind::Closure => { + SecondBorrowUsePlaceClosure { place: desc_place, var_span } + } } }, ); @@ -1651,7 +1659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { if e.span.contains(self.capture_span) { if let hir::ExprKind::Closure(&hir::Closure { - movability: None, + kind: hir::ClosureKind::Closure, body, fn_arg_span, fn_decl: hir::FnDecl { inputs, .. }, @@ -1686,7 +1694,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let Some(init) = local.init { if let hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { movability: None, .. }), + kind: + hir::ExprKind::Closure(&hir::Closure { + kind: hir::ClosureKind::Closure, + .. + }), .. } = init && init.span.contains(self.capture_span) @@ -2537,7 +2549,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } } - CoroutineKind::Coroutine => "coroutine", + CoroutineKind::Coroutine(_) => "coroutine", }, None => "closure", }; @@ -2838,8 +2850,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { - Some(_) => BorrowUseInCoroutine { var_span }, - None => BorrowUseInClosure { var_span }, + hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, + hir::ClosureKind::Closure => BorrowUseInClosure { var_span }, } }); @@ -2854,8 +2866,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| { use crate::session_diagnostics::CaptureVarCause::*; match kind { - Some(_) => BorrowUseInCoroutine { var_span }, - None => BorrowUseInClosure { var_span }, + hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span }, + hir::ClosureKind::Closure => BorrowUseInClosure { var_span }, } }); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 65dee9d0e0098..c14a05bd145a3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -505,7 +505,7 @@ pub(super) enum UseSpans<'tcx> { /// The access is caused by capturing a variable for a closure. ClosureUse { /// This is true if the captured variable was from a coroutine. - coroutine_kind: Option, + closure_kind: hir::ClosureKind, /// The span of the args of the closure, including the `move` keyword if /// it's present. args_span: Span, @@ -572,9 +572,13 @@ impl UseSpans<'_> { } } + // FIXME(coroutines): Make this just return the `ClosureKind` directly? pub(super) fn coroutine_kind(self) -> Option { match self { - UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind, + UseSpans::ClosureUse { + closure_kind: hir::ClosureKind::Coroutine(coroutine_kind), + .. + } => Some(coroutine_kind), _ => None, } } @@ -599,9 +603,9 @@ impl UseSpans<'_> { ) { use crate::InitializationRequiringAction::*; use CaptureVarPathUseCause::*; - if let UseSpans::ClosureUse { coroutine_kind, path_span, .. } = self { - match coroutine_kind { - Some(_) => { + if let UseSpans::ClosureUse { closure_kind, path_span, .. } = self { + match closure_kind { + hir::ClosureKind::Coroutine(_) => { err.subdiagnostic(match action { Borrow => BorrowInCoroutine { path_span }, MatchOn | Use => UseInCoroutine { path_span }, @@ -609,7 +613,7 @@ impl UseSpans<'_> { PartialAssignment => AssignPartInCoroutine { path_span }, }); } - None => { + hir::ClosureKind::Closure => { err.subdiagnostic(match action { Borrow => BorrowInClosure { path_span }, MatchOn | Use => UseInClosure { path_span }, @@ -627,9 +631,9 @@ impl UseSpans<'_> { dcx: Option<&rustc_errors::DiagCtxt>, err: &mut Diagnostic, kind: Option, - f: impl FnOnce(Option, Span) -> CaptureVarCause, + f: impl FnOnce(hir::ClosureKind, Span) -> CaptureVarCause, ) { - if let UseSpans::ClosureUse { coroutine_kind, capture_kind_span, path_span, .. } = self { + if let UseSpans::ClosureUse { closure_kind, capture_kind_span, path_span, .. } = self { if capture_kind_span != path_span { err.subdiagnostic(match kind { Some(kd) => match kd { @@ -645,7 +649,7 @@ impl UseSpans<'_> { None => CaptureVarKind::Move { kind_span: capture_kind_span }, }); }; - let diag = f(coroutine_kind, path_span); + let diag = f(closure_kind, path_span); match dcx { Some(hd) => err.eager_subdiagnostic(hd, diag), None => err.subdiagnostic(diag), @@ -656,7 +660,9 @@ impl UseSpans<'_> { /// Returns `false` if this place is not used in a closure. pub(super) fn for_closure(&self) -> bool { match *self { - UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_none(), + UseSpans::ClosureUse { closure_kind, .. } => { + matches!(closure_kind, hir::ClosureKind::Closure) + } _ => false, } } @@ -664,7 +670,10 @@ impl UseSpans<'_> { /// Returns `false` if this place is not used in a coroutine. pub(super) fn for_coroutine(&self) -> bool { match *self { - UseSpans::ClosureUse { coroutine_kind, .. } => coroutine_kind.is_some(), + // FIXME(coroutines): Do we want this to apply to synthetic coroutines? + UseSpans::ClosureUse { closure_kind, .. } => { + matches!(closure_kind, hir::ClosureKind::Coroutine(..)) + } _ => false, } } @@ -788,10 +797,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { debug!("move_spans: def_id={:?} places={:?}", def_id, places); let def_id = def_id.expect_local(); - if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) = + if let Some((args_span, closure_kind, capture_kind_span, path_span)) = self.closure_span(def_id, moved_place, places) { - return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span }; + return ClosureUse { closure_kind, args_span, capture_kind_span, path_span }; } } @@ -803,11 +812,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | FakeReadCause::ForLet(Some(closure_def_id)) => { debug!("move_spans: def_id={:?} place={:?}", closure_def_id, place); let places = &[Operand::Move(place)]; - if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) = + if let Some((args_span, closure_kind, capture_kind_span, path_span)) = self.closure_span(closure_def_id, moved_place, IndexSlice::from_raw(places)) { return ClosureUse { - coroutine_kind, + closure_kind, args_span, capture_kind_span, path_span, @@ -928,10 +937,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "borrow_spans: def_id={:?} is_coroutine={:?} places={:?}", def_id, is_coroutine, places ); - if let Some((args_span, coroutine_kind, capture_kind_span, path_span)) = + if let Some((args_span, closure_kind, capture_kind_span, path_span)) = self.closure_span(def_id, Place::from(target).as_ref(), places) { - return ClosureUse { coroutine_kind, args_span, capture_kind_span, path_span }; + return ClosureUse { closure_kind, args_span, capture_kind_span, path_span }; } else { return OtherUse(use_span); } @@ -953,7 +962,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { def_id: LocalDefId, target_place: PlaceRef<'tcx>, places: &IndexSlice>, - ) -> Option<(Span, Option, Span, Span)> { + ) -> Option<(Span, hir::ClosureKind, Span, Span)> { debug!( "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places @@ -961,7 +970,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id); let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); - if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr { + if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr { for (captured_place, place) in self.infcx.tcx.closure_captures(def_id).iter().zip(places) { @@ -970,12 +979,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if target_place == place.as_ref() => { debug!("closure_span: found captured local {:?}", place); - let body = self.infcx.tcx.hir().body(body); - let coroutine_kind = body.coroutine_kind(); - return Some(( fn_decl_span, - coroutine_kind, + kind, captured_place.get_capture_kind_span(self.infcx.tcx), captured_place.get_path_span(self.infcx.tcx), )); @@ -1242,8 +1248,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // another message for the same span if !is_loop_message { move_spans.var_subdiag(None, err, None, |kind, var_span| match kind { - Some(_) => CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial }, - None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial }, + hir::ClosureKind::Coroutine(_) => { + CaptureVarCause::PartialMoveUseInCoroutine { var_span, is_partial } + } + hir::ClosureKind::Closure => { + CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial } + } }) } } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 506933c470e25..3b3d440df97b5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1030,8 +1030,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let hir = self.infcx.tcx.hir(); if let InstanceDef::Item(def_id) = source.instance && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id) - && let ExprKind::Closure(closure) = kind - && closure.movability == None + && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id) { let mut cur_expr = expr; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 8387eaed61c79..b3450b09cdf9e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1041,13 +1041,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } hir::ExprKind::Closure(hir::Closure { capture_clause: hir::CaptureBy::Ref, - body, + kind, .. }) => { - let body = map.body(*body); if !matches!( - body.coroutine_kind, - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) + kind, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + _ + ),) ) { closure_span = Some(expr.span.shrink_to_lo()); } diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 73dc7a9600f1a..4cb49362863fc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -674,7 +674,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) { hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, body, fn_decl_span, .. }), + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, kind, fn_decl_span, .. }), .. }) => { let (mut span, mut hir_ty) = match fn_decl.output { @@ -683,62 +683,86 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } hir::FnRetTy::Return(hir_ty) => (fn_decl.output.span(), Some(hir_ty)), }; - let mir_description = match hir.body(body).coroutine_kind { - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, src)) => { - match src { - hir::CoroutineSource::Block => " of async block", - hir::CoroutineSource::Closure => " of async closure", - hir::CoroutineSource::Fn => { - let parent_item = - tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); - let output = &parent_item - .fn_decl() - .expect("coroutine lowered from async fn should be in fn") - .output; - span = output.span(); - if let hir::FnRetTy::Return(ret) = output { - hir_ty = Some(self.get_future_inner_return_ty(*ret)); - } - " of async function" - } + let mir_description = match kind { + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + )) => " of async block", + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )) => " of async closure", + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + )) => { + let parent_item = + tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); + let output = &parent_item + .fn_decl() + .expect("coroutine lowered from async fn should be in fn") + .output; + span = output.span(); + if let hir::FnRetTy::Return(ret) = output { + hir_ty = Some(self.get_future_inner_return_ty(*ret)); } + " of async function" } - Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, src)) => { - match src { - hir::CoroutineSource::Block => " of gen block", - hir::CoroutineSource::Closure => " of gen closure", - hir::CoroutineSource::Fn => { - let parent_item = - tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); - let output = &parent_item - .fn_decl() - .expect("coroutine lowered from gen fn should be in fn") - .output; - span = output.span(); - " of gen function" - } - } + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + )) => " of gen block", + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + )) => " of gen closure", + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + )) => { + let parent_item = + tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); + let output = &parent_item + .fn_decl() + .expect("coroutine lowered from gen fn should be in fn") + .output; + span = output.span(); + " of gen function" } - Some(hir::CoroutineKind::Desugared( + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::AsyncGen, - src, - )) => match src { - hir::CoroutineSource::Block => " of async gen block", - hir::CoroutineSource::Closure => " of async gen closure", - hir::CoroutineSource::Fn => { - let parent_item = - tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); - let output = &parent_item - .fn_decl() - .expect("coroutine lowered from async gen fn should be in fn") - .output; - span = output.span(); - " of async gen function" - } - }, - Some(hir::CoroutineKind::Coroutine) => " of coroutine", - None => " of closure", + hir::CoroutineSource::Block, + )) => " of async gen block", + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + )) => " of async gen closure", + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + )) => { + let parent_item = + tcx.hir_node_by_def_id(hir.get_parent_item(mir_hir_id).def_id); + let output = &parent_item + .fn_decl() + .expect("coroutine lowered from async gen fn should be in fn") + .output; + span = output.span(); + " of async gen function" + } + + hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => { + " of coroutine" + } + hir::ClosureKind::Closure => " of closure", }; (span, mir_description, hir_ty) } diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 1b01fe0365462..4f9f70648bd88 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -585,7 +585,7 @@ fn coroutine_kind_label(coroutine_kind: Option) -> &'static str { Some(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, CoroutineSource::Fn)) => { "async_gen_fn" } - Some(CoroutineKind::Coroutine) => "coroutine", + Some(CoroutineKind::Coroutine(_)) => "coroutine", None => "closure", } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index c1ab62ac0b86e..92955c4ed14ca 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -938,8 +938,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), - TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { - self.check_op(ops::Coroutine(hir::CoroutineKind::Coroutine)) + TerminatorKind::Yield { .. } => self.check_op(ops::Coroutine( + self.tcx + .coroutine_kind(self.body.source.def_id()) + .expect("Only expected to have a yield in a coroutine"), + )), + + TerminatorKind::CoroutineDrop => { + span_bug!( + self.body.source_info(location).span, + "We should not encounter TerminatorKind::CoroutineDrop after coroutine transform" + ); } TerminatorKind::UnwindTerminate(_) => { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 452f5d0b7ace9..2b8408601663c 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -945,7 +945,18 @@ pub struct Closure<'hir> { pub fn_decl_span: Span, /// The span of the argument block `|...|` pub fn_arg_span: Option, - pub movability: Option, + pub kind: ClosureKind, +} + +#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash, HashStable_Generic, Encodable, Decodable)] +pub enum ClosureKind { + /// This is a plain closure expression. + Closure, + /// This is a coroutine expression -- i.e. a closure expression in which + /// we've found a `yield`. These can arise either from "plain" coroutine + /// usage (e.g. `let x = || { yield (); }`) or from a desugared expression + /// (e.g. `async` and `gen` blocks). + Coroutine(CoroutineKind), } /// A block of statements `{ .. }`, which may have a label (in this case the @@ -1335,17 +1346,12 @@ pub struct BodyId { pub struct Body<'hir> { pub params: &'hir [Param<'hir>], pub value: &'hir Expr<'hir>, - pub coroutine_kind: Option, } impl<'hir> Body<'hir> { pub fn id(&self) -> BodyId { BodyId { hir_id: self.value.hir_id } } - - pub fn coroutine_kind(&self) -> Option { - self.coroutine_kind - } } /// The type of source expression that caused this coroutine to be created. @@ -1355,7 +1361,18 @@ pub enum CoroutineKind { Desugared(CoroutineDesugaring, CoroutineSource), /// A coroutine literal created via a `yield` inside a closure. - Coroutine, + Coroutine(Movability), +} + +impl CoroutineKind { + pub fn movability(self) -> Movability { + match self { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + | CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) => Movability::Static, + CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => Movability::Movable, + CoroutineKind::Coroutine(mov) => mov, + } + } } impl fmt::Display for CoroutineKind { @@ -1365,7 +1382,7 @@ impl fmt::Display for CoroutineKind { d.fmt(f)?; k.fmt(f) } - CoroutineKind::Coroutine => f.write_str("coroutine"), + CoroutineKind::Coroutine(_) => f.write_str("coroutine"), } } } @@ -3661,7 +3678,7 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(Block<'_>, 48); - static_assert_size!(Body<'_>, 32); + static_assert_size!(Body<'_>, 24); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 48); static_assert_size!(FnDecl<'_>, 40); diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 67e058a3219ec..e58e4c8fe0edb 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -757,7 +757,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) capture_clause: _, fn_decl_span: _, fn_arg_span: _, - movability: _, + kind: _, constness: _, }) => { walk_list!(visitor, visit_generic_param, bound_generic_params); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 34d3f20d0cfa9..eab83c7a25467 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -824,10 +824,6 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> { resolve_local(self, None, Some(body.value)); } - if body.coroutine_kind.is_some() { - self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count); - } - // Restore context we had at the start. self.expr_and_pat_count = outer_ec; self.cx = outer_cx; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 4513653b64481..8aeab2ca67e39 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1551,10 +1551,14 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { match tcx.hir_node_by_def_id(def_id) { - Node::Expr(&rustc_hir::Expr { - kind: rustc_hir::ExprKind::Closure(&rustc_hir::Closure { body, .. }), + Node::Expr(&hir::Expr { + kind: + hir::ExprKind::Closure(&rustc_hir::Closure { + kind: hir::ClosureKind::Coroutine(kind), + .. + }), .. - }) => tcx.hir().body(body).coroutine_kind(), + }) => Some(kind), _ => None, } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 4abebb4596674..5abc752309ad5 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -338,14 +338,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // cares about anything but the length is instantiation, // and we don't do that for closures. if let Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { movability: gen, .. }), - .. + kind: hir::ExprKind::Closure(hir::Closure { kind, .. }), .. }) = node { - let dummy_args = if gen.is_some() { - &["", "", "", "", ""][..] - } else { - &["", "", ""][..] + let dummy_args = match kind { + ClosureKind::Closure => &["", "", ""][..], + ClosureKind::Coroutine(_) => { + &["", "", "", "", ""][..] + } }; params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index feaec5ac620ef..d6eea07cfbc38 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1407,7 +1407,7 @@ impl<'a> State<'a> { body, fn_decl_span: _, fn_arg_span: _, - movability: _, + kind: _, def_id: _, }) => { self.print_closure_binder(binder, bound_generic_params); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2f8ad96deb430..de2cb5a6d5c7c 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -298,17 +298,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_node = self.tcx.hir_node(parent_hir_id); if let ( hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, body, .. }), + kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, kind, .. }), .. }), hir::ExprKind::Block(..), ) = (parent_node, callee_node) { - let fn_decl_span = if hir.body(body).coroutine_kind - == Some(hir::CoroutineKind::Desugared( + let fn_decl_span = if matches!( + kind, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure, - )) { + hir::CoroutineSource::Closure + ),) + ) { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... let async_closure = hir.parent_id(parent_hir_id); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index f4bcee384a740..984c2829c81b6 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -31,7 +31,7 @@ pub(super) fn check_fn<'a, 'tcx>( decl: &'tcx hir::FnDecl<'tcx>, fn_def_id: LocalDefId, body: &'tcx hir::Body<'tcx>, - can_be_coroutine: Option, + closure_kind: Option, params_can_be_unsized: bool, ) -> Option> { let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id); @@ -55,12 +55,10 @@ pub(super) fn check_fn<'a, 'tcx>( forbid_intrinsic_abi(tcx, span, fn_sig.abi); - if let Some(kind) = body.coroutine_kind - && can_be_coroutine.is_some() - { + if let Some(hir::ClosureKind::Coroutine(kind)) = closure_kind { let yield_ty = match kind { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) - | hir::CoroutineKind::Coroutine => { + | hir::CoroutineKind::Coroutine(_) => { let yield_ty = fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span, @@ -151,9 +149,7 @@ pub(super) fn check_fn<'a, 'tcx>( // We insert the deferred_coroutine_interiors entry after visiting the body. // This ensures that all nested coroutines appear before the entry of this coroutine. // resolve_coroutine_interiors relies on this property. - let coroutine_ty = if let (Some(_), Some(coroutine_kind)) = - (can_be_coroutine, body.coroutine_kind) - { + let coroutine_ty = if let Some(hir::ClosureKind::Coroutine(coroutine_kind)) = closure_kind { let interior = fcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); fcx.deferred_coroutine_interiors.borrow_mut().push(( @@ -168,7 +164,7 @@ pub(super) fn check_fn<'a, 'tcx>( resume_ty, yield_ty, interior, - movability: can_be_coroutine.unwrap(), + movability: coroutine_kind.movability(), }) } else { None diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index cd42be28e6f04..c29ef375ce4c6 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -60,25 +60,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } None => (None, None), }; - let body = self.tcx.hir().body(closure.body); - self.check_closure(closure, expr_span, expected_kind, body, expected_sig) + + self.check_closure(closure, expr_span, expected_kind, expected_sig) } - #[instrument(skip(self, closure, body), level = "debug", ret)] + #[instrument(skip(self, closure), level = "debug", ret)] fn check_closure( &self, closure: &hir::Closure<'tcx>, expr_span: Span, opt_kind: Option, - body: &'tcx hir::Body<'tcx>, expected_sig: Option>, ) -> Ty<'tcx> { + let body = self.tcx.hir().body(closure.body); + trace!("decl = {:#?}", closure.fn_decl); let expr_def_id = closure.def_id; debug!(?expr_def_id); let ClosureSignatures { bound_sig, liberated_sig } = - self.sig_of_closure(expr_def_id, closure.fn_decl, body, expected_sig); + self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig); debug!(?bound_sig, ?liberated_sig); @@ -89,7 +90,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure.fn_decl, expr_def_id, body, - closure.movability, + Some(closure.kind), // Closure "rust-call" ABI doesn't support unsized params false, ); @@ -351,28 +352,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - body: &hir::Body<'_>, + closure_kind: hir::ClosureKind, expected_sig: Option>, ) -> ClosureSignatures<'tcx> { if let Some(e) = expected_sig { - self.sig_of_closure_with_expectation(expr_def_id, decl, body, e) + self.sig_of_closure_with_expectation(expr_def_id, decl, closure_kind, e) } else { - self.sig_of_closure_no_expectation(expr_def_id, decl, body) + self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind) } } /// If there is no expected signature, then we will convert the /// types that the user gave into a signature. - #[instrument(skip(self, expr_def_id, decl, body), level = "debug")] + #[instrument(skip(self, expr_def_id, decl), level = "debug")] fn sig_of_closure_no_expectation( &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - body: &hir::Body<'_>, + closure_kind: hir::ClosureKind, ) -> ClosureSignatures<'tcx> { - let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, body); + let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind); - self.closure_sigs(expr_def_id, body, bound_sig) + self.closure_sigs(expr_def_id, bound_sig) } /// Invoked to compute the signature of a closure expression. This @@ -422,24 +423,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// - `expected_sig`: the expected signature (if any). Note that /// this is missing a binder: that is, there may be late-bound /// regions with depth 1, which are bound then by the closure. - #[instrument(skip(self, expr_def_id, decl, body), level = "debug")] + #[instrument(skip(self, expr_def_id, decl), level = "debug")] fn sig_of_closure_with_expectation( &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - body: &hir::Body<'_>, + closure_kind: hir::ClosureKind, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { // Watch out for some surprises and just ignore the // expectation if things don't see to match up with what we // expect. if expected_sig.sig.c_variadic() != decl.c_variadic { - return self.sig_of_closure_no_expectation(expr_def_id, decl, body); + return self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind); } else if expected_sig.sig.skip_binder().inputs_and_output.len() != decl.inputs.len() + 1 { return self.sig_of_closure_with_mismatched_number_of_arguments( expr_def_id, decl, - body, expected_sig, ); } @@ -463,16 +463,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // anonymize away, so as not to confuse the user. let bound_sig = self.tcx.anonymize_bound_vars(bound_sig); - let closure_sigs = self.closure_sigs(expr_def_id, body, bound_sig); + let closure_sigs = self.closure_sigs(expr_def_id, bound_sig); // Up till this point, we have ignored the annotations that the user // gave. This function will check that they unify successfully. // Along the way, it also writes out entries for types that the user // wrote into our typeck results, which are then later used by the privacy // check. - match self.merge_supplied_sig_with_expectation(expr_def_id, decl, body, closure_sigs) { + match self.merge_supplied_sig_with_expectation( + expr_def_id, + decl, + closure_kind, + closure_sigs, + ) { Ok(infer_ok) => self.register_infer_ok_obligations(infer_ok), - Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, body), + Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind), } } @@ -480,7 +485,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - body: &hir::Body<'_>, expected_sig: ExpectedSig<'tcx>, ) -> ClosureSignatures<'tcx> { let expr_map_node = self.tcx.hir_node_by_def_id(expr_def_id); @@ -511,25 +515,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let error_sig = self.error_sig_of_closure(decl, guar); - self.closure_sigs(expr_def_id, body, error_sig) + self.closure_sigs(expr_def_id, error_sig) } /// Enforce the user's types against the expectation. See /// `sig_of_closure_with_expectation` for details on the overall /// strategy. - #[instrument(level = "debug", skip(self, expr_def_id, decl, body, expected_sigs))] + #[instrument(level = "debug", skip(self, expr_def_id, decl, expected_sigs))] fn merge_supplied_sig_with_expectation( &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - body: &hir::Body<'_>, + closure_kind: hir::ClosureKind, mut expected_sigs: ClosureSignatures<'tcx>, ) -> InferResult<'tcx, ClosureSignatures<'tcx>> { // Get the signature S that the user gave. // // (See comment on `sig_of_closure_with_expectation` for the // meaning of these letters.) - let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, body); + let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind); debug!(?supplied_sig); @@ -611,17 +615,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// types that the user gave into a signature. /// /// Also, record this closure signature for later. - #[instrument(skip(self, decl, body), level = "debug", ret)] + #[instrument(skip(self, decl), level = "debug", ret)] fn supplied_sig_of_closure( &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - body: &hir::Body<'_>, + closure_kind: hir::ClosureKind, ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; trace!("decl = {:#?}", decl); - debug!(?body.coroutine_kind); + debug!(?closure_kind); let hir_id = self.tcx.local_def_id_to_hir_id(expr_def_id); let bound_vars = self.tcx.late_bound_vars(hir_id); @@ -630,36 +634,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let supplied_arguments = decl.inputs.iter().map(|a| astconv.ast_ty_to_ty(a)); let supplied_return = match decl.output { hir::FnRetTy::Return(ref output) => astconv.ast_ty_to_ty(output), - hir::FnRetTy::DefaultReturn(_) => match body.coroutine_kind { + hir::FnRetTy::DefaultReturn(_) => match closure_kind { // In the case of the async block that we create for a function body, // we expect the return type of the block to match that of the enclosing // function. - Some(hir::CoroutineKind::Desugared( + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( hir::CoroutineDesugaring::Async, hir::CoroutineSource::Fn, )) => { debug!("closure is async fn body"); - let def_id = self.tcx.hir().body_owner_def_id(body.id()); - self.deduce_future_output_from_obligations(expr_def_id, def_id).unwrap_or_else( - || { - // AFAIK, deducing the future output - // always succeeds *except* in error cases - // like #65159. I'd like to return Error - // here, but I can't because I can't - // easily (and locally) prove that we - // *have* reported an - // error. --nikomatsakis - astconv.ty_infer(None, decl.output.span()) - }, - ) + self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { + // AFAIK, deducing the future output + // always succeeds *except* in error cases + // like #65159. I'd like to return Error + // here, but I can't because I can't + // easily (and locally) prove that we + // *have* reported an + // error. --nikomatsakis + astconv.ty_infer(None, decl.output.span()) + }) } // All `gen {}` and `async gen {}` must return unit. - Some( + hir::ClosureKind::Coroutine( hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _), ) => self.tcx.types.unit, - _ => astconv.ty_infer(None, decl.output.span()), + // For async blocks, we just fall back to `_` here. + // For closures/coroutines, we know nothing about the return + // type unless it was supplied. + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + _, + )) + | hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) + | hir::ClosureKind::Closure => astconv.ty_infer(None, decl.output.span()), }, }; @@ -688,16 +697,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Future`, so we do this by searching through the /// obligations to extract the `T`. #[instrument(skip(self), level = "debug", ret)] - fn deduce_future_output_from_obligations( - &self, - expr_def_id: LocalDefId, - body_def_id: LocalDefId, - ) -> Option> { + fn deduce_future_output_from_obligations(&self, body_def_id: LocalDefId) -> Option> { let ret_coercion = self.ret_coercion.as_ref().unwrap_or_else(|| { - span_bug!(self.tcx.def_span(expr_def_id), "async fn coroutine outside of a fn") + span_bug!(self.tcx.def_span(body_def_id), "async fn coroutine outside of a fn") }); - let closure_span = self.tcx.def_span(expr_def_id); + let closure_span = self.tcx.def_span(body_def_id); let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty); @@ -842,12 +847,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn closure_sigs( &self, expr_def_id: LocalDefId, - body: &hir::Body<'_>, bound_sig: ty::PolyFnSig<'tcx>, ) -> ClosureSignatures<'tcx> { let liberated_sig = self.tcx().liberate_late_bound_regions(expr_def_id.to_def_id(), bound_sig); - let liberated_sig = self.normalize(body.value.span, liberated_sig); + let liberated_sig = self.normalize(self.tcx.def_span(expr_def_id), liberated_sig); ClosureSignatures { bound_sig, liberated_sig } } } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 916ff469e099a..306bf07a97608 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -199,7 +199,8 @@ fixed_size_enum! { fixed_size_enum! { hir::CoroutineKind { - ( Coroutine ) + ( Coroutine(hir::Movability::Movable) ) + ( Coroutine(hir::Movability::Static) ) ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Block) ) ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Fn) ) ( Desugared(hir::CoroutineDesugaring::Gen, hir::CoroutineSource::Closure) ) diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 3f6dc2b9f1261..b4dd8f6f4a781 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -307,11 +307,6 @@ pub struct ScopeTree { /// the values are still owned by their containing expressions. So /// we'll see that `&x`. pub yield_in_scope: FxHashMap>, - - /// The number of visit_expr and visit_pat calls done in the body. - /// Used to sanity check visit_expr/visit_pat call count when - /// calculating coroutine interiors. - pub body_expr_count: FxHashMap, } /// Identifies the reason that a given expression is an rvalue candidate @@ -408,20 +403,12 @@ impl ScopeTree { pub fn yield_in_scope(&self, scope: Scope) -> Option<&[YieldData]> { self.yield_in_scope.get(&scope).map(Deref::deref) } - - /// Gives the number of expressions visited in a body. - /// Used to sanity check visit_expr call count when - /// calculating coroutine interiors. - pub fn body_expr_count(&self, body_id: hir::BodyId) -> Option { - self.body_expr_count.get(&body_id).copied() - } } impl<'a> HashStable> for ScopeTree { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let ScopeTree { root_body, - ref body_expr_count, ref parent_map, ref var_map, ref destruction_scopes, @@ -430,7 +417,6 @@ impl<'a> HashStable> for ScopeTree { } = *self; root_body.hash_stable(hcx, hasher); - body_expr_count.hash_stable(hcx, hasher); parent_map.hash_stable(hcx, hasher); var_map.hash_stable(hcx, hasher); destruction_scopes.hash_stable(hcx, hasher); diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index e0c9def037948..7be6deb614193 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -147,7 +147,7 @@ impl AssertKind { Overflow(op, _, _) => bug!("{:?} cannot overflow", op), DivisionByZero(_) => "attempt to divide by zero", RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero", - ResumedAfterReturn(CoroutineKind::Coroutine) => "coroutine resumed after completion", + ResumedAfterReturn(CoroutineKind::Coroutine(_)) => "coroutine resumed after completion", ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { "`async fn` resumed after completion" } @@ -157,7 +157,7 @@ impl AssertKind { ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { "`gen fn` should just keep returning `None` after completion" } - ResumedAfterPanic(CoroutineKind::Coroutine) => "coroutine resumed after panicking", + ResumedAfterPanic(CoroutineKind::Coroutine(_)) => "coroutine resumed after panicking", ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { "`async fn` resumed after panicking" } @@ -262,7 +262,7 @@ impl AssertKind { ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { bug!("gen blocks can be resumed after they return and will keep returning `None`") } - ResumedAfterReturn(CoroutineKind::Coroutine) => { + ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { middle_assert_coroutine_resume_after_return } ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => { @@ -274,7 +274,7 @@ impl AssertKind { ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => { middle_assert_gen_resume_after_panic } - ResumedAfterPanic(CoroutineKind::Coroutine) => { + ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { middle_assert_coroutine_resume_after_panic } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ac675a70b546e..17691de630f1d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -858,7 +858,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns `true` if the node pointed to by `def_id` is a general coroutine that implements `Coroutine`. /// This means it is neither an `async` or `gen` construct. pub fn is_general_coroutine(self, def_id: DefId) -> bool { - matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Coroutine)) + matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Coroutine(_))) } /// Returns `true` if the node pointed to by `def_id` is a coroutine for a `gen` construct. diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8e045397b0ffa..13a5e881134d3 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -786,8 +786,8 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Coroutine(did, args, movability) => { p!(write("{{")); let coroutine_kind = self.tcx().coroutine_kind(did).unwrap(); - let should_print_movability = - self.should_print_verbose() || coroutine_kind == hir::CoroutineKind::Coroutine; + let should_print_movability = self.should_print_verbose() + || matches!(coroutine_kind, hir::CoroutineKind::Coroutine(_)); if should_print_movability { match movability { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 55dc72b19d3f4..5e24b47fbd2f0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -735,7 +735,7 @@ impl<'tcx> TyCtxt<'tcx> { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { "async gen closure" } - hir::CoroutineKind::Coroutine => "coroutine", + hir::CoroutineKind::Coroutine(_) => "coroutine", hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) => { "gen closure" } @@ -759,7 +759,7 @@ impl<'tcx> TyCtxt<'tcx> { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an", hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, ..) => "an", hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, ..) => "a", - hir::CoroutineKind::Coroutine => "a", + hir::CoroutineKind::Coroutine(_) => "a", } } _ => def_kind.article(), diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index d1d5b72af7063..05d8d842b5813 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -257,7 +257,7 @@ impl<'tcx> TransformVisitor<'tcx> { CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => { span_bug!(body.span, "`Future`s are not fused inherently") } - CoroutineKind::Coroutine => span_bug!(body.span, "`Coroutine`s cannot be fused"), + CoroutineKind::Coroutine(_) => span_bug!(body.span, "`Coroutine`s cannot be fused"), // `gen` continues return `None` CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => { let option_def_id = self.tcx.require_lang_item(LangItem::Option, None); @@ -396,7 +396,7 @@ impl<'tcx> TransformVisitor<'tcx> { Rvalue::Use(val) } } - CoroutineKind::Coroutine => { + CoroutineKind::Coroutine(_) => { let coroutine_state_def_id = self.tcx.require_lang_item(LangItem::CoroutineState, None); let args = self.tcx.mk_args(&[self.old_yield_ty.into(), self.old_ret_ty.into()]); @@ -1428,7 +1428,8 @@ fn create_coroutine_resume_function<'tcx>( if can_return { let block = match coroutine_kind { - CoroutineKind::Desugared(CoroutineDesugaring::Async, _) | CoroutineKind::Coroutine => { + CoroutineKind::Desugared(CoroutineDesugaring::Async, _) + | CoroutineKind::Coroutine(_) => { insert_panic_block(tcx, body, ResumedAfterReturn(coroutine_kind)) } CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _) @@ -1643,7 +1644,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // The yield ty is already `Poll>` old_yield_ty } - CoroutineKind::Coroutine => { + CoroutineKind::Coroutine(_) => { // Compute CoroutineState let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); let state_adt_ref = tcx.adt_def(state_did); diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 24db708196b85..0f8cc583b03cf 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -3,7 +3,7 @@ use Context::*; use rustc_hir as hir; use rustc_hir::def_id::{LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Destination, Movability, Node}; +use rustc_hir::{Destination, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -86,16 +86,15 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Loop(source), |v| v.visit_block(b)); } hir::ExprKind::Closure(&hir::Closure { - ref fn_decl, - body, - fn_decl_span, - movability, - .. + ref fn_decl, body, fn_decl_span, kind, .. }) => { - let cx = if let Some(Movability::Static) = movability { - AsyncClosure(fn_decl_span) - } else { - Closure(fn_decl_span) + // FIXME(coroutines): This doesn't handle coroutines correctly + let cx = match kind { + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + )) => AsyncClosure(fn_decl_span), + _ => Closure(fn_decl_span), }; self.visit_fn_decl(fn_decl); self.with_context(cx, |v| v.visit_nested_body(body)); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 5f505ac181cad..2446671770ecb 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -42,7 +42,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { type T = stable_mir::mir::CoroutineKind; fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { use rustc_hir::{CoroutineDesugaring, CoroutineKind}; - match self { + match *self { CoroutineKind::Desugared(CoroutineDesugaring::Async, source) => { stable_mir::mir::CoroutineKind::Desugared( stable_mir::mir::CoroutineDesugaring::Async, @@ -55,7 +55,9 @@ impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineKind { source.stable(tables), ) } - CoroutineKind::Coroutine => stable_mir::mir::CoroutineKind::Coroutine, + CoroutineKind::Coroutine(movability) => { + stable_mir::mir::CoroutineKind::Coroutine(movability.stable(tables)) + } CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, source) => { stable_mir::mir::CoroutineKind::Desugared( stable_mir::mir::CoroutineDesugaring::AsyncGen, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 13ac2e26e4080..52f91d282f0b6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -8,7 +8,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, ErrorGuaranteed}; use rustc_hir as hir; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; @@ -32,7 +32,7 @@ pub trait TypeErrCtxtExt<'tcx> { ) -> Option<(DefId, GenericArgsRef<'tcx>)>; /*private*/ - fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>; + fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str>; fn on_unimplemented_note( &self, @@ -101,43 +101,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { /// Used to set on_unimplemented's `ItemContext` /// to be the enclosing (async) block/function/closure - fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { - let hir = self.tcx.hir(); - let node = self.tcx.opt_hir_node(hir_id)?; - match &node { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { - self.describe_coroutine(*body_id).or_else(|| { - Some(match sig.header { - hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => { - "an async function" - } - _ => "a function", - }) - }) + fn describe_enclosure(&self, def_id: LocalDefId) -> Option<&'static str> { + match self.tcx.opt_hir_node_by_def_id(def_id)? { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. }) => Some("a function"), + hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. }) => { + Some("a trait method") + } + hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => { + Some("a method") } - hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)), - .. - }) => self.describe_coroutine(*body_id).or_else(|| Some("a trait method")), - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(sig, body_id), - .. - }) => self.describe_coroutine(*body_id).or_else(|| { - Some(match sig.header { - hir::FnHeader { asyncness: hir::IsAsync::Async(_), .. } => "an async method", - _ => "a method", - }) - }), hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(hir::Closure { body, movability, .. }), + kind: hir::ExprKind::Closure(hir::Closure { kind, .. }), .. - }) => self.describe_coroutine(*body).or_else(|| { - Some(if movability.is_some() { "an async closure" } else { "a closure" }) - }), - hir::Node::Expr(hir::Expr { .. }) => { - let parent_hid = hir.parent_id(hir_id); - if parent_hid != hir_id { self.describe_enclosure(parent_hid) } else { None } - } + }) => Some(self.describe_closure(*kind)), _ => None, } } @@ -156,12 +132,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs, // but I guess we could synthesize one here. We don't see any errors that rely on // that yet, though. - let enclosure = - if let Some(body_hir) = self.tcx.opt_local_def_id_to_hir_id(obligation.cause.body_id) { - self.describe_enclosure(body_hir).map(|s| s.to_owned()) - } else { - None - }; + let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned()); flags.push((sym::ItemContext, enclosure)); match obligation.cause.code() { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index e1f3c6d4f975a..171b86d4f2571 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2577,7 +2577,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let message = outer_coroutine .and_then(|coroutine_did| { Some(match self.tcx.coroutine_kind(coroutine_did).unwrap() { - CoroutineKind::Coroutine => format!("coroutine is not {trait_name}"), + CoroutineKind::Coroutine(_) => format!("coroutine is not {trait_name}"), CoroutineKind::Desugared( CoroutineDesugaring::Async, CoroutineSource::Fn, @@ -3169,7 +3169,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => { let what = match self.tcx.coroutine_kind(coroutine_def_id) { None - | Some(hir::CoroutineKind::Coroutine) + | Some(hir::CoroutineKind::Coroutine(_)) | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => { "yield" } @@ -3564,55 +3564,52 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) { - if let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { - let body = self.tcx.hir().body(body_id); - if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) = - body.coroutine_kind - { - let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) = + self.tcx.coroutine_kind(obligation.cause.body_id) + { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); - let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); - let impls_future = self.type_implements_trait( - future_trait, - [self.tcx.instantiate_bound_regions_with_erased(self_ty)], - obligation.param_env, - ); - if !impls_future.must_apply_modulo_regions() { - return; - } + let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty()); + let impls_future = self.type_implements_trait( + future_trait, + [self.tcx.instantiate_bound_regions_with_erased(self_ty)], + obligation.param_env, + ); + if !impls_future.must_apply_modulo_regions() { + return; + } - let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; - // `::Output` - let projection_ty = trait_pred.map_bound(|trait_pred| { - Ty::new_projection( - self.tcx, - item_def_id, - // Future::Output has no args - [trait_pred.self_ty()], - ) - }); - let InferOk { value: projection_ty, .. } = - self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); + let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0]; + // `::Output` + let projection_ty = trait_pred.map_bound(|trait_pred| { + Ty::new_projection( + self.tcx, + item_def_id, + // Future::Output has no args + [trait_pred.self_ty()], + ) + }); + let InferOk { value: projection_ty, .. } = + self.at(&obligation.cause, obligation.param_env).normalize(projection_ty); - debug!( - normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) - ); - let try_obligation = self.mk_trait_obligation_with_new_self_ty( - obligation.param_env, - trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), + debug!( + normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty) + ); + let try_obligation = self.mk_trait_obligation_with_new_self_ty( + obligation.param_env, + trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())), + ); + debug!(try_trait_obligation = ?try_obligation); + if self.predicate_may_hold(&try_obligation) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) + && snippet.ends_with('?') + { + err.span_suggestion_verbose( + span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await", + Applicability::MaybeIncorrect, ); - debug!(try_trait_obligation = ?try_obligation); - if self.predicate_may_hold(&try_obligation) - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) - && snippet.ends_with('?') - { - err.span_suggestion_verbose( - span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), - "consider `await`ing on the `Future`", - ".await", - Applicability::MaybeIncorrect, - ); - } } } } @@ -4665,13 +4662,7 @@ impl<'v> Visitor<'v> for ReturnsVisitor<'v> { fn visit_body(&mut self, body: &'v hir::Body<'v>) { assert!(!self.in_block_tail); - if body.coroutine_kind().is_none() { - if let hir::ExprKind::Block(block, None) = body.value.kind { - if block.expr.is_some() { - self.in_block_tail = true; - } - } - } + self.in_block_tail = true; hir::intravisit::walk_body(self, body); } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 4b84aae70fd10..d2598b0defe7f 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1348,7 +1348,7 @@ pub(super) trait InferCtxtPrivExt<'tcx> { ignoring_lifetimes: bool, ) -> Option; - fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str>; + fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str; fn find_similar_impl_candidates( &self, @@ -1925,46 +1925,49 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } - fn describe_coroutine(&self, body_id: hir::BodyId) -> Option<&'static str> { - self.tcx.hir().body(body_id).coroutine_kind.map(|coroutine_source| match coroutine_source { - hir::CoroutineKind::Coroutine => "a coroutine", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - ) => "an async block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Fn, - ) => "an async function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure, - ) => "an async closure", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Block, - ) => "an async gen block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Fn, - ) => "an async gen function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - hir::CoroutineSource::Closure, - ) => "an async gen closure", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Block, - ) => "a gen block", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Fn, - ) => "a gen function", - hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Gen, - hir::CoroutineSource::Closure, - ) => "a gen closure", - }) + fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { + match kind { + hir::ClosureKind::Closure => "a closure", + hir::ClosureKind::Coroutine(kind) => match kind { + hir::CoroutineKind::Coroutine(_) => "a coroutine", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Block, + ) => "an async block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + ) => "an async function", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + ) => "an async closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Block, + ) => "an async gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Fn, + ) => "an async gen function", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::AsyncGen, + hir::CoroutineSource::Closure, + ) => "an async gen closure", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Block, + ) => "a gen block", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Fn, + ) => "a gen function", + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Gen, + hir::CoroutineSource::Closure, + ) => "a gen closure", + }, + } } fn find_similar_impl_candidates( diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 86501b5a72d15..4756a45a44781 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -121,7 +121,7 @@ fn fn_sig_for_fn_abi<'tcx>( } hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) - | hir::CoroutineKind::Coroutine => Ty::new_adt(tcx, pin_adt_ref, pin_args), + | hir::CoroutineKind::Coroutine(_) => Ty::new_adt(tcx, pin_adt_ref, pin_args), }; // The `FnSig` and the `ret_ty` here is for a coroutines main @@ -192,7 +192,7 @@ fn fn_sig_for_fn_abi<'tcx>( (Some(context_mut_ref), ret_ty) } - hir::CoroutineKind::Coroutine => { + hir::CoroutineKind::Coroutine(_) => { // The signature should be `Coroutine::resume(_, Resume) -> CoroutineState` let state_did = tcx.require_lang_item(LangItem::CoroutineState, None); let state_adt_ref = tcx.adt_def(state_did); diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 89d75569ce3db..5871600bece4c 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -285,7 +285,7 @@ impl AssertMessage { AssertMessage::RemainderByZero(_) => { Ok("attempt to calculate the remainder with a divisor of zero") } - AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine) => { + AssertMessage::ResumedAfterReturn(CoroutineKind::Coroutine(_)) => { Ok("coroutine resumed after completion") } AssertMessage::ResumedAfterReturn(CoroutineKind::Desugared( @@ -300,7 +300,7 @@ impl AssertMessage { CoroutineDesugaring::AsyncGen, _, )) => Ok("`gen fn` should just keep returning `AssertMessage::None` after completion"), - AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine) => { + AssertMessage::ResumedAfterPanic(CoroutineKind::Coroutine(_)) => { Ok("coroutine resumed after panicking") } AssertMessage::ResumedAfterPanic(CoroutineKind::Desugared( @@ -399,7 +399,7 @@ pub enum UnOp { #[derive(Clone, Debug, Eq, PartialEq)] pub enum CoroutineKind { Desugared(CoroutineDesugaring, CoroutineSource), - Coroutine, + Coroutine(Movability), } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs index 28e6614f03fb6..c965341d3fdf6 100644 --- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs +++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_errors::Applicability; -use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, CoroutineDesugaring, ExprKind, QPath}; +use rustc_hir::{ + Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, QPath, +}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -44,15 +46,22 @@ declare_clippy_lint! { declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]); impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync { - fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { // For functions, with explicitly defined types, don't warn. // XXXkhuey maybe we should? - if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block | CoroutineSource::Closure)) = body.coroutine_kind { + if let ExprKind::Closure(Closure { + kind: + ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block | CoroutineSource::Closure, + )), + body: body_id, + .. + }) = expr.kind + { if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() { - let body_id = BodyId { - hir_id: body.value.hir_id, - }; - let typeck_results = cx.tcx.typeck_body(body_id); + let typeck_results = cx.tcx.typeck_body(*body_id); + let body = cx.tcx.hir().body(*body_id); let expr_ty = typeck_results.expr_ty(body.value); if implements_trait(cx, expr_ty, future_trait_def_id, &[]) { diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs index dff6e884fa118..765cc7c0a54fb 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -2,8 +2,8 @@ use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{Body, CoroutineKind, CoroutineDesugaring}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::CoroutineLayout; use rustc_session::impl_lint_pass; @@ -183,8 +183,8 @@ impl AwaitHolding { } } -impl LateLintPass<'_> for AwaitHolding { - fn check_crate(&mut self, cx: &LateContext<'_>) { +impl<'tcx> LateLintPass<'tcx> for AwaitHolding { + fn check_crate(&mut self, cx: &LateContext<'tcx>) { for conf in &self.conf_invalid_types { let segs: Vec<_> = conf.path().split("::").collect(); for id in clippy_utils::def_path_def_ids(cx, &segs) { @@ -193,10 +193,14 @@ impl LateLintPass<'_> for AwaitHolding { } } - fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) = body.coroutine_kind { - let def_id = cx.tcx.hir().body_owner_def_id(body.id()); - if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Closure(hir::Closure { + kind: hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)), + def_id, + .. + }) = expr.kind + { + if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) { self.check_interior_types(cx, coroutine_layout); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 8982ce5e196ec..9ba1d3afcbe9d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -3,8 +3,9 @@ use clippy_utils::source::{position_before_rarrow, snippet_block, snippet_opt}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; use rustc_hir::{ - Block, Body, Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound, - ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind, + Block, Body, Closure, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, + GenericArg, GenericBound, ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, + TypeBindingKind, ClosureKind, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -171,16 +172,25 @@ fn captures_all_lifetimes(inputs: &[Ty<'_>], output_lifetimes: &[LifetimeName]) .all(|in_lt| output_lifetimes.iter().any(|out_lt| in_lt == out_lt)) } -fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> { - if let Some(block_expr) = block.expr - && let Expr { - kind: ExprKind::Closure(&Closure { body, .. }), - .. - } = block_expr - && let closure_body = cx.tcx.hir().body(body) - && closure_body.coroutine_kind == Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block)) +fn desugared_async_block<'tcx>( + cx: &LateContext<'tcx>, + block: &'tcx Block<'tcx>, +) -> Option<&'tcx Body<'tcx>> { + if let Some(Expr { + kind: + ExprKind::Closure(&Closure { + kind: + ClosureKind::Coroutine(CoroutineKind::Desugared( + CoroutineDesugaring::Async, + CoroutineSource::Block, + )), + body, + .. + }), + .. + }) = block.expr { - return Some(closure_body); + return Some(cx.tcx.hir().body(body)); } None diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index e1b934d36ea8b..6394f35f8604f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -32,7 +32,6 @@ pub(super) fn check<'tcx>( && let Body { params: [p], value: body_expr, - coroutine_kind: _, } = cx.tcx.hir().body(c.body) && let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind && let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) { diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 350707d3a1361..d7adf22ff32a3 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -3,7 +3,7 @@ use clippy_utils::path_res; use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, LangItem, MatchSource, QPath}; +use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -86,22 +86,20 @@ impl LateLintPass<'_> for NeedlessQuestionMark { } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - if let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Fn)) = body.coroutine_kind { - if let ExprKind::Block( - Block { - expr: - Some(Expr { - kind: ExprKind::DropTemps(async_body), - .. - }), - .. - }, - _, - ) = body.value.kind - { - if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind { - check(cx, expr); - } + if let ExprKind::Block( + Block { + expr: + Some(Expr { + kind: ExprKind::DropTemps(async_body), + .. + }), + .. + }, + _, + ) = body.value.kind + { + if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind { + check(cx, expr.peel_blocks()); } } else { check(cx, body.value.peel_blocks()); diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs index 4b3fe9c0bb556..b50141f048c5b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs @@ -5,7 +5,7 @@ use clippy_utils::peel_blocks; use clippy_utils::source::{snippet, walk_span_to_context}; use clippy_utils::visitors::for_each_expr; use rustc_errors::Applicability; -use rustc_hir::{Closure, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource}; +use rustc_hir::{Closure, ClosureKind, CoroutineKind, CoroutineSource, CoroutineDesugaring, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::UpvarCapture; @@ -69,9 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock { /// If `expr` is a desugared `async` block, return the original expression if it does not capture /// any variable by ref. fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { - if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind + if let ExprKind::Closure(Closure { body, def_id, kind, .. }) = expr.kind && let body = cx.tcx.hir().body(*body) - && matches!(body.coroutine_kind, Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))) + && matches!(kind, ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Block))) { cx.typeck_results() .closure_min_captures diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 9312a9c89b789..16c929edb928f 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -5,7 +5,7 @@ use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; -use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node}; +use rustc_hir::{intravisit as hir_visit, CoroutineKind, CoroutineSource, CoroutineDesugaring, Node, ClosureKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -63,11 +63,10 @@ impl<'tcx> Visitor<'tcx> for ReturnVisitor { /// Checks if the body is owned by an async closure. /// Returns true for `async || whatever_expression`, but false for `|| async { whatever_expression /// }`. -fn is_async_closure(cx: &LateContext<'_>, body: &hir::Body<'_>) -> bool { +fn is_async_closure(body: &hir::Body<'_>) -> bool { if let hir::ExprKind::Closure(innermost_closure_generated_by_desugar) = body.value.kind - && let desugared_inner_closure_body = cx.tcx.hir().body(innermost_closure_generated_by_desugar.body) // checks whether it is `async || whatever_expression` - && let Some(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = desugared_inner_closure_body.coroutine_kind + && let ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)) = innermost_closure_generated_by_desugar.kind { true } else { @@ -103,7 +102,7 @@ fn find_innermost_closure<'tcx>( data = Some(( body.value, closure.fn_decl, - if is_async_closure(cx, body) { + if is_async_closure(body) { ty::Asyncness::Yes } else { ty::Asyncness::No diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index f71fe4e1e92e1..1d42375ba8e55 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::is_def_id_trait_method; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor}; +use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnDecl, Node, YieldSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; @@ -78,32 +78,32 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { self.await_in_async_block = Some(ex.span); } } - walk_expr(self, ex); - } - - fn nested_visit_map(&mut self) -> Self::Map { - self.cx.tcx.hir() - } - fn visit_body(&mut self, b: &'tcx Body<'tcx>) { let is_async_block = matches!( - b.coroutine_kind, - Some(rustc_hir::CoroutineKind::Desugared( - rustc_hir::CoroutineDesugaring::Async, - _ - )) + ex.kind, + ExprKind::Closure(rustc_hir::Closure { + kind: rustc_hir::ClosureKind::Coroutine(rustc_hir::CoroutineKind::Desugared( + rustc_hir::CoroutineDesugaring::Async, + _ + )), + .. + }) ); if is_async_block { self.async_depth += 1; } - walk_body(self, b); + walk_expr(self, ex); if is_async_block { self.async_depth -= 1; } } + + fn nested_visit_map(&mut self) -> Self::Map { + self.cx.tcx.hir() + } } impl<'tcx> LateLintPass<'tcx> for UnusedAsync { diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e83c04eda2077..df715b12dea7e 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -7,7 +7,8 @@ use rustc_ast::LitIntType; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::{ - ArrayLen, BindingAnnotation, CaptureBy, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, + ArrayLen, BindingAnnotation, CaptureBy, Closure, ClosureKind, CoroutineKind, ExprKind, FnRetTy, HirId, Lit, + PatKind, QPath, StmtKind, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -476,7 +477,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { capture_clause, fn_decl, body: body_id, - movability, + kind, .. }) => { let capture_clause = match capture_clause { @@ -484,7 +485,17 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { CaptureBy::Ref => "Ref", }; - let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}"))); + let closure_kind = match kind { + ClosureKind::Closure => "ClosureKind::Closure".to_string(), + ClosureKind::Coroutine(coroutine_kind) => match coroutine_kind { + CoroutineKind::Desugared(desugaring, source) => format!( + "ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::{desugaring:?}, CoroutineSource::{source:?}))" + ), + CoroutineKind::Coroutine(movability) => { + format!("ClosureKind::Coroutine(CoroutineKind::Coroutine(Movability::{movability:?})") + }, + }, + }; let ret_ty = match fn_decl.output { FnRetTy::DefaultReturn(_) => "FnRetTy::DefaultReturn(_)", @@ -492,7 +503,9 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }; bind!(self, fn_decl, body_id); - kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})"); + kind!( + "Closure {{ capture_clause: CaptureBy::{capture_clause}, fn_decl: {fn_decl}, body: {body_id}, closure_kind: {closure_kind}, .. }}" + ); chain!(self, "let {ret_ty} = {fn_decl}.output"); self.body(body_id); }, diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 140300a167308..62de661f8ff86 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind { // report your lint here } -if let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl, body_id, _, None) = expr.kind +if let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = expr.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr1 = &cx.tcx.hir().body(body_id).value - && let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind + && let ExprKind::Closure { capture_clause: CaptureBy::Value { .. }, fn_decl: fn_decl1, body: body_id1, closure_kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, CoroutineSource::Closure)), .. } = expr1.kind && let FnRetTy::DefaultReturn(_) = fn_decl1.output && expr2 = &cx.tcx.hir().body(body_id1).value && let ExprKind::Block(block, None) = expr2.kind diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout index 9ab71986f40f4..06386d1d7ec40 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout +++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout @@ -1,6 +1,6 @@ if let StmtKind::Local(local) = stmt.kind && let Some(init) = local.init - && let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind + && let ExprKind::Closure { capture_clause: CaptureBy::Ref, fn_decl: fn_decl, body: body_id, closure_kind: ClosureKind::Closure, .. } = init.kind && let FnRetTy::DefaultReturn(_) = fn_decl.output && expr = &cx.tcx.hir().body(body_id).value && let ExprKind::Block(block, None) = expr.kind diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index 07bd6b6f3c1e2..92f01c217c1cb 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> { async fn async_result_bad(s: TR) -> Result { s.magic } + +async fn async_wrapped(a: Option) -> Option { + { a } +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index fbf8a12fd5044..21c858c291ffa 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -135,3 +135,7 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> { async fn async_result_bad(s: TR) -> Result { Ok(s.magic?) } + +async fn async_wrapped(a: Option) -> Option { + { Some(a?) } +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index cd961a49f421a..bf090302ef7eb 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -90,5 +90,11 @@ error: question mark operator is useless here LL | Ok(s.magic?) | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` -error: aborting due to 14 previous errors +error: question mark operator is useless here + --> $DIR/needless_question_mark.rs:140:7 + | +LL | { Some(a?) } + | ^^^^^^^^ help: try removing question mark and `Some()`: `a` + +error: aborting due to 15 previous errors diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 070dbbb10bb65..5296475c94a78 100644 --- a/tests/ui/stats/hir-stats.stderr +++ b/tests/ui/stats/hir-stats.stderr @@ -125,9 +125,9 @@ hir-stats ExprField 40 ( 0.4%) 1 40 hir-stats TraitItemRef 56 ( 0.6%) 2 28 hir-stats Local 64 ( 0.7%) 1 64 hir-stats Param 64 ( 0.7%) 2 32 +hir-stats Body 72 ( 0.8%) 3 24 hir-stats InlineAsm 72 ( 0.8%) 1 72 hir-stats ImplItemRef 72 ( 0.8%) 2 36 -hir-stats Body 96 ( 1.1%) 3 32 hir-stats FieldDef 96 ( 1.1%) 2 48 hir-stats Arm 96 ( 1.1%) 2 48 hir-stats Stmt 96 ( 1.1%) 3 32 @@ -146,7 +146,7 @@ hir-stats - Trait 192 ( 2.1%) 4 hir-stats WherePredicate 192 ( 2.1%) 3 64 hir-stats - BoundPredicate 192 ( 2.1%) 3 hir-stats Block 288 ( 3.2%) 6 48 -hir-stats Pat 360 ( 3.9%) 5 72 +hir-stats Pat 360 ( 4.0%) 5 72 hir-stats - Wild 72 ( 0.8%) 1 hir-stats - Struct 72 ( 0.8%) 1 hir-stats - Binding 216 ( 2.4%) 3 @@ -172,7 +172,7 @@ hir-stats - Impl 88 ( 1.0%) 1 hir-stats - Fn 176 ( 1.9%) 2 hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.6%) 31 40 -hir-stats PathSegment 1_920 (21.0%) 40 48 +hir-stats PathSegment 1_920 (21.1%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 9_136 +hir-stats Total 9_112 hir-stats