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 | 453 |
1 files changed, 290 insertions, 163 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index e4a8def442..bc726b652f 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -10,17 +10,20 @@ use std::{ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, - Lookup, ModuleDefId, ModuleId, TraitId, + ExpressionStoreOwnerId, FindPathConfig, GenericDefId, GenericParamId, HasModule, + ItemContainerId, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, TypeAliasId, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, - hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, + hir::{ + ClosureKind as HirClosureKind, CoroutineKind, + generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate}, + }, item_scope::ItemInNs, item_tree::FieldsShape, lang_item::LangItems, signatures::{ - EnumSignature, FunctionSignature, StructSignature, TraitSignature, TypeAliasSignature, - UnionSignature, VariantFields, + ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature, + TraitSignature, TypeAliasSignature, UnionSignature, VariantFields, }, type_ref::{ ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, @@ -32,6 +35,7 @@ use hir_expand::{mod_path::PathKind, name::Name}; use intern::{Internable, Interned, sym}; use itertools::Itertools; use la_arena::ArenaMap; +use rustc_abi::ExternAbi; use rustc_apfloat::{ Float, ieee::{Half as f16, Quad as f128}, @@ -40,24 +44,24 @@ use rustc_ast_ir::FloatTy; use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, BoundVarIndexKind, CoroutineArgsParts, RegionKind, Upcast, - inherent::{AdtDef, GenericArgs as _, IntoKind, Term as _, Ty as _, Tys as _}, + inherent::{GenericArgs as _, IntoKind, Term as _, Ty as _, Tys as _}, }; use smallvec::SmallVec; use span::Edition; use stdx::never; use crate::{ - CallableDefId, FnAbi, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval, - db::{HirDatabase, InternedClosure}, - generics::generics, + CallableDefId, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval, + db::{GeneralConstId, HirDatabase}, + generics::{ProvenanceSplit, generics}, layout::Layout, lower::GenericPredicates, mir::pad16, next_solver::{ AliasTy, Allocation, Clause, ClauseKind, Const, ConstKind, DbInterner, ExistentialPredicate, FnSig, GenericArg, GenericArgKind, GenericArgs, ParamEnv, PolyFnSig, - Region, SolverDefId, StoredEarlyBinder, StoredTy, Term, TermKind, TraitRef, Ty, TyKind, - TypingMode, ValTree, + Region, StoredEarlyBinder, StoredTy, Term, TermId, TermKind, TraitPredicate, TraitRef, Ty, + TyKind, TypingMode, Unnormalized, ValTree, abi::Safety, infer::{DbInternerInferExt, traits::ObligationCause}, }, @@ -65,6 +69,36 @@ use crate::{ utils::{detect_variant_from_bytes, fn_traits}, }; +fn async_gen_item_ty_from_yield_ty<'db>( + lang_items: &LangItems, + yield_ty: Ty<'db>, +) -> Option<Ty<'db>> { + let poll_id = lang_items.Poll.map(hir_def::AdtId::EnumId)?; + let option_id = lang_items.Option.map(hir_def::AdtId::EnumId)?; + + let TyKind::Adt(poll_def, poll_args) = yield_ty.kind() else { + return None; + }; + if poll_def.def_id() != poll_id { + return None; + } + let [poll_inner] = poll_args.as_slice() else { + return None; + }; + let poll_inner = poll_inner.ty()?; + + let TyKind::Adt(option_def, option_args) = poll_inner.kind() else { + return None; + }; + if option_def.def_id() != option_id { + return None; + } + let [item] = option_args.as_slice() else { + return None; + }; + item.ty() +} + pub type Result<T = (), E = HirDisplayError> = std::result::Result<T, E>; pub trait HirWrite: fmt::Write { @@ -101,7 +135,15 @@ pub struct HirFormatter<'a, 'db> { display_lifetimes: DisplayLifetime, display_kind: DisplayKind, display_target: DisplayTarget, - bounds_formatting_ctx: BoundsFormattingCtx<'db>, + /// We can have recursive bounds like the following case: + /// ```ignore + /// where + /// T: Foo, + /// T::FooAssoc: Baz<<T::FooAssoc as Bar>::BarAssoc> + Bar + /// ``` + /// So, record the projection types met while formatting bounds and + /// prevent recursing into their bounds to avoid infinite loops. + currently_formatting_bounds: FxHashSet<AliasTy<'db>>, /// Whether formatting `impl Trait1 + Trait2` or `dyn Trait1 + Trait2` needs parentheses around it, /// for example when formatting `&(impl Trait1 + Trait2)`. trait_bounds_need_parens: bool, @@ -121,34 +163,6 @@ pub enum DisplayLifetime { Never, } -#[derive(Default)] -enum BoundsFormattingCtx<'db> { - Entered { - /// We can have recursive bounds like the following case: - /// ```ignore - /// where - /// T: Foo, - /// T::FooAssoc: Baz<<T::FooAssoc as Bar>::BarAssoc> + Bar - /// ``` - /// So, record the projection types met while formatting bounds and - //. prevent recursing into their bounds to avoid infinite loops. - projection_tys_met: FxHashSet<AliasTy<'db>>, - }, - #[default] - Exited, -} - -impl<'db> BoundsFormattingCtx<'db> { - fn contains(&self, proj: &AliasTy<'db>) -> bool { - match self { - BoundsFormattingCtx::Entered { projection_tys_met } => { - projection_tys_met.contains(proj) - } - BoundsFormattingCtx::Exited => false, - } - } -} - impl<'db> HirFormatter<'_, 'db> { pub fn start_location_link(&mut self, location: ModuleDefId) { self.fmt.start_location_link(location); @@ -162,26 +176,42 @@ impl<'db> HirFormatter<'_, 'db> { self.fmt.end_location_link(); } - fn format_bounds_with<T, F: FnOnce(&mut Self) -> T>( + fn format_bounds_with<F: FnOnce(&mut Self) -> Result>( &mut self, target: AliasTy<'db>, format_bounds: F, - ) -> T { - match self.bounds_formatting_ctx { - BoundsFormattingCtx::Entered { ref mut projection_tys_met } => { - projection_tys_met.insert(target); - format_bounds(self) - } - BoundsFormattingCtx::Exited => { - let mut projection_tys_met = FxHashSet::default(); - projection_tys_met.insert(target); - self.bounds_formatting_ctx = BoundsFormattingCtx::Entered { projection_tys_met }; - let res = format_bounds(self); - // Since we want to prevent only the infinite recursions in bounds formatting - // and do not want to skip formatting of other separate bounds, clear context - // when exiting the formatting of outermost bounds - self.bounds_formatting_ctx = BoundsFormattingCtx::Exited; - res + ) -> Result { + if self.currently_formatting_bounds.insert(target) { + let result = format_bounds(self); + self.currently_formatting_bounds.remove(&target); + result + } else { + if self.display_kind.is_source_code() { + Err(HirDisplayError::DisplaySourceCodeError(DisplaySourceCodeError::Cycle)) + } else { + match target.kind { + AliasTyKind::Projection { def_id } => { + let def_id = def_id.0; + let ItemContainerId::TraitId(trait_) = def_id.loc(self.db).container else { + panic!("expected an assoc type"); + }; + let trait_name = &TraitSignature::of(self.db, trait_).name; + let assoc_type_name = &TypeAliasSignature::of(self.db, def_id).name; + write!( + self, + "<… as {}>::{}", + trait_name.display(self.db, self.edition()), + assoc_type_name.display(self.db, self.edition()), + )?; + if target.args.len() > 1 { + self.write_str("<…>")?; + } + Ok(()) + } + AliasTyKind::Inherent { .. } + | AliasTyKind::Opaque { .. } + | AliasTyKind::Free { .. } => self.write_str("…"), + } } } } @@ -335,7 +365,7 @@ pub trait HirDisplay<'db> { display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque }, show_container_bounds: false, display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, - bounds_formatting_ctx: Default::default(), + currently_formatting_bounds: Default::default(), trait_bounds_need_parens: false, }) { Ok(()) => {} @@ -511,6 +541,7 @@ pub enum DisplaySourceCodeError { PathNotFound, Coroutine, OpaqueType, + Cycle, } pub enum HirDisplayError { @@ -571,7 +602,7 @@ impl<'db, T: HirDisplay<'db>> HirDisplayWrapper<'_, 'db, T> { closure_style: self.closure_style, show_container_bounds: self.show_container_bounds, display_lifetimes: self.display_lifetimes, - bounds_formatting_ctx: Default::default(), + currently_formatting_bounds: Default::default(), trait_bounds_need_parens: false, }) } @@ -623,63 +654,58 @@ fn write_projection<'db>( f: &mut HirFormatter<'_, 'db>, alias: &AliasTy<'db>, needs_parens_if_multi: bool, + def_id: TypeAliasId, ) -> Result { - if f.should_truncate() { - return write!(f, "{TYPE_HINT_TRUNCATION}"); - } - let trait_ref = alias.trait_ref(f.interner); - let self_ty = trait_ref.self_ty(); - - // if we are projection on a type parameter, check if the projection target has bounds - // itself, if so, we render them directly as `impl Bound` instead of the less useful - // `<Param as Trait>::Assoc` - if !f.display_kind.is_source_code() - && let TyKind::Param(param) = self_ty.kind() - && !f.bounds_formatting_ctx.contains(alias) - { - // FIXME: We shouldn't use `param.id`, it should be removed. We should know the - // `GenericDefId` from the formatted type (store it inside the `HirFormatter`). - let bounds = GenericPredicates::query_all(f.db, param.id.parent()) - .iter_identity() - .filter(|wc| { - let ty = match wc.kind().skip_binder() { - ClauseKind::Trait(tr) => tr.self_ty(), - ClauseKind::TypeOutlives(t) => t.0, - _ => return false, - }; - let TyKind::Alias(a) = ty.kind() else { - return false; - }; - a == *alias - }) - .collect::<Vec<_>>(); - if !bounds.is_empty() { - return f.format_bounds_with(*alias, |f| { - write_bounds_like_dyn_trait_with_prefix( + f.format_bounds_with(*alias, |f| { + if f.should_truncate() { + return write!(f, "{TYPE_HINT_TRUNCATION}"); + } + let trait_ref = alias.trait_ref(f.interner); + let self_ty = trait_ref.self_ty(); + + // if we are projection on a type parameter, check if the projection target has bounds + // itself, if so, we render them directly as `impl Bound` instead of the less useful + // `<Param as Trait>::Assoc` + if !f.display_kind.is_source_code() + && let TyKind::Param(param) = self_ty.kind() + { + // FIXME: We shouldn't use `param.id`, it should be removed. We should know the + // `GenericDefId` from the formatted type (store it inside the `HirFormatter`). + let bounds = GenericPredicates::query_all(f.db, param.id.parent()) + .iter_identity() + .map(Unnormalized::skip_norm_wip) + .filter(|wc| { + let ty = match wc.kind().skip_binder() { + ClauseKind::Trait(tr) => tr.self_ty(), + ClauseKind::TypeOutlives(t) => t.0, + _ => return false, + }; + let TyKind::Alias(a) = ty.kind() else { + return false; + }; + a == *alias + }) + .collect::<Vec<_>>(); + if !bounds.is_empty() { + return write_bounds_like_dyn_trait_with_prefix( f, "impl", Either::Left(Ty::new_alias(f.interner, *alias)), &bounds, SizedByDefault::NotSized, needs_parens_if_multi, - ) - }); + ); + } } - } - write!(f, "<")?; - self_ty.hir_fmt(f)?; - write!(f, " as ")?; - trait_ref.hir_fmt(f)?; - write!( - f, - ">::{}", - TypeAliasSignature::of(f.db, alias.kind.def_id().expect_type_alias()) - .name - .display(f.db, f.edition()) - )?; - let proj_params = &alias.args.as_slice()[trait_ref.args.len()..]; - hir_fmt_generics(f, proj_params, None, None) + write!(f, "<")?; + self_ty.hir_fmt(f)?; + write!(f, " as ")?; + trait_ref.hir_fmt(f)?; + write!(f, ">::{}", TypeAliasSignature::of(f.db, def_id).name.display(f.db, f.edition()))?; + let proj_params = &alias.args.as_slice()[trait_ref.args.len()..]; + hir_fmt_generics(f, proj_params, None, None) + }) } impl<'db> HirDisplay<'db> for GenericArg<'db> { @@ -710,7 +736,7 @@ impl<'db> HirDisplay<'db> for Const<'db> { } ConstKind::Infer(..) => write!(f, "#c#"), ConstKind::Param(param) => { - let generics = generics(f.db, param.id.parent()); + let generics = GenericParams::of(f.db, param.id.parent()); let param_data = &generics[param.id.local_id()]; f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; @@ -720,7 +746,25 @@ impl<'db> HirDisplay<'db> for Const<'db> { ConstKind::Value(value) => render_const_scalar_from_valtree(f, value.ty, value.value), ConstKind::Unevaluated(unev) => { let c = unev.def.0; - write!(f, "{}", c.name(f.db))?; + match c { + GeneralConstId::ConstId(id) => match &ConstSignature::of(f.db, id).name { + Some(name) => { + f.start_location_link(id.into()); + write!(f, "{}", name.display(f.db, f.edition()))?; + f.end_location_link(); + } + None => f.write_str("_")?, + }, + GeneralConstId::StaticId(id) => { + let name = &StaticSignature::of(f.db, id).name; + f.start_location_link(id.into()); + write!(f, "{}", name.display(f.db, f.edition()))?; + f.end_location_link(); + } + GeneralConstId::AnonConstId(_) => { + f.write_str(if f.display_kind.is_source_code() { "_" } else { "{const}" })? + } + }; hir_fmt_generics(f, unev.args.as_slice(), c.generic_def(f.db), None)?; Ok(()) } @@ -738,7 +782,7 @@ fn render_const_scalar<'db>( ) -> Result { let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty); + let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_inner(f, b, memory_map, ty, param_env) } @@ -857,7 +901,7 @@ fn render_const_scalar_inner<'db>( f.write_str("&")?; render_const_scalar(f, bytes, memory_map, t) } - TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id().0 { + TyKind::Adt(adt, _) if b.len() == 2 * size_of::<usize>() => match adt.def_id() { hir_def::AdtId::StructId(s) => { let data = StructSignature::of(f.db, s); write!(f, "&{}", data.name.display(f.db, f.edition()))?; @@ -911,7 +955,7 @@ fn render_const_scalar_inner<'db>( f.write_str(")") } TyKind::Adt(def, args) => { - let def = def.def_id().0; + let def = def.def_id(); let Ok(layout) = f.db.layout_of_adt(def, args.store(), param_env.store()) else { return f.write_str("<layout-error>"); }; @@ -941,7 +985,7 @@ fn render_const_scalar_inner<'db>( return f.write_str("<target-layout-not-available>"); }; let Some((var_id, var_layout)) = - detect_variant_from_bytes(&layout, f.db, &target_data_layout, b, e) + detect_variant_from_bytes(&layout, f.db, target_data_layout, b, e) else { return f.write_str("<failed-to-detect-variant>"); }; @@ -1023,7 +1067,7 @@ fn render_const_scalar_from_valtree<'db>( ) -> Result { let param_env = ParamEnv::empty(); let infcx = f.interner.infer_ctxt().build(TypingMode::PostAnalysis); - let ty = infcx.at(&ObligationCause::new(), param_env).deeply_normalize(ty).unwrap_or(ty); + let ty = infcx.at(&ObligationCause::dummy(), param_env).deeply_normalize(ty).unwrap_or(ty); render_const_scalar_from_valtree_inner(f, ty, valtree, param_env) } @@ -1176,7 +1220,7 @@ fn render_variant_after_name<'db>( FieldsShape::Record | FieldsShape::Tuple => { let render_field = |f: &mut HirFormatter<'_, 'db>, id: LocalFieldId| { let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize(); - let ty = field_types[id].get().instantiate(f.interner, args); + let ty = field_types[id].get().instantiate(f.interner, args).skip_norm_wip(); let Ok(layout) = f.db.layout_of_ty(ty.store(), param_env.store()) else { return f.write_str("<layout-error>"); }; @@ -1287,7 +1331,8 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } TyKind::FnDef(def, args) => { let def = def.0; - let sig = db.callable_item_signature(def).instantiate(interner, args); + let sig = + db.callable_item_signature(def).instantiate(interner, args).skip_norm_wip(); if f.display_kind.is_source_code() { // `FnDef` is anonymous and there's no surface syntax for it. Show it as a @@ -1297,7 +1342,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { if let Safety::Unsafe = sig.safety() { write!(f, "unsafe ")?; } - if !matches!(sig.abi(), FnAbi::Rust | FnAbi::RustCall) { + if !sig.abi().is_rustic_abi() { f.write_str("extern \"")?; f.write_str(sig.abi().as_str())?; f.write_str("\" ")?; @@ -1331,8 +1376,14 @@ impl<'db> HirDisplay<'db> for Ty<'db> { if !args.is_empty() { let generic_def_id = GenericDefId::from_callable(db, def); let generics = generics(db, generic_def_id); - let (parent_len, self_param, type_, const_, impl_, lifetime) = - generics.provenance_split(); + let ProvenanceSplit { + parent_total: parent_len, + has_self_param: self_param, + non_impl_trait_type_params: type_, + const_params: const_, + impl_trait_type_params: impl_, + lifetimes: lifetime, + } = generics.provenance_split(); let parameters = args.as_slice(); debug_assert_eq!( parameters.len(), @@ -1387,7 +1438,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } } TyKind::Adt(def, parameters) => { - let def_id = def.def_id().0; + let def_id = def.def_id(); f.start_location_link(def_id.into()); match f.display_kind { DisplayKind::Diagnostics | DisplayKind::Test => { @@ -1425,10 +1476,10 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } f.end_location_link(); - hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().0.into()), None)?; + hir_fmt_generics(f, parameters.as_slice(), Some(def.def_id().into()), None)?; } - TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Projection { .. }, .. }) => { - write_projection(f, &alias_ty, trait_bounds_need_parens)? + TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Projection { def_id }, .. }) => { + write_projection(f, &alias_ty, trait_bounds_need_parens, def_id.0)? } TyKind::Foreign(alias) => { let type_alias = TypeAliasSignature::of(db, alias.0); @@ -1437,19 +1488,17 @@ impl<'db> HirDisplay<'db> for Ty<'db> { f.end_location_link(); } TyKind::Alias(alias_ty @ AliasTy { kind: AliasTyKind::Opaque { def_id }, .. }) => { - let opaque_ty_id = match def_id { - SolverDefId::InternedOpaqueTyId(id) => id, - _ => unreachable!(), - }; + let opaque_ty_id = def_id.0; if !f.display_kind.allows_opaque() { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::OpaqueType, )); } - let impl_trait_id = db.lookup_intern_impl_trait_id(opaque_ty_id); + let impl_trait_id = opaque_ty_id.loc(db); let data = impl_trait_id.predicates(db); let bounds = data .iter_instantiated_copied(interner, alias_ty.args.as_slice()) + .map(Unnormalized::skip_norm_wip) .collect::<Vec<_>>(); let krate = match impl_trait_id { ImplTraitId::ReturnTypeImplTrait(func, _) => { @@ -1519,6 +1568,15 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } TyKind::CoroutineClosure(id, args) => { let id = id.0; + let closure_kind = match id.loc(db).kind { + HirClosureKind::CoroutineClosure(kind) => kind, + kind => panic!("invalid kind for coroutine closure: {kind:?}"), + }; + let closure_label = match closure_kind { + CoroutineKind::Async => "async closure", + CoroutineKind::Gen => "gen closure", + CoroutineKind::AsyncGen => "async gen closure", + }; if f.display_kind.is_source_code() { if !f.display_kind.allows_opaque() { return Err(HirDisplayError::DisplaySourceCodeError( @@ -1533,25 +1591,28 @@ impl<'db> HirDisplay<'db> for Ty<'db> { ClosureStyle::ClosureWithId => { return write!( f, - "{{async closure#{:?}}}", + "{{{closure_label}#{:?}}}", salsa::plumbing::AsId::as_id(&id).index() ); } ClosureStyle::ClosureWithSubst => { write!( f, - "{{async closure#{:?}}}", + "{{{closure_label}#{:?}}}", salsa::plumbing::AsId::as_id(&id).index() )?; return hir_fmt_generics(f, args.as_slice(), None, None); } _ => (), } - let kind = args.as_coroutine_closure().kind(); - let kind = match kind { - rustc_type_ir::ClosureKind::Fn => "AsyncFn", - rustc_type_ir::ClosureKind::FnMut => "AsyncFnMut", - rustc_type_ir::ClosureKind::FnOnce => "AsyncFnOnce", + let callable_kind = args.as_coroutine_closure().kind(); + let kind = match (closure_kind, callable_kind) { + (CoroutineKind::Async, rustc_type_ir::ClosureKind::Fn) => "AsyncFn", + (CoroutineKind::Async, rustc_type_ir::ClosureKind::FnMut) => "AsyncFnMut", + (CoroutineKind::Async, rustc_type_ir::ClosureKind::FnOnce) => "AsyncFnOnce", + (_, rustc_type_ir::ClosureKind::Fn) => "Fn", + (_, rustc_type_ir::ClosureKind::FnMut) => "FnMut", + (_, rustc_type_ir::ClosureKind::FnOnce) => "FnOnce", }; let coroutine_sig = args.as_coroutine_closure().coroutine_closure_sig(); let coroutine_sig = coroutine_sig.skip_binder(); @@ -1559,7 +1620,11 @@ impl<'db> HirDisplay<'db> for Ty<'db> { let coroutine_output = coroutine_sig.return_ty; match f.closure_style { ClosureStyle::ImplFn => write!(f, "impl {kind}(")?, - ClosureStyle::RANotation => write!(f, "async |")?, + ClosureStyle::RANotation => match closure_kind { + CoroutineKind::Async => write!(f, "async |")?, + CoroutineKind::Gen => write!(f, "gen |")?, + CoroutineKind::AsyncGen => write!(f, "async gen |")?, + }, _ => unreachable!(), } if coroutine_inputs.is_empty() { @@ -1582,7 +1647,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { TyKind::Param(param) => { // FIXME: We should not access `param.id`, it should be removed, and we should know the // parent from the formatted type. - let generics = generics(db, param.id.parent()); + let generics = GenericParams::of(db, param.id.parent()); let param_data = &generics[param.id.local_id()]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { @@ -1601,6 +1666,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { TypeParamProvenance::ArgumentImplTrait => { let bounds = GenericPredicates::query_all(f.db, param.id.parent()) .iter_identity() + .map(Unnormalized::skip_norm_wip) .filter(|wc| match wc.kind().skip_binder() { ClauseKind::Trait(tr) => tr.self_ty() == *self, ClauseKind::Projection(proj) => proj.self_ty() == *self, @@ -1670,21 +1736,14 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } TyKind::Infer(..) => write!(f, "_")?, TyKind::Coroutine(coroutine_id, subst) => { - let InternedClosure(owner, expr_id) = coroutine_id.0.loc(db); + let kind = coroutine_id.0.loc(db).kind; let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } = subst.split_coroutine_args(); - let body = ExpressionStore::of(db, owner); - let expr = &body[expr_id]; - match expr { - hir_def::hir::Expr::Closure { - closure_kind: hir_def::hir::ClosureKind::AsyncBlock { .. }, - .. - } => { - let future_trait = f.lang_items().Future; - let output = future_trait.and_then(|t| { - t.trait_items(db) - .associated_type_by_name(&Name::new_symbol_root(sym::Output)) - }); + match kind { + HirClosureKind::Coroutine { kind: CoroutineKind::Async, .. } => { + let lang_items = f.lang_items(); + let future_trait = lang_items.Future; + let output = lang_items.FutureOutput; write!(f, "impl ")?; if let Some(t) = future_trait { f.start_location_link(t.into()); @@ -1705,10 +1764,57 @@ 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(..), - .. - } => { + HirClosureKind::Coroutine { kind: CoroutineKind::Gen, .. } => { + let lang_items = f.lang_items(); + let iterator_trait = lang_items.Iterator; + let item = lang_items.IteratorItem; + write!(f, "impl ")?; + if let Some(t) = iterator_trait { + f.start_location_link(t.into()); + } + write!(f, "Iterator")?; + if iterator_trait.is_some() { + f.end_location_link(); + } + write!(f, "<")?; + if let Some(t) = item { + f.start_location_link(t.into()); + } + write!(f, "Item")?; + if item.is_some() { + f.end_location_link(); + } + write!(f, " = ")?; + yield_ty.hir_fmt(f)?; + write!(f, ">")?; + } + HirClosureKind::Coroutine { kind: CoroutineKind::AsyncGen, .. } => { + let lang_items = f.lang_items(); + let async_iterator_trait = lang_items.AsyncIterator; + let item = lang_items.AsyncIteratorItem; + write!(f, "impl ")?; + if let Some(t) = async_iterator_trait { + f.start_location_link(t.into()); + } + write!(f, "AsyncIterator")?; + if async_iterator_trait.is_some() { + f.end_location_link(); + } + write!(f, "<")?; + if let Some(t) = item { + f.start_location_link(t.into()); + } + write!(f, "Item")?; + if item.is_some() { + f.end_location_link(); + } + write!(f, " = ")?; + let item_ty = async_gen_item_ty_from_yield_ty(f.lang_items(), yield_ty) + .unwrap_or(yield_ty); + item_ty.hir_fmt(f)?; + write!(f, ">")?; + } + HirClosureKind::OldCoroutine(..) => { if f.display_kind.is_source_code() { return Err(HirDisplayError::DisplaySourceCodeError( DisplaySourceCodeError::Coroutine, @@ -1724,7 +1830,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { write!(f, " -> ")?; return_ty.hir_fmt(f)?; } - _ => panic!("invalid expr for coroutine: {expr:?}"), + _ => panic!("invalid kind for coroutine: {kind:?}"), } } TyKind::CoroutineWitness(..) => write!(f, "{{coroutine witness}}")?, @@ -1769,7 +1875,9 @@ fn generic_args_sans_defaults<'ga, 'db>( let should_show = |arg: GenericArg<'db>, i: usize| match default_parameters.get(i) { None => true, Some(default_parameter) => { - arg != default_parameter.instantiate(f.interner, ¶meters[..i]) + arg != default_parameter + .instantiate(f.interner, ¶meters[..i]) + .skip_norm_wip() } }; let mut default_from = 0; @@ -1852,8 +1960,8 @@ fn hir_fmt_tys<'db>( impl<'db> HirDisplay<'db> for PolyFnSig<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { - let FnSig { inputs_and_output, c_variadic, safety, abi: _ } = self.skip_binder(); - if let Safety::Unsafe = safety { + let FnSig { inputs_and_output, fn_sig_kind } = self.skip_binder(); + if let Safety::Unsafe = fn_sig_kind.safety() { write!(f, "unsafe ")?; } // FIXME: Enable this when the FIXME on FnAbi regarding PartialEq is fixed. @@ -1864,7 +1972,7 @@ impl<'db> HirDisplay<'db> for PolyFnSig<'db> { // } write!(f, "fn(")?; f.write_joined(inputs_and_output.inputs(), ", ")?; - if c_variadic { + if fn_sig_kind.c_variadic() { if inputs_and_output.inputs().is_empty() { write!(f, "...")?; } else { @@ -2067,6 +2175,9 @@ fn write_bounds_like_dyn_trait<'db>( } } ClauseKind::Projection(projection) => { + let TermId::TypeAliasId(assoc_ty_id) = projection.def_id().0 else { + continue; + }; // in types in actual Rust, these will always come // after the corresponding Implemented predicate if angle_open { @@ -2075,7 +2186,6 @@ fn write_bounds_like_dyn_trait<'db>( write!(f, "<")?; angle_open = true; } - let assoc_ty_id = projection.def_id().expect_type_alias(); let type_alias = TypeAliasSignature::of(f.db, assoc_ty_id); f.start_location_link(assoc_ty_id.into()); write!(f, "{}", type_alias.name.display(f.db, f.edition()))?; @@ -2174,11 +2284,28 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> { } } +impl<'db> HirDisplay<'db> for TraitPredicate<'db> { + fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { + self.self_ty().hir_fmt(f)?; + f.write_str(": ")?; + match self.polarity { + rustc_type_ir::PredicatePolarity::Positive => {} + rustc_type_ir::PredicatePolarity::Negative => f.write_char('!')?, + } + let trait_ = self.def_id().0; + f.start_location_link(trait_.into()); + write!(f, "{}", TraitSignature::of(f.db, trait_).name.display(f.db, f.edition()))?; + f.end_location_link(); + let substs = &self.trait_ref.args[1..]; + hir_fmt_generic_args(f, substs, None, None) + } +} + impl<'db> HirDisplay<'db> for Region<'db> { fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result { match self.kind() { RegionKind::ReEarlyParam(param) => { - let generics = generics(f.db, param.id.parent); + let generics = GenericParams::of(f.db, param.id.parent); let param_data = &generics[param.id.local_id]; f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name.display(f.db, f.edition()))?; @@ -2364,9 +2491,9 @@ impl<'db> HirDisplayWithExpressionStore<'db> for TypeRefId { if fn_.is_unsafe { write!(f, "unsafe ")?; } - if let Some(abi) = &fn_.abi { + if fn_.abi != ExternAbi::Rust { f.write_str("extern \"")?; - f.write_str(abi.as_str())?; + f.write_str(fn_.abi.as_str())?; f.write_str("\" ")?; } write!(f, "fn(")?; |