From 909dd864f140b5aeefd116d60ec6bffa4271617a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 22 Dec 2023 21:29:12 +0000 Subject: [PATCH] Make closures carry their own ClosureKind, rather than deducing what it is from movability --- compiler/rustc_ast_lowering/src/expr.rs | 45 +++++---- compiler/rustc_ast_lowering/src/item.rs | 6 +- .../src/diagnostics/conflict_errors.rs | 48 +++++---- .../rustc_borrowck/src/diagnostics/mod.rs | 60 ++++++----- .../src/diagnostics/mutability_errors.rs | 3 +- .../src/diagnostics/region_errors.rs | 10 +- .../src/diagnostics/region_name.rs | 84 ++++++++-------- compiler/rustc_hir/src/hir.rs | 23 +++-- compiler/rustc_hir/src/intravisit.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 10 +- .../src/collect/generics_of.rs | 12 +-- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/callee.rs | 17 ++-- compiler/rustc_hir_typeck/src/check.rs | 17 +--- compiler/rustc_hir_typeck/src/closure.rs | 56 ++++++----- compiler/rustc_passes/src/loops.rs | 22 +++-- .../error_reporting/on_unimplemented.rs | 55 +++-------- .../src/traits/error_reporting/suggestions.rs | 99 +++++++++---------- .../error_reporting/type_err_ctxt_ext.rs | 85 ++++++++-------- tests/ui/stats/hir-stats.stderr | 8 +- 20 files changed, 338 insertions(+), 326 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 1f6d47ab453..04483b8e150 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -669,11 +669,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); @@ -692,7 +691,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, Movability::Static), constness: hir::Constness::NotConst, })) } @@ -726,11 +725,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) @@ -746,7 +744,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, Movability::Movable), constness: hir::Constness::NotConst, })) } @@ -807,11 +805,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); @@ -830,7 +829,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, Movability::Static), constness: hir::Constness::NotConst, })) } @@ -1087,7 +1086,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); @@ -1095,7 +1094,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) }); @@ -1112,26 +1111,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) => { if decl.inputs.len() > 1 { self.tcx.sess.emit_err(CoroutineTooManyParameters { fn_decl_span }); } - Some(movability) + hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine, movability) } Some( hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) @@ -1144,7 +1143,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if movability == Movability::Static { self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span }); } - None + hir::ClosureKind::Closure } } } @@ -1236,7 +1235,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) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9c990cb4619..c5f29e52c35 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 1577b2896c3..50da24a9f99 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) @@ -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 ee321365470..0eb5e517164 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 506933c470e..3b3d440df97 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 f0b773b17ba..c6ab52c67df 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -1042,13 +1042,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 78d84f468e0..f41def844e2 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,47 +683,49 @@ 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, 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" } - } - 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, 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" } - } + }, - Some(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::AsyncGen, - src, - )) => match src { + 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 => { @@ -737,8 +739,10 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { " of async gen function" } }, - Some(hir::CoroutineKind::Coroutine) => " of coroutine", - None => " of closure", + hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine, _) => { + " of coroutine" + } + hir::ClosureKind::Closure => " of closure", }; (span, mir_description, hir_ty) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 452f5d0b7ac..7b95fb33785 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -945,7 +945,21 @@ 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). + // FIXME(coroutines): We could probably remove movability here -- it can be deduced + // from the `CoroutineKind` in all cases (except for "plain" coroutines, which could + // carry the movability in the variant). + Coroutine(CoroutineKind, Movability), } /// A block of statements `{ .. }`, which may have a label (in this case the @@ -1335,17 +1349,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. @@ -3661,7 +3670,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 67e058a3219..e58e4c8fe0e 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/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index d43b4adfe39..9fbe7b99a80 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 3ee2822edd8..5a15a375baf 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 feaec5ac620..d6eea07cfbc 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 2146effd84f..a13e765df80 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -298,17 +298,22 @@ 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( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Closure, - )) { + let fn_decl_span = if matches!( + kind, + hir::ClosureKind::Coroutine( + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + 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 8e2af402918..898ecf6ba87 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,9 +55,7 @@ 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 => { @@ -151,8 +149,8 @@ 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, movability)) = + closure_kind { let interior = fcx .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); @@ -164,12 +162,7 @@ pub(super) fn check_fn<'a, 'tcx>( )); let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); - Some(CoroutineTypes { - resume_ty, - yield_ty, - interior, - movability: can_be_coroutine.unwrap(), - }) + Some(CoroutineTypes { resume_ty, yield_ty, interior, movability: movability }) } else { None }; diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 5d517cd55f3..fe07a868839 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -79,7 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!(?expr_def_id); let ClosureSignatures { bound_sig, liberated_sig } = - self.sig_of_closure(expr_def_id, closure.fn_decl, body.coroutine_kind, expected_sig); + self.sig_of_closure(expr_def_id, closure.fn_decl, closure.kind, expected_sig); debug!(?bound_sig, ?liberated_sig); @@ -90,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, ); @@ -352,13 +352,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - coroutine_kind: Option, + 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, coroutine_kind, 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, coroutine_kind) + self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind) } } @@ -369,9 +369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - coroutine_kind: Option, + closure_kind: hir::ClosureKind, ) -> ClosureSignatures<'tcx> { - let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, coroutine_kind); + let bound_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind); self.closure_sigs(expr_def_id, bound_sig) } @@ -428,14 +428,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - coroutine_kind: Option, + 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, coroutine_kind); + 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, @@ -473,11 +473,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match self.merge_supplied_sig_with_expectation( expr_def_id, decl, - coroutine_kind, + 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, coroutine_kind), + Err(_) => self.sig_of_closure_no_expectation(expr_def_id, decl, closure_kind), } } @@ -526,14 +526,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - coroutine_kind: Option, + 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, coroutine_kind); + let supplied_sig = self.supplied_sig_of_closure(expr_def_id, decl, closure_kind); debug!(?supplied_sig); @@ -620,12 +620,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, expr_def_id: LocalDefId, decl: &hir::FnDecl<'_>, - coroutine_kind: Option, + closure_kind: hir::ClosureKind, ) -> ty::PolyFnSig<'tcx> { let astconv: &dyn AstConv<'_> = self; trace!("decl = {:#?}", decl); - debug!(?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); @@ -634,14 +634,17 @@ 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 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::CoroutineDesugaring::Async, - hir::CoroutineSource::Fn, - )) => { + hir::ClosureKind::Coroutine( + hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Fn, + ), + _, + ) => { debug!("closure is async fn body"); self.deduce_future_output_from_obligations(expr_def_id).unwrap_or_else(|| { // AFAIK, deducing the future output @@ -655,12 +658,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } // 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()), }, }; diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index bfaf4a5a957..b8b7e0d4580 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,18 @@ 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_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 61e97dde5f8..c89b32ecfde 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 e84c5b76421..97d67c2dad6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -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 + 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 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!(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('?') { - 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, + err.span_suggestion_verbose( + span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(), + "consider `await`ing on the `Future`", + ".await", + Applicability::MaybeIncorrect, ); - 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); - - 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, - ); - } } } } @@ -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 a495f8399b9..f668c069f5b 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/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr index 070dbbb10bb..5296475c94a 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