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.rs | 92 |
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(()) |