Make closures carry their own ClosureKind, rather than deducing what it is from movability
This commit is contained in:
parent
981fc6e174
commit
909dd864f1
20 changed files with 338 additions and 326 deletions
|
@ -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() {
|
||||
|
|
|
@ -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];
|
||||
// `<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!(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];
|
||||
// `<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!(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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue