Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/display.rs')
-rw-r--r--crates/hir-ty/src/display.rs92
1 files changed, 85 insertions, 7 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index c749a3d24a..dd1b212d4c 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -38,7 +38,8 @@ use rustc_apfloat::{
use rustc_ast_ir::FloatTy;
use rustc_hash::FxHashSet;
use rustc_type_ir::{
- AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, RegionKind, Upcast,
+ AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, CoroutineClosureArgsParts, RegionKind,
+ Upcast,
inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _, Tys as _},
};
use smallvec::SmallVec;
@@ -1444,14 +1445,83 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
}
if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
write!(f, " -> ")?;
- // FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because
- // we don't have a trait environment here, required to normalize `<Ret as Future>::Output`.
sig.output().hir_fmt(f)?;
}
} else {
write!(f, "{{closure}}")?;
}
}
+ TyKind::CoroutineClosure(id, args) => {
+ let id = id.0;
+ if f.display_kind.is_source_code() {
+ if !f.display_kind.allows_opaque() {
+ return Err(HirDisplayError::DisplaySourceCodeError(
+ DisplaySourceCodeError::OpaqueType,
+ ));
+ } else if f.closure_style != ClosureStyle::ImplFn {
+ never!("Only `impl Fn` is valid for displaying closures in source code");
+ }
+ }
+ match f.closure_style {
+ ClosureStyle::Hide => return write!(f, "{TYPE_HINT_TRUNCATION}"),
+ ClosureStyle::ClosureWithId => {
+ return write!(
+ f,
+ "{{async closure#{:?}}}",
+ salsa::plumbing::AsId::as_id(&id).index()
+ );
+ }
+ ClosureStyle::ClosureWithSubst => {
+ write!(
+ f,
+ "{{async closure#{:?}}}",
+ salsa::plumbing::AsId::as_id(&id).index()
+ )?;
+ return hir_fmt_generics(f, args.as_slice(), None, None);
+ }
+ _ => (),
+ }
+ let CoroutineClosureArgsParts { closure_kind_ty, signature_parts_ty, .. } =
+ args.split_coroutine_closure_args();
+ let kind = closure_kind_ty.to_opt_closure_kind().unwrap();
+ let kind = match kind {
+ rustc_type_ir::ClosureKind::Fn => "AsyncFn",
+ rustc_type_ir::ClosureKind::FnMut => "AsyncFnMut",
+ rustc_type_ir::ClosureKind::FnOnce => "AsyncFnOnce",
+ };
+ let TyKind::FnPtr(coroutine_sig, _) = signature_parts_ty.kind() else {
+ unreachable!("invalid coroutine closure signature");
+ };
+ let coroutine_sig = coroutine_sig.skip_binder();
+ let coroutine_inputs = coroutine_sig.inputs();
+ let TyKind::Tuple(coroutine_inputs) = coroutine_inputs.as_slice()[1].kind() else {
+ unreachable!("invalid coroutine closure signature");
+ };
+ let TyKind::Tuple(coroutine_output) = coroutine_sig.output().kind() else {
+ unreachable!("invalid coroutine closure signature");
+ };
+ let coroutine_output = coroutine_output.as_slice()[1];
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, "impl {kind}(")?,
+ ClosureStyle::RANotation => write!(f, "async |")?,
+ _ => unreachable!(),
+ }
+ if coroutine_inputs.is_empty() {
+ } else if f.should_truncate() {
+ write!(f, "{TYPE_HINT_TRUNCATION}")?;
+ } else {
+ f.write_joined(coroutine_inputs, ", ")?;
+ };
+ match f.closure_style {
+ ClosureStyle::ImplFn => write!(f, ")")?,
+ ClosureStyle::RANotation => write!(f, "|")?,
+ _ => unreachable!(),
+ }
+ if f.closure_style == ClosureStyle::RANotation || !coroutine_output.is_unit() {
+ write!(f, " -> ")?;
+ coroutine_output.hir_fmt(f)?;
+ }
+ }
TyKind::Placeholder(_) => write!(f, "{{placeholder}}")?,
TyKind::Param(param) => {
// FIXME: We should not access `param.id`, it should be removed, and we should know the
@@ -1545,8 +1615,13 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
subst.split_coroutine_args();
let body = db.body(owner);
- match &body[expr_id] {
- hir_def::hir::Expr::Async { .. } => {
+ let expr = &body[expr_id];
+ match expr {
+ hir_def::hir::Expr::Closure {
+ closure_kind: hir_def::hir::ClosureKind::Async,
+ ..
+ }
+ | hir_def::hir::Expr::Async { .. } => {
let future_trait =
LangItem::Future.resolve_trait(db, owner.module(db).krate());
let output = future_trait.and_then(|t| {
@@ -1573,7 +1648,10 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
return_ty.hir_fmt(f)?;
write!(f, ">")?;
}
- _ => {
+ hir_def::hir::Expr::Closure {
+ closure_kind: hir_def::hir::ClosureKind::Coroutine(..),
+ ..
+ } => {
if f.display_kind.is_source_code() {
return Err(HirDisplayError::DisplaySourceCodeError(
DisplaySourceCodeError::Coroutine,
@@ -1589,12 +1667,12 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
write!(f, " -> ")?;
return_ty.hir_fmt(f)?;
}
+ _ => panic!("invalid expr for coroutine: {expr:?}"),
}
}
TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?,
TyKind::Pat(_, _) => write!(f, "{{pat}}")?,
TyKind::UnsafeBinder(_) => write!(f, "{{unsafe binder}}")?,
- TyKind::CoroutineClosure(_, _) => write!(f, "{{coroutine closure}}")?,
TyKind::Alias(_, _) => write!(f, "{{alias}}")?,
}
Ok(())