about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-26 04:25:53 +0000
committerbors <bors@rust-lang.org>2023-12-26 04:25:53 +0000
commit1ab783112ab4e4807304dbd249b39771246013ef (patch)
tree827d6051e0e3ffcaadd0d6c7369b71547319a525 /compiler/rustc_trait_selection/src
parent2271c26e4a8e062bb00d709d0ccb5846e0c341b9 (diff)
parentba912855cc1aff5f2b403411c8d890d3978abf9a (diff)
downloadrust-1ab783112ab4e4807304dbd249b39771246013ef.tar.gz
rust-1ab783112ab4e4807304dbd249b39771246013ef.zip
Auto merge of #119258 - compiler-errors:closure-kind, r=eholk
Make closures carry their own ClosureKind

Right now, we use the "`movability`" field of `hir::Closure` to distinguish a closure and a coroutine. This is paired together with the `CoroutineKind`, which is located not in the `hir::Closure`, but the `hir::Body`. This is strange and redundant.

This PR introduces `ClosureKind` with two variants -- `Closure` and `Coroutine`, which is put into `hir::Closure`. The `CoroutineKind` is thus removed from `hir::Body`, and `Option<Movability>` no longer needs to be a stand-in for "is this a closure or a coroutine".

r? eholk
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs55
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs99
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs85
3 files changed, 102 insertions, 137 deletions
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 13ac2e26e40..52f91d282f0 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 e1f3c6d4f97..171b86d4f25 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];
-                // `<T as Future>::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];
+            // `<T as Future>::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 4b84aae70fd..d2598b0defe 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<CandidateSimilarity>;
 
-    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(