2021-04-09 12:39:07 +00:00
//! The `HirDisplay` trait, which serves two purposes: Turning various bits from
//! HIR back into source code, and just displaying them for debugging/testing
//! purposes.
2019-09-30 08:58:53 +00:00
2021-06-29 15:35:37 +00:00
use std ::fmt ::{ self , Debug } ;
2019-03-14 21:03:39 +00:00
2021-06-15 18:28:37 +00:00
use base_db ::CrateId ;
2023-03-05 10:23:49 +00:00
use chalk_ir ::{ BoundVar , TyKind } ;
2020-04-25 14:57:59 +00:00
use hir_def ::{
2023-04-06 17:23:29 +00:00
data ::adt ::VariantData ,
2021-03-14 12:03:39 +00:00
db ::DefDatabase ,
find_path ,
2021-12-29 13:35:59 +00:00
generics ::{ TypeOrConstParamData , TypeParamProvenance } ,
2021-03-14 12:03:39 +00:00
item_scope ::ItemInNs ,
2023-02-07 21:42:03 +00:00
lang_item ::{ LangItem , LangItemTarget } ,
2021-04-01 19:04:02 +00:00
path ::{ Path , PathKind } ,
2023-02-03 11:16:25 +00:00
type_ref ::{ TraitBoundModifier , TypeBound , TypeRef } ,
2021-03-14 12:03:39 +00:00
visibility ::Visibility ,
2023-02-03 11:16:25 +00:00
HasModule , ItemContainerId , LocalFieldId , Lookup , ModuleDefId , ModuleId , TraitId ,
2020-04-25 14:57:59 +00:00
} ;
2021-04-12 14:24:48 +00:00
use hir_expand ::{ hygiene ::Hygiene , name ::Name } ;
2023-01-09 18:29:28 +00:00
use intern ::{ Internable , Interned } ;
2021-06-29 23:34:51 +00:00
use itertools ::Itertools ;
2022-09-21 13:04:55 +00:00
use smallvec ::SmallVec ;
2023-04-06 12:44:38 +00:00
use stdx ::never ;
2019-03-14 21:03:39 +00:00
2021-03-01 20:57:39 +00:00
use crate ::{
2021-06-29 15:35:37 +00:00
db ::HirDatabase ,
2023-02-03 11:16:25 +00:00
from_assoc_type_id , from_foreign_def_id , from_placeholder_idx ,
layout ::layout_of_ty ,
lt_from_placeholder_idx ,
2021-06-29 15:35:37 +00:00
mapping ::from_chalk ,
2023-02-03 11:16:25 +00:00
mir ::pad16 ,
2022-10-02 13:15:57 +00:00
primitive , to_assoc_type_id ,
2023-04-28 17:14:30 +00:00
utils ::{ self , generics , ClosureSubst } ,
2023-02-03 11:16:25 +00:00
AdtId , AliasEq , AliasTy , Binders , CallableDefId , CallableSig , Const , ConstScalar , ConstValue ,
DomainGoal , GenericArg , ImplTraitId , Interner , Lifetime , LifetimeData , LifetimeOutlives ,
MemoryMap , Mutability , OpaqueTy , ProjectionTy , ProjectionTyExt , QuantifiedWhereClause , Scalar ,
2023-03-05 10:23:49 +00:00
Substitution , TraitRef , TraitRefExt , Ty , TyExt , WhereClause ,
2021-03-01 20:57:39 +00:00
} ;
2022-12-01 15:39:57 +00:00
pub trait HirWrite : fmt ::Write {
fn start_location_link ( & mut self , location : ModuleDefId ) ;
fn end_location_link ( & mut self ) ;
}
// String will ignore link metadata
impl HirWrite for String {
fn start_location_link ( & mut self , _ : ModuleDefId ) { }
fn end_location_link ( & mut self ) { }
}
// `core::Formatter` will ignore metadata
impl HirWrite for fmt ::Formatter < '_ > {
fn start_location_link ( & mut self , _ : ModuleDefId ) { }
fn end_location_link ( & mut self ) { }
}
2020-04-25 14:57:59 +00:00
pub struct HirFormatter < ' a > {
2020-03-13 15:05:46 +00:00
pub db : & ' a dyn HirDatabase ,
2022-12-01 15:39:57 +00:00
fmt : & ' a mut dyn HirWrite ,
2019-11-18 17:02:28 +00:00
buf : String ,
curr_size : usize ,
2020-01-22 14:44:05 +00:00
pub ( crate ) max_size : Option < usize > ,
2019-12-23 15:53:35 +00:00
omit_verbose_types : bool ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ,
2020-04-25 14:57:59 +00:00
display_target : DisplayTarget ,
2019-03-14 21:03:39 +00:00
}
2022-12-01 15:39:57 +00:00
impl HirFormatter < '_ > {
fn start_location_link ( & mut self , location : ModuleDefId ) {
self . fmt . start_location_link ( location ) ;
}
fn end_location_link ( & mut self ) {
self . fmt . end_location_link ( ) ;
}
}
2019-03-14 21:03:39 +00:00
pub trait HirDisplay {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > ;
2019-11-18 17:02:28 +00:00
2020-10-28 16:58:16 +00:00
/// Returns a `Display`able type that is human-readable.
fn into_displayable < ' a > (
& ' a self ,
db : & ' a dyn HirDatabase ,
max_size : Option < usize > ,
omit_verbose_types : bool ,
display_target : DisplayTarget ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ,
2020-10-28 16:58:16 +00:00
) -> HirDisplayWrapper < ' a , Self >
where
Self : Sized ,
{
2021-04-06 12:42:34 +00:00
assert! (
! matches! ( display_target , DisplayTarget ::SourceCode { .. } ) ,
" HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead "
) ;
2023-04-06 12:44:38 +00:00
HirDisplayWrapper {
db ,
t : self ,
max_size ,
omit_verbose_types ,
display_target ,
closure_style ,
}
2020-10-28 16:58:16 +00:00
}
2020-04-25 14:57:59 +00:00
/// Returns a `Display`able type that is human-readable.
/// Use this for showing types to the user (e.g. diagnostics)
2020-03-13 15:05:46 +00:00
fn display < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
2019-03-14 21:03:39 +00:00
where
Self : Sized ,
{
2020-04-25 14:57:59 +00:00
HirDisplayWrapper {
db ,
t : self ,
max_size : None ,
omit_verbose_types : false ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ::ImplFn ,
2020-04-25 14:57:59 +00:00
display_target : DisplayTarget ::Diagnostics ,
}
2019-11-18 17:02:28 +00:00
}
2020-04-25 14:57:59 +00:00
/// Returns a `Display`able type that is human-readable and tries to be succinct.
/// Use this for showing types to the user where space is constrained (e.g. doc popups)
2020-03-13 15:05:46 +00:00
fn display_truncated < ' a > (
2019-11-18 17:02:28 +00:00
& ' a self ,
2020-03-13 15:05:46 +00:00
db : & ' a dyn HirDatabase ,
2019-12-19 14:43:41 +00:00
max_size : Option < usize > ,
2020-03-13 15:05:46 +00:00
) -> HirDisplayWrapper < ' a , Self >
2019-11-18 17:02:28 +00:00
where
Self : Sized ,
{
2020-04-25 14:57:59 +00:00
HirDisplayWrapper {
db ,
t : self ,
max_size ,
omit_verbose_types : true ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ::ImplFn ,
2020-04-25 14:57:59 +00:00
display_target : DisplayTarget ::Diagnostics ,
}
}
/// Returns a String representation of `self` that can be inserted into the given module.
/// Use this when generating code (e.g. assists)
fn display_source_code < ' a > (
& ' a self ,
db : & ' a dyn HirDatabase ,
module_id : ModuleId ,
2023-04-07 13:45:04 +00:00
allow_opaque : bool ,
2020-04-25 14:57:59 +00:00
) -> Result < String , DisplaySourceCodeError > {
let mut result = String ::new ( ) ;
match self . hir_fmt ( & mut HirFormatter {
db ,
fmt : & mut result ,
buf : String ::with_capacity ( 20 ) ,
curr_size : 0 ,
max_size : None ,
omit_verbose_types : false ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ::ImplFn ,
2023-04-07 13:45:04 +00:00
display_target : DisplayTarget ::SourceCode { module_id , allow_opaque } ,
2020-10-28 11:29:42 +00:00
} ) {
Ok ( ( ) ) = > { }
Err ( HirDisplayError ::FmtError ) = > panic! ( " Writing to String can't fail! " ) ,
Err ( HirDisplayError ::DisplaySourceCodeError ( e ) ) = > return Err ( e ) ,
} ;
Ok ( result )
}
/// Returns a String representation of `self` for test purposes
2020-10-28 14:09:47 +00:00
fn display_test < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
where
Self : Sized ,
{
HirDisplayWrapper {
2020-10-28 11:29:42 +00:00
db ,
2020-10-28 14:09:47 +00:00
t : self ,
2020-10-28 11:29:42 +00:00
max_size : None ,
omit_verbose_types : false ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ::ImplFn ,
2020-10-28 14:09:47 +00:00
display_target : DisplayTarget ::Test ,
}
2019-03-14 21:03:39 +00:00
}
}
2020-04-25 14:57:59 +00:00
impl < ' a > HirFormatter < ' a > {
2019-03-14 21:03:39 +00:00
pub fn write_joined < T : HirDisplay > (
& mut self ,
iter : impl IntoIterator < Item = T > ,
sep : & str ,
2020-04-25 14:57:59 +00:00
) -> Result < ( ) , HirDisplayError > {
2019-03-14 21:03:39 +00:00
let mut first = true ;
for e in iter {
if ! first {
2022-12-23 18:42:58 +00:00
write! ( self , " {sep} " ) ? ;
2019-03-14 21:03:39 +00:00
}
first = false ;
2022-01-10 15:55:53 +00:00
// Abbreviate multiple omitted types with a single ellipsis.
if self . should_truncate ( ) {
2022-12-23 18:42:58 +00:00
return write! ( self , " {TYPE_HINT_TRUNCATION} " ) ;
2022-01-10 15:55:53 +00:00
}
2019-03-14 21:03:39 +00:00
e . hir_fmt ( self ) ? ;
}
Ok ( ( ) )
}
/// This allows using the `write!` macro directly with a `HirFormatter`.
2022-07-20 13:02:08 +00:00
pub fn write_fmt ( & mut self , args : fmt ::Arguments < '_ > ) -> Result < ( ) , HirDisplayError > {
2019-11-18 17:02:28 +00:00
// We write to a buffer first to track output size
self . buf . clear ( ) ;
fmt ::write ( & mut self . buf , args ) ? ;
self . curr_size + = self . buf . len ( ) ;
// Then we write to the internal formatter from the buffer
2020-04-25 14:57:59 +00:00
self . fmt . write_str ( & self . buf ) . map_err ( HirDisplayError ::from )
2019-11-18 17:02:28 +00:00
}
2022-04-07 13:41:07 +00:00
pub fn write_str ( & mut self , s : & str ) -> Result < ( ) , HirDisplayError > {
self . fmt . write_str ( s ) ? ;
Ok ( ( ) )
}
pub fn write_char ( & mut self , c : char ) -> Result < ( ) , HirDisplayError > {
self . fmt . write_char ( c ) ? ;
Ok ( ( ) )
}
2019-11-18 17:02:28 +00:00
pub fn should_truncate ( & self ) -> bool {
2021-10-03 12:53:01 +00:00
match self . max_size {
Some ( max_size ) = > self . curr_size > = max_size ,
None = > false ,
2019-11-18 17:02:28 +00:00
}
2019-03-14 21:03:39 +00:00
}
2019-12-07 22:54:18 +00:00
2019-12-23 15:53:35 +00:00
pub fn omit_verbose_types ( & self ) -> bool {
self . omit_verbose_types
2019-12-07 22:54:18 +00:00
}
}
2020-04-25 14:57:59 +00:00
#[ derive(Clone, Copy) ]
2020-10-28 16:58:16 +00:00
pub enum DisplayTarget {
2020-04-25 14:57:59 +00:00
/// Display types for inlays, doc popups, autocompletion, etc...
/// Showing `{unknown}` or not qualifying paths is fine here.
/// There's no reason for this to fail.
Diagnostics ,
/// Display types for inserting them in source files.
/// The generated code should compile, so paths need to be qualified.
2023-04-07 13:45:04 +00:00
SourceCode { module_id : ModuleId , allow_opaque : bool } ,
2020-10-28 10:20:05 +00:00
/// Only for test purpose to keep real types
2020-10-28 14:09:47 +00:00
Test ,
2020-04-25 14:57:59 +00:00
}
2020-05-10 16:09:22 +00:00
impl DisplayTarget {
2023-04-07 13:45:04 +00:00
fn is_source_code ( self ) -> bool {
2021-01-05 12:45:46 +00:00
matches! ( self , Self ::SourceCode { .. } )
2020-05-10 16:09:22 +00:00
}
2023-04-07 13:45:04 +00:00
fn is_test ( self ) -> bool {
2020-10-28 14:09:47 +00:00
matches! ( self , Self ::Test )
2020-10-28 10:20:05 +00:00
}
2023-04-07 13:45:04 +00:00
fn allows_opaque ( self ) -> bool {
match self {
Self ::SourceCode { allow_opaque , .. } = > allow_opaque ,
_ = > true ,
}
}
2020-05-10 16:09:22 +00:00
}
2020-04-25 14:57:59 +00:00
#[ derive(Debug) ]
pub enum DisplaySourceCodeError {
PathNotFound ,
2020-12-12 17:18:19 +00:00
UnknownType ,
2022-09-21 13:04:55 +00:00
Generator ,
2023-04-07 13:45:04 +00:00
OpaqueType ,
2020-04-25 14:57:59 +00:00
}
pub enum HirDisplayError {
/// Errors that can occur when generating source code
DisplaySourceCodeError ( DisplaySourceCodeError ) ,
/// `FmtError` is required to be compatible with std::fmt::Display
FmtError ,
}
impl From < fmt ::Error > for HirDisplayError {
fn from ( _ : fmt ::Error ) -> Self {
Self ::FmtError
}
}
pub struct HirDisplayWrapper < ' a , T > {
db : & ' a dyn HirDatabase ,
t : & ' a T ,
max_size : Option < usize > ,
omit_verbose_types : bool ,
2023-04-06 12:44:38 +00:00
closure_style : ClosureStyle ,
2020-04-25 14:57:59 +00:00
display_target : DisplayTarget ,
}
2019-03-14 21:03:39 +00:00
2023-04-06 12:44:38 +00:00
#[ derive(Debug, PartialEq, Eq, Clone, Copy) ]
pub enum ClosureStyle {
/// `impl FnX(i32, i32) -> i32`, where `FnX` is the most special trait between `Fn`, `FnMut`, `FnOnce` that the
/// closure implements. This is the default.
ImplFn ,
/// `|i32, i32| -> i32`
RANotation ,
/// `{closure#14825}`, useful for some diagnostics (like type mismatch) and internal usage.
ClosureWithId ,
/// `…`, which is the `TYPE_HINT_TRUNCATION`
Hide ,
}
2022-12-01 15:39:57 +00:00
impl < T : HirDisplay > HirDisplayWrapper < '_ , T > {
pub fn write_to < F : HirWrite > ( & self , f : & mut F ) -> Result < ( ) , HirDisplayError > {
self . t . hir_fmt ( & mut HirFormatter {
2020-04-25 14:57:59 +00:00
db : self . db ,
2019-11-18 17:02:28 +00:00
fmt : f ,
buf : String ::with_capacity ( 20 ) ,
curr_size : 0 ,
2020-04-25 14:57:59 +00:00
max_size : self . max_size ,
omit_verbose_types : self . omit_verbose_types ,
display_target : self . display_target ,
2023-04-06 12:44:38 +00:00
closure_style : self . closure_style ,
2022-12-01 15:39:57 +00:00
} )
}
2023-04-06 12:44:38 +00:00
pub fn with_closure_style ( mut self , c : ClosureStyle ) -> Self {
self . closure_style = c ;
self
}
2022-12-01 15:39:57 +00:00
}
impl < ' a , T > fmt ::Display for HirDisplayWrapper < ' a , T >
where
T : HirDisplay ,
{
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
match self . write_to ( f ) {
2020-04-25 14:57:59 +00:00
Ok ( ( ) ) = > Ok ( ( ) ) ,
Err ( HirDisplayError ::FmtError ) = > Err ( fmt ::Error ) ,
Err ( HirDisplayError ::DisplaySourceCodeError ( _ ) ) = > {
// This should never happen
2021-04-06 12:42:34 +00:00
panic! ( " HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt! " )
2020-04-25 14:57:59 +00:00
}
}
2019-03-14 21:03:39 +00:00
}
}
2020-02-14 14:01:25 +00:00
const TYPE_HINT_TRUNCATION : & str = " … " ;
2021-03-14 12:03:39 +00:00
impl < T : HirDisplay > HirDisplay for & '_ T {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2020-02-14 14:01:25 +00:00
HirDisplay ::hir_fmt ( * self , f )
}
}
2021-05-24 13:13:23 +00:00
impl < T : HirDisplay + Internable > HirDisplay for Interned < T > {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-05-24 13:13:23 +00:00
HirDisplay ::hir_fmt ( self . as_ref ( ) , f )
}
}
2021-02-28 18:13:37 +00:00
impl HirDisplay for ProjectionTy {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2020-02-14 14:01:25 +00:00
if f . should_truncate ( ) {
2022-12-23 18:42:58 +00:00
return write! ( f , " {TYPE_HINT_TRUNCATION} " ) ;
2020-02-14 14:01:25 +00:00
}
2022-10-27 08:05:22 +00:00
let trait_ref = self . trait_ref ( f . db ) ;
2021-04-06 12:16:07 +00:00
write! ( f , " < " ) ? ;
2023-01-14 12:27:32 +00:00
fmt_trait_ref ( f , & trait_ref , true ) ? ;
2022-10-27 08:05:22 +00:00
write! ( f , " >::{} " , f . db . type_alias_data ( from_assoc_type_id ( self . associated_ty_id ) ) . name ) ? ;
let proj_params_count =
self . substitution . len ( Interner ) - trait_ref . substitution . len ( Interner ) ;
let proj_params = & self . substitution . as_slice ( Interner ) [ .. proj_params_count ] ;
if ! proj_params . is_empty ( ) {
2021-02-28 18:13:37 +00:00
write! ( f , " < " ) ? ;
2022-10-27 08:05:22 +00:00
f . write_joined ( proj_params , " , " ) ? ;
2021-02-28 18:13:37 +00:00
write! ( f , " > " ) ? ;
}
Ok ( ( ) )
}
}
2021-03-19 01:07:15 +00:00
impl HirDisplay for OpaqueTy {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-03-19 01:07:15 +00:00
if f . should_truncate ( ) {
2022-12-23 18:42:58 +00:00
return write! ( f , " {TYPE_HINT_TRUNCATION} " ) ;
2021-03-19 01:07:15 +00:00
}
2021-12-19 16:58:39 +00:00
self . substitution . at ( Interner , 0 ) . hir_fmt ( f )
2021-04-01 19:04:02 +00:00
}
}
impl HirDisplay for GenericArg {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-04-01 19:04:02 +00:00
match self . interned ( ) {
crate ::GenericArgData ::Ty ( ty ) = > ty . hir_fmt ( f ) ,
2021-04-08 11:51:04 +00:00
crate ::GenericArgData ::Lifetime ( lt ) = > lt . hir_fmt ( f ) ,
crate ::GenericArgData ::Const ( c ) = > c . hir_fmt ( f ) ,
2021-04-01 19:04:02 +00:00
}
2021-03-19 01:07:15 +00:00
}
}
2021-04-06 09:45:41 +00:00
impl HirDisplay for Const {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-04-06 09:45:41 +00:00
let data = self . interned ( ) ;
2023-02-03 11:16:25 +00:00
match & data . value {
2021-04-06 09:45:41 +00:00
ConstValue ::BoundVar ( idx ) = > idx . hir_fmt ( f ) ,
2022-03-09 18:50:24 +00:00
ConstValue ::InferenceVar ( .. ) = > write! ( f , " #c# " ) ,
2021-04-06 09:45:41 +00:00
ConstValue ::Placeholder ( idx ) = > {
2023-02-03 11:16:25 +00:00
let id = from_placeholder_idx ( f . db , * idx ) ;
2021-04-06 09:45:41 +00:00
let generics = generics ( f . db . upcast ( ) , id . parent ) ;
2022-03-09 18:50:24 +00:00
let param_data = & generics . params . type_or_consts [ id . local_id ] ;
2021-12-29 13:35:59 +00:00
write! ( f , " {} " , param_data . name ( ) . unwrap ( ) )
2021-04-06 09:45:41 +00:00
}
2023-02-03 11:16:25 +00:00
ConstValue ::Concrete ( c ) = > match & c . interned {
ConstScalar ::Bytes ( b , m ) = > render_const_scalar ( f , & b , m , & data . ty ) ,
2023-04-28 17:14:30 +00:00
ConstScalar ::UnevaluatedConst ( c , parameters ) = > {
let const_data = f . db . const_data ( * c ) ;
write! (
f ,
" {} " ,
const_data . name . as_ref ( ) . and_then ( | x | x . as_str ( ) ) . unwrap_or ( " _ " )
) ? ;
hir_fmt_generics ( f , parameters , Some ( ( * c ) . into ( ) ) ) ? ;
Ok ( ( ) )
}
2023-02-03 11:16:25 +00:00
ConstScalar ::Unknown = > f . write_char ( '_' ) ,
} ,
2021-04-06 09:45:41 +00:00
}
}
}
2023-03-05 10:23:49 +00:00
pub struct HexifiedConst ( pub Const ) ;
impl HirDisplay for HexifiedConst {
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
let data = & self . 0. data ( Interner ) ;
if let TyKind ::Scalar ( s ) = data . ty . kind ( Interner ) {
if matches! ( s , Scalar ::Int ( _ ) | Scalar ::Uint ( _ ) ) {
if let ConstValue ::Concrete ( c ) = & data . value {
if let ConstScalar ::Bytes ( b , m ) = & c . interned {
let value = u128 ::from_le_bytes ( pad16 ( b , false ) ) ;
if value > = 10 {
render_const_scalar ( f , & b , m , & data . ty ) ? ;
return write! ( f , " ({:#X}) " , value ) ;
}
}
}
}
}
self . 0. hir_fmt ( f )
}
}
2023-02-03 11:16:25 +00:00
fn render_const_scalar (
f : & mut HirFormatter < '_ > ,
b : & [ u8 ] ,
memory_map : & MemoryMap ,
ty : & Ty ,
) -> Result < ( ) , HirDisplayError > {
match ty . kind ( Interner ) {
chalk_ir ::TyKind ::Scalar ( s ) = > match s {
Scalar ::Bool = > write! ( f , " {} " , if b [ 0 ] = = 0 { false } else { true } ) ,
Scalar ::Char = > {
let x = u128 ::from_le_bytes ( pad16 ( b , false ) ) as u32 ;
let Ok ( c ) = char ::try_from ( x ) else {
return f . write_str ( " <unicode-error> " ) ;
} ;
write! ( f , " {c:?} " )
}
Scalar ::Int ( _ ) = > {
let x = i128 ::from_le_bytes ( pad16 ( b , true ) ) ;
write! ( f , " {x} " )
}
Scalar ::Uint ( _ ) = > {
let x = u128 ::from_le_bytes ( pad16 ( b , false ) ) ;
write! ( f , " {x} " )
}
Scalar ::Float ( fl ) = > match fl {
chalk_ir ::FloatTy ::F32 = > {
let x = f32 ::from_le_bytes ( b . try_into ( ) . unwrap ( ) ) ;
write! ( f , " {x:?} " )
}
chalk_ir ::FloatTy ::F64 = > {
let x = f64 ::from_le_bytes ( b . try_into ( ) . unwrap ( ) ) ;
write! ( f , " {x:?} " )
}
} ,
} ,
chalk_ir ::TyKind ::Ref ( _ , _ , t ) = > match t . kind ( Interner ) {
chalk_ir ::TyKind ::Str = > {
let addr = usize ::from_le_bytes ( b [ 0 .. b . len ( ) / 2 ] . try_into ( ) . unwrap ( ) ) ;
2023-04-28 17:14:30 +00:00
let bytes = memory_map . memory . get ( & addr ) . map ( | x | & * * x ) . unwrap_or ( & [ ] ) ;
2023-02-03 11:16:25 +00:00
let s = std ::str ::from_utf8 ( bytes ) . unwrap_or ( " <utf8-error> " ) ;
write! ( f , " {s:?} " )
}
2023-02-28 19:42:30 +00:00
_ = > f . write_str ( " <ref-not-supported> " ) ,
2023-02-03 11:16:25 +00:00
} ,
2023-02-28 19:42:30 +00:00
chalk_ir ::TyKind ::Tuple ( _ , subst ) = > {
// FIXME: Remove this line. If the target data layout is independent
// of the krate, the `db.target_data_layout` and its callers like `layout_of_ty` don't need
// to get krate. Otherwise, we need to get krate from the final callers of the hir display
// infrastructure and have it here as a field on `f`.
let krate = * f . db . crate_graph ( ) . crates_in_topological_order ( ) . last ( ) . unwrap ( ) ;
let Ok ( layout ) = layout_of_ty ( f . db , ty , krate ) else {
return f . write_str ( " <layout-error> " ) ;
} ;
f . write_str ( " ( " ) ? ;
let mut first = true ;
for ( id , ty ) in subst . iter ( Interner ) . enumerate ( ) {
if first {
first = false ;
} else {
f . write_str ( " , " ) ? ;
}
let ty = ty . assert_ty_ref ( Interner ) ; // Tuple only has type argument
let offset = layout . fields . offset ( id ) . bytes_usize ( ) ;
let Ok ( layout ) = layout_of_ty ( f . db , & ty , krate ) else {
f . write_str ( " <layout-error> " ) ? ;
continue ;
} ;
let size = layout . size . bytes_usize ( ) ;
render_const_scalar ( f , & b [ offset .. offset + size ] , memory_map , & ty ) ? ;
}
f . write_str ( " ) " )
}
2023-02-03 11:16:25 +00:00
chalk_ir ::TyKind ::Adt ( adt , subst ) = > match adt . 0 {
hir_def ::AdtId ::StructId ( s ) = > {
let data = f . db . struct_data ( s ) ;
let Ok ( layout ) = f . db . layout_of_adt ( adt . 0 , subst . clone ( ) ) else {
return f . write_str ( " <layout-error> " ) ;
} ;
match data . variant_data . as_ref ( ) {
VariantData ::Record ( fields ) | VariantData ::Tuple ( fields ) = > {
let field_types = f . db . field_types ( s . into ( ) ) ;
let krate = adt . 0. module ( f . db . upcast ( ) ) . krate ( ) ;
let render_field = | f : & mut HirFormatter < '_ > , id : LocalFieldId | {
let offset = layout
. fields
. offset ( u32 ::from ( id . into_raw ( ) ) as usize )
. bytes_usize ( ) ;
let ty = field_types [ id ] . clone ( ) . substitute ( Interner , subst ) ;
let Ok ( layout ) = layout_of_ty ( f . db , & ty , krate ) else {
return f . write_str ( " <layout-error> " ) ;
} ;
let size = layout . size . bytes_usize ( ) ;
render_const_scalar ( f , & b [ offset .. offset + size ] , memory_map , & ty )
} ;
let mut it = fields . iter ( ) ;
if matches! ( data . variant_data . as_ref ( ) , VariantData ::Record ( _ ) ) {
write! ( f , " {} {{ " , data . name ) ? ;
if let Some ( ( id , data ) ) = it . next ( ) {
write! ( f , " {}: " , data . name ) ? ;
render_field ( f , id ) ? ;
}
for ( id , data ) in it {
2023-02-28 19:42:30 +00:00
write! ( f , " , {}: " , data . name ) ? ;
2023-02-03 11:16:25 +00:00
render_field ( f , id ) ? ;
}
write! ( f , " }} " ) ? ;
} else {
let mut it = it . map ( | x | x . 0 ) ;
write! ( f , " {}( " , data . name ) ? ;
if let Some ( id ) = it . next ( ) {
render_field ( f , id ) ? ;
}
for id in it {
write! ( f , " , " ) ? ;
render_field ( f , id ) ? ;
}
write! ( f , " ) " ) ? ;
}
return Ok ( ( ) ) ;
}
VariantData ::Unit = > write! ( f , " {} " , data . name ) ,
}
}
hir_def ::AdtId ::UnionId ( u ) = > write! ( f , " {} " , f . db . union_data ( u ) . name ) ,
hir_def ::AdtId ::EnumId ( _ ) = > f . write_str ( " <enum-not-supported> " ) ,
} ,
2023-02-26 12:34:41 +00:00
chalk_ir ::TyKind ::FnDef ( .. ) = > ty . hir_fmt ( f ) ,
2023-04-28 17:14:30 +00:00
chalk_ir ::TyKind ::Raw ( _ , _ ) = > {
let x = u128 ::from_le_bytes ( pad16 ( b , false ) ) ;
write! ( f , " {:#X} as " , x ) ? ;
ty . hir_fmt ( f )
}
2023-02-28 19:42:30 +00:00
_ = > f . write_str ( " <not-supported> " ) ,
2023-02-03 11:16:25 +00:00
}
}
2021-04-06 09:45:41 +00:00
impl HirDisplay for BoundVar {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-04-06 09:45:41 +00:00
write! ( f , " ?{}.{} " , self . debruijn . depth ( ) , self . index )
}
}
2021-02-28 18:13:37 +00:00
impl HirDisplay for Ty {
2023-01-14 12:27:32 +00:00
fn hir_fmt (
& self ,
f @ & mut HirFormatter { db , .. } : & mut HirFormatter < '_ > ,
) -> Result < ( ) , HirDisplayError > {
2021-02-28 18:13:37 +00:00
if f . should_truncate ( ) {
2022-12-23 18:42:58 +00:00
return write! ( f , " {TYPE_HINT_TRUNCATION} " ) ;
2021-02-28 18:13:37 +00:00
}
2022-02-15 14:47:51 +00:00
2021-12-19 16:58:39 +00:00
match self . kind ( Interner ) {
2021-03-13 13:44:51 +00:00
TyKind ::Never = > write! ( f , " ! " ) ? ,
TyKind ::Str = > write! ( f , " str " ) ? ,
TyKind ::Scalar ( Scalar ::Bool ) = > write! ( f , " bool " ) ? ,
TyKind ::Scalar ( Scalar ::Char ) = > write! ( f , " char " ) ? ,
& TyKind ::Scalar ( Scalar ::Float ( t ) ) = > write! ( f , " {} " , primitive ::float_ty_to_string ( t ) ) ? ,
& TyKind ::Scalar ( Scalar ::Int ( t ) ) = > write! ( f , " {} " , primitive ::int_ty_to_string ( t ) ) ? ,
& TyKind ::Scalar ( Scalar ::Uint ( t ) ) = > write! ( f , " {} " , primitive ::uint_ty_to_string ( t ) ) ? ,
2021-03-14 16:40:55 +00:00
TyKind ::Slice ( t ) = > {
2020-10-28 16:58:16 +00:00
write! ( f , " [ " ) ? ;
t . hir_fmt ( f ) ? ;
write! ( f , " ] " ) ? ;
2020-02-14 14:01:25 +00:00
}
2021-04-06 09:45:41 +00:00
TyKind ::Array ( t , c ) = > {
2020-10-28 16:58:16 +00:00
write! ( f , " [ " ) ? ;
t . hir_fmt ( f ) ? ;
2021-04-06 09:45:41 +00:00
write! ( f , " ; " ) ? ;
c . hir_fmt ( f ) ? ;
write! ( f , " ] " ) ? ;
2020-02-14 14:01:25 +00:00
}
2021-04-05 20:08:16 +00:00
TyKind ::Raw ( m , t ) | TyKind ::Ref ( m , _ , t ) = > {
2021-12-19 16:58:39 +00:00
if matches! ( self . kind ( Interner ) , TyKind ::Raw ( .. ) ) {
2021-03-01 18:30:34 +00:00
write! (
f ,
" *{} " ,
match m {
Mutability ::Not = > " const " ,
Mutability ::Mut = > " mut " ,
}
) ? ;
2020-10-06 12:40:27 +00:00
} else {
2021-03-01 18:30:34 +00:00
write! (
f ,
" &{} " ,
match m {
Mutability ::Not = > " " ,
Mutability ::Mut = > " mut " ,
}
) ? ;
2021-01-12 19:19:13 +00:00
}
2021-03-13 19:05:47 +00:00
// FIXME: all this just to decide whether to use parentheses...
2021-08-12 14:31:00 +00:00
let contains_impl_fn = | bounds : & [ QuantifiedWhereClause ] | {
2021-08-03 12:01:00 +00:00
bounds . iter ( ) . any ( | bound | {
if let WhereClause ::Implemented ( trait_ref ) = bound . skip_binders ( ) {
let trait_ = trait_ref . hir_trait_id ( ) ;
2023-01-14 12:27:32 +00:00
fn_traits ( db . upcast ( ) , trait_ ) . any ( | it | it = = trait_ )
2021-08-03 12:01:00 +00:00
} else {
false
}
} )
} ;
2021-12-19 16:58:39 +00:00
let ( preds_to_print , has_impl_fn_pred ) = match t . kind ( Interner ) {
2021-03-21 12:22:22 +00:00
TyKind ::Dyn ( dyn_ty ) if dyn_ty . bounds . skip_binders ( ) . interned ( ) . len ( ) > 1 = > {
2021-08-03 12:01:00 +00:00
let bounds = dyn_ty . bounds . skip_binders ( ) . interned ( ) ;
2021-08-12 14:31:00 +00:00
( bounds . len ( ) , contains_impl_fn ( bounds ) )
2021-01-12 19:19:13 +00:00
}
2021-08-02 12:59:28 +00:00
TyKind ::Alias ( AliasTy ::Opaque ( OpaqueTy {
2021-03-14 15:33:27 +00:00
opaque_ty_id ,
2021-08-02 12:59:28 +00:00
substitution : parameters ,
2021-07-08 19:19:53 +00:00
} ) )
2021-08-02 12:59:28 +00:00
| TyKind ::OpaqueType ( opaque_ty_id , parameters ) = > {
2023-01-14 12:27:32 +00:00
let impl_trait_id = db . lookup_intern_impl_trait_id ( ( * opaque_ty_id ) . into ( ) ) ;
2021-03-13 19:05:47 +00:00
if let ImplTraitId ::ReturnTypeImplTrait ( func , idx ) = impl_trait_id {
2023-01-14 12:27:32 +00:00
let datas = db
. return_type_impl_traits ( func )
. expect ( " impl trait id without data " ) ;
2023-02-06 17:20:25 +00:00
let data =
( * datas ) . as_ref ( ) . map ( | rpit | rpit . impl_traits [ idx ] . bounds . clone ( ) ) ;
2021-12-19 16:58:39 +00:00
let bounds = data . substitute ( Interner , parameters ) ;
2021-08-03 12:01:00 +00:00
let mut len = bounds . skip_binders ( ) . len ( ) ;
// Don't count Sized but count when it absent
// (i.e. when explicit ?Sized bound is set).
let default_sized = SizedByDefault ::Sized {
2023-01-14 12:27:32 +00:00
anchor : func . lookup ( db . upcast ( ) ) . module ( db . upcast ( ) ) . krate ( ) ,
2021-08-03 12:01:00 +00:00
} ;
let sized_bounds = bounds
. skip_binders ( )
. iter ( )
. filter ( | b | {
matches! (
b . skip_binders ( ) ,
WhereClause ::Implemented ( trait_ref )
if default_sized . is_sized_trait (
trait_ref . hir_trait_id ( ) ,
2023-01-14 12:27:32 +00:00
db . upcast ( ) ,
2021-08-03 12:01:00 +00:00
) ,
)
} )
. count ( ) ;
match sized_bounds {
0 = > len + = 1 ,
_ = > {
len = len . saturating_sub ( sized_bounds ) ;
}
}
2021-08-12 14:31:00 +00:00
( len , contains_impl_fn ( bounds . skip_binders ( ) ) )
2021-03-13 19:05:47 +00:00
} else {
2021-08-03 12:01:00 +00:00
( 0 , false )
2021-03-13 19:05:47 +00:00
}
2021-01-12 19:19:13 +00:00
}
2021-08-03 12:01:00 +00:00
_ = > ( 0 , false ) ,
2021-01-12 19:19:13 +00:00
} ;
2021-08-03 12:01:00 +00:00
if has_impl_fn_pred & & preds_to_print < = 2 {
return t . hir_fmt ( f ) ;
2020-10-06 12:40:27 +00:00
}
2021-08-03 12:01:00 +00:00
if preds_to_print > 1 {
2020-10-06 12:40:27 +00:00
write! ( f , " ( " ) ? ;
2021-04-06 12:16:07 +00:00
t . hir_fmt ( f ) ? ;
2020-10-06 12:40:27 +00:00
write! ( f , " ) " ) ? ;
} else {
2021-04-06 12:16:07 +00:00
t . hir_fmt ( f ) ? ;
2020-10-06 12:40:27 +00:00
}
2020-02-14 14:01:25 +00:00
}
2021-03-13 13:44:51 +00:00
TyKind ::Tuple ( _ , substs ) = > {
2021-12-19 16:58:39 +00:00
if substs . len ( Interner ) = = 1 {
2020-10-28 16:58:16 +00:00
write! ( f , " ( " ) ? ;
2021-12-19 16:58:39 +00:00
substs . at ( Interner , 0 ) . hir_fmt ( f ) ? ;
2020-10-28 16:58:16 +00:00
write! ( f , " ,) " ) ? ;
2020-02-14 14:01:25 +00:00
} else {
write! ( f , " ( " ) ? ;
2021-12-19 16:58:39 +00:00
f . write_joined ( & * substs . as_slice ( Interner ) , " , " ) ? ;
2020-02-14 14:01:25 +00:00
write! ( f , " ) " ) ? ;
}
}
2021-03-13 13:44:51 +00:00
TyKind ::Function ( fn_ptr ) = > {
2021-02-28 21:12:07 +00:00
let sig = CallableSig ::from_fn_ptr ( fn_ptr ) ;
2020-12-09 17:06:56 +00:00
sig . hir_fmt ( f ) ? ;
2020-02-14 14:01:25 +00:00
}
2021-03-13 13:44:51 +00:00
TyKind ::FnDef ( def , parameters ) = > {
2023-01-14 12:27:32 +00:00
let def = from_chalk ( db , * def ) ;
let sig = db . callable_item_signature ( def ) . substitute ( Interner , parameters ) ;
f . start_location_link ( def . into ( ) ) ;
2020-03-28 21:25:29 +00:00
match def {
2023-01-14 12:27:32 +00:00
CallableDefId ::FunctionId ( ff ) = > write! ( f , " fn {} " , db . function_data ( ff ) . name ) ? ,
CallableDefId ::StructId ( s ) = > write! ( f , " {} " , db . struct_data ( s ) . name ) ? ,
2020-07-16 11:15:00 +00:00
CallableDefId ::EnumVariantId ( e ) = > {
2023-01-14 12:27:32 +00:00
write! ( f , " {} " , db . enum_data ( e . parent ) . variants [ e . local_id ] . name ) ?
2020-02-14 14:01:25 +00:00
}
} ;
2023-01-14 12:27:32 +00:00
f . end_location_link ( ) ;
2021-12-19 16:58:39 +00:00
if parameters . len ( Interner ) > 0 {
2023-01-14 12:27:32 +00:00
let generics = generics ( db . upcast ( ) , def . into ( ) ) ;
2022-03-08 16:21:35 +00:00
let ( parent_params , self_param , type_params , const_params , _impl_trait_params ) =
2020-02-14 14:01:25 +00:00
generics . provenance_split ( ) ;
2022-03-08 16:21:35 +00:00
let total_len = parent_params + self_param + type_params + const_params ;
2020-02-14 14:01:25 +00:00
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 {
2022-10-02 13:15:57 +00:00
// `parameters` are in the order of fn's params (including impl traits),
// parent's params (those from enclosing impl or trait, if any).
let parameters = parameters . as_slice ( Interner ) ;
let fn_params_len = self_param + type_params + const_params ;
let fn_params = parameters . get ( .. fn_params_len ) ;
let parent_params = parameters . get ( parameters . len ( ) - parent_params .. ) ;
let params = parent_params . into_iter ( ) . chain ( fn_params ) . flatten ( ) ;
2020-02-14 14:01:25 +00:00
write! ( f , " < " ) ? ;
2022-10-02 13:15:57 +00:00
f . write_joined ( params , " , " ) ? ;
2020-02-14 14:01:25 +00:00
write! ( f , " > " ) ? ;
}
}
write! ( f , " ( " ) ? ;
f . write_joined ( sig . params ( ) , " , " ) ? ;
2020-04-05 15:25:47 +00:00
write! ( f , " ) " ) ? ;
let ret = sig . ret ( ) ;
2021-04-03 18:22:59 +00:00
if ! ret . is_unit ( ) {
2021-04-06 12:16:07 +00:00
write! ( f , " -> " ) ? ;
ret . hir_fmt ( f ) ? ;
2020-04-05 15:25:47 +00:00
}
2020-02-14 14:01:25 +00:00
}
2021-03-13 13:44:51 +00:00
TyKind ::Adt ( AdtId ( def_id ) , parameters ) = > {
2022-12-01 15:39:57 +00:00
f . start_location_link ( ( * def_id ) . into ( ) ) ;
2020-04-25 14:57:59 +00:00
match f . display_target {
2020-10-28 14:09:47 +00:00
DisplayTarget ::Diagnostics | DisplayTarget ::Test = > {
2021-02-28 18:46:59 +00:00
let name = match * def_id {
2023-01-14 12:27:32 +00:00
hir_def ::AdtId ::StructId ( it ) = > db . struct_data ( it ) . name . clone ( ) ,
hir_def ::AdtId ::UnionId ( it ) = > db . union_data ( it ) . name . clone ( ) ,
hir_def ::AdtId ::EnumId ( it ) = > db . enum_data ( it ) . name . clone ( ) ,
2020-04-25 14:57:59 +00:00
} ;
2022-12-23 18:42:58 +00:00
write! ( f , " {name} " ) ? ;
2020-04-25 14:57:59 +00:00
}
2023-04-07 13:45:04 +00:00
DisplayTarget ::SourceCode { module_id , allow_opaque : _ } = > {
2020-10-28 10:20:05 +00:00
if let Some ( path ) = find_path ::find_path (
2023-01-14 12:27:32 +00:00
db . upcast ( ) ,
2021-02-28 18:46:59 +00:00
ItemInNs ::Types ( ( * def_id ) . into ( ) ) ,
2020-10-28 10:20:05 +00:00
module_id ,
2022-09-09 18:04:56 +00:00
false ,
2020-10-28 10:20:05 +00:00
) {
2022-12-23 18:42:58 +00:00
write! ( f , " {path} " ) ? ;
2020-10-28 10:20:05 +00:00
} else {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::PathNotFound ,
) ) ;
}
}
2020-04-25 14:57:59 +00:00
}
2022-12-01 15:39:57 +00:00
f . end_location_link ( ) ;
2020-04-25 14:57:59 +00:00
2023-04-28 17:14:30 +00:00
let generic_def = self . as_generic_def ( db ) ;
2022-01-02 23:34:33 +00:00
2023-04-28 17:14:30 +00:00
hir_fmt_generics ( f , parameters , generic_def ) ? ;
2020-02-14 14:01:25 +00:00
}
2021-03-13 16:36:07 +00:00
TyKind ::AssociatedType ( assoc_type_id , parameters ) = > {
let type_alias = from_assoc_type_id ( * assoc_type_id ) ;
2023-01-14 12:27:32 +00:00
let trait_ = match type_alias . lookup ( db . upcast ( ) ) . container {
2021-12-07 16:31:26 +00:00
ItemContainerId ::TraitId ( it ) = > it ,
2020-02-14 14:01:25 +00:00
_ = > panic! ( " not an associated type " ) ,
} ;
2023-01-14 12:27:32 +00:00
let trait_data = db . trait_data ( trait_ ) ;
let type_alias_data = db . type_alias_data ( type_alias ) ;
2020-10-27 19:23:09 +00:00
2020-10-28 10:20:05 +00:00
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
2020-10-28 14:09:47 +00:00
if f . display_target . is_test ( ) {
2023-01-14 12:27:32 +00:00
f . start_location_link ( trait_ . into ( ) ) ;
write! ( f , " {} " , trait_data . name ) ? ;
f . end_location_link ( ) ;
write! ( f , " :: " ) ? ;
f . start_location_link ( type_alias . into ( ) ) ;
write! ( f , " {} " , type_alias_data . name ) ? ;
f . end_location_link ( ) ;
2022-10-27 08:05:22 +00:00
// Note that the generic args for the associated type come before those for the
// trait (including the self type).
// FIXME: reconsider the generic args order upon formatting?
2021-12-19 16:58:39 +00:00
if parameters . len ( Interner ) > 0 {
2020-10-27 19:23:09 +00:00
write! ( f , " < " ) ? ;
2022-10-27 08:05:22 +00:00
f . write_joined ( parameters . as_slice ( Interner ) , " , " ) ? ;
2020-10-27 19:23:09 +00:00
write! ( f , " > " ) ? ;
}
} else {
2021-03-13 16:36:07 +00:00
let projection_ty = ProjectionTy {
2021-03-14 15:26:12 +00:00
associated_ty_id : to_assoc_type_id ( type_alias ) ,
substitution : parameters . clone ( ) ,
2021-03-13 16:36:07 +00:00
} ;
2020-10-28 14:09:47 +00:00
projection_ty . hir_fmt ( f ) ? ;
2020-02-14 14:01:25 +00:00
}
}
2021-04-05 12:38:28 +00:00
TyKind ::Foreign ( type_alias ) = > {
2023-01-14 12:27:32 +00:00
let alias = from_foreign_def_id ( * type_alias ) ;
let type_alias = db . type_alias_data ( alias ) ;
f . start_location_link ( alias . into ( ) ) ;
2020-09-13 02:24:19 +00:00
write! ( f , " {} " , type_alias . name ) ? ;
2023-01-14 12:27:32 +00:00
f . end_location_link ( ) ;
2020-09-13 02:24:19 +00:00
}
2021-03-13 13:44:51 +00:00
TyKind ::OpaqueType ( opaque_ty_id , parameters ) = > {
2023-04-07 13:45:04 +00:00
if ! f . display_target . allows_opaque ( ) {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::OpaqueType ,
) ) ;
}
2023-01-14 12:27:32 +00:00
let impl_trait_id = db . lookup_intern_impl_trait_id ( ( * opaque_ty_id ) . into ( ) ) ;
2021-03-13 19:05:47 +00:00
match impl_trait_id {
ImplTraitId ::ReturnTypeImplTrait ( func , idx ) = > {
2020-03-04 22:00:44 +00:00
let datas =
2023-01-14 12:27:32 +00:00
db . return_type_impl_traits ( func ) . expect ( " impl trait id without data " ) ;
2023-02-06 17:20:25 +00:00
let data =
( * datas ) . as_ref ( ) . map ( | rpit | rpit . impl_traits [ idx ] . bounds . clone ( ) ) ;
2021-12-19 16:58:39 +00:00
let bounds = data . substitute ( Interner , & parameters ) ;
2023-01-14 12:27:32 +00:00
let krate = func . lookup ( db . upcast ( ) ) . module ( db . upcast ( ) ) . krate ( ) ;
2021-06-15 08:53:20 +00:00
write_bounds_like_dyn_trait_with_prefix (
2023-01-14 12:27:32 +00:00
f ,
2021-06-15 08:53:20 +00:00
" impl " ,
bounds . skip_binders ( ) ,
2021-06-15 18:28:37 +00:00
SizedByDefault ::Sized { anchor : krate } ,
2021-06-15 08:53:20 +00:00
) ? ;
2020-09-10 12:01:23 +00:00
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
2020-03-04 22:00:44 +00:00
}
2023-02-07 21:42:03 +00:00
ImplTraitId ::AsyncBlockTypeImplTrait ( body , .. ) = > {
let future_trait = db
. lang_item ( body . module ( db . upcast ( ) ) . krate ( ) , LangItem ::Future )
. and_then ( LangItemTarget ::as_trait ) ;
let output = future_trait . and_then ( | t | {
db . trait_data ( t ) . associated_type_by_name ( & hir_expand ::name! ( Output ) )
} ) ;
write! ( f , " impl " ) ? ;
if let Some ( t ) = future_trait {
f . start_location_link ( t . into ( ) ) ;
}
write! ( f , " Future " ) ? ;
if let Some ( _ ) = future_trait {
f . end_location_link ( ) ;
}
write! ( f , " < " ) ? ;
if let Some ( t ) = output {
f . start_location_link ( t . into ( ) ) ;
}
write! ( f , " Output " ) ? ;
if let Some ( _ ) = output {
f . end_location_link ( ) ;
}
write! ( f , " = " ) ? ;
2021-12-19 16:58:39 +00:00
parameters . at ( Interner , 0 ) . hir_fmt ( f ) ? ;
2020-09-10 12:01:23 +00:00
write! ( f , " > " ) ? ;
}
}
2020-03-04 22:00:44 +00:00
}
2023-04-06 12:44:38 +00:00
TyKind ::Closure ( id , substs ) = > {
2023-04-07 13:45:04 +00:00
if f . display_target . is_source_code ( ) {
if ! f . display_target . 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 " ) ;
}
2023-04-06 12:44:38 +00:00
}
match f . closure_style {
ClosureStyle ::Hide = > return write! ( f , " {TYPE_HINT_TRUNCATION} " ) ,
ClosureStyle ::ClosureWithId = > {
return write! ( f , " {{closure#{:?}}} " , id . 0. as_u32 ( ) )
}
_ = > ( ) ,
2021-03-22 07:17:01 +00:00
}
2023-04-28 17:14:30 +00:00
let sig = ClosureSubst ( substs ) . sig_ty ( ) . callable_sig ( db ) ;
2020-03-27 17:56:18 +00:00
if let Some ( sig ) = sig {
2023-04-06 12:44:38 +00:00
let ( def , _ ) = db . lookup_intern_closure ( ( * id ) . into ( ) ) ;
let infer = db . infer ( def ) ;
let ( _ , kind ) = infer . closure_info ( id ) ;
match f . closure_style {
ClosureStyle ::ImplFn = > write! ( f , " impl {kind:?}( " ) ? ,
ClosureStyle ::RANotation = > write! ( f , " | " ) ? ,
_ = > unreachable! ( ) ,
}
2020-03-27 17:56:18 +00:00
if sig . params ( ) . is_empty ( ) {
2021-11-22 17:27:03 +00:00
} else if f . should_truncate ( ) {
2023-04-06 12:44:38 +00:00
write! ( f , " {TYPE_HINT_TRUNCATION} " ) ? ;
2020-03-27 17:56:18 +00:00
} else {
f . write_joined ( sig . params ( ) , " , " ) ? ;
} ;
2023-04-06 12:44:38 +00:00
match f . closure_style {
ClosureStyle ::ImplFn = > write! ( f , " ) " ) ? ,
ClosureStyle ::RANotation = > write! ( f , " | " ) ? ,
_ = > unreachable! ( ) ,
}
if f . closure_style = = ClosureStyle ::RANotation | | ! sig . ret ( ) . is_unit ( ) {
write! ( f , " -> " ) ? ;
sig . ret ( ) . hir_fmt ( f ) ? ;
}
2020-02-14 14:01:25 +00:00
} else {
2020-03-27 17:56:18 +00:00
write! ( f , " {{closure}} " ) ? ;
}
2020-02-14 14:01:25 +00:00
}
2021-03-13 18:47:34 +00:00
TyKind ::Placeholder ( idx ) = > {
2023-01-14 12:27:32 +00:00
let id = from_placeholder_idx ( db , * idx ) ;
let generics = generics ( db . upcast ( ) , id . parent ) ;
2022-03-09 18:50:24 +00:00
let param_data = & generics . params . type_or_consts [ id . local_id ] ;
2021-12-29 13:35:59 +00:00
match param_data {
TypeOrConstParamData ::TypeParamData ( p ) = > match p . provenance {
TypeParamProvenance ::TypeParamList | TypeParamProvenance ::TraitSelf = > {
write! ( f , " {} " , p . name . clone ( ) . unwrap_or_else ( Name ::missing ) ) ?
}
TypeParamProvenance ::ArgumentImplTrait = > {
2023-01-14 12:27:32 +00:00
let substs = generics . placeholder_subst ( db ) ;
let bounds = db
. generic_predicates ( id . parent )
. iter ( )
. map ( | pred | pred . clone ( ) . substitute ( Interner , & substs ) )
. filter ( | wc | match & wc . skip_binders ( ) {
WhereClause ::Implemented ( tr ) = > {
& tr . self_type_parameter ( Interner ) = = self
}
WhereClause ::AliasEq ( AliasEq {
alias : AliasTy ::Projection ( proj ) ,
ty : _ ,
} ) = > & proj . self_type_parameter ( db ) = = self ,
_ = > false ,
} )
. collect ::< Vec < _ > > ( ) ;
let krate = id . parent . module ( db . upcast ( ) ) . krate ( ) ;
2021-12-29 13:35:59 +00:00
write_bounds_like_dyn_trait_with_prefix (
2023-01-14 12:27:32 +00:00
f ,
2021-12-29 13:35:59 +00:00
" impl " ,
& bounds ,
SizedByDefault ::Sized { anchor : krate } ,
) ? ;
}
} ,
TypeOrConstParamData ::ConstParamData ( p ) = > {
write! ( f , " {} " , p . name ) ? ;
2020-02-14 14:01:25 +00:00
}
}
}
2021-04-06 09:45:41 +00:00
TyKind ::BoundVar ( idx ) = > idx . hir_fmt ( f ) ? ,
2021-03-21 12:22:22 +00:00
TyKind ::Dyn ( dyn_ty ) = > {
2022-10-10 10:32:24 +00:00
// Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation.
// FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it
// more efficient when either of them hits stable.
let mut bounds : SmallVec < [ _ ; 4 ] > =
dyn_ty . bounds . skip_binders ( ) . iter ( Interner ) . cloned ( ) . collect ( ) ;
let ( auto_traits , others ) : ( SmallVec < [ _ ; 4 ] > , _ ) =
bounds . drain ( 1 .. ) . partition ( | b | b . skip_binders ( ) . trait_id ( ) . is_some ( ) ) ;
bounds . extend ( others ) ;
bounds . extend ( auto_traits ) ;
2021-03-21 12:22:22 +00:00
write_bounds_like_dyn_trait_with_prefix (
2023-01-14 12:27:32 +00:00
f ,
2021-03-21 12:22:22 +00:00
" dyn " ,
2022-10-10 10:32:24 +00:00
& bounds ,
2021-06-15 08:53:20 +00:00
SizedByDefault ::NotSized ,
2021-03-21 12:22:22 +00:00
) ? ;
2020-02-14 14:01:25 +00:00
}
2021-03-13 13:44:51 +00:00
TyKind ::Alias ( AliasTy ::Projection ( p_ty ) ) = > p_ty . hir_fmt ( f ) ? ,
TyKind ::Alias ( AliasTy ::Opaque ( opaque_ty ) ) = > {
2023-04-07 13:45:04 +00:00
if ! f . display_target . allows_opaque ( ) {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::OpaqueType ,
) ) ;
}
2023-01-14 12:27:32 +00:00
let impl_trait_id = db . lookup_intern_impl_trait_id ( opaque_ty . opaque_ty_id . into ( ) ) ;
2021-03-13 19:05:47 +00:00
match impl_trait_id {
ImplTraitId ::ReturnTypeImplTrait ( func , idx ) = > {
2020-03-04 22:00:44 +00:00
let datas =
2023-01-14 12:27:32 +00:00
db . return_type_impl_traits ( func ) . expect ( " impl trait id without data " ) ;
2023-02-06 17:20:25 +00:00
let data =
( * datas ) . as_ref ( ) . map ( | rpit | rpit . impl_traits [ idx ] . bounds . clone ( ) ) ;
2021-12-19 16:58:39 +00:00
let bounds = data . substitute ( Interner , & opaque_ty . substitution ) ;
2023-01-14 12:27:32 +00:00
let krate = func . lookup ( db . upcast ( ) ) . module ( db . upcast ( ) ) . krate ( ) ;
2021-06-15 08:53:20 +00:00
write_bounds_like_dyn_trait_with_prefix (
2023-01-14 12:27:32 +00:00
f ,
2021-06-15 08:53:20 +00:00
" impl " ,
bounds . skip_binders ( ) ,
2021-06-15 18:28:37 +00:00
SizedByDefault ::Sized { anchor : krate } ,
2021-06-15 08:53:20 +00:00
) ? ;
2020-09-10 12:01:23 +00:00
}
2021-03-13 19:05:47 +00:00
ImplTraitId ::AsyncBlockTypeImplTrait ( .. ) = > {
2020-09-10 12:01:23 +00:00
write! ( f , " {{async block}} " ) ? ;
2020-03-04 22:00:44 +00:00
}
} ;
}
2021-04-05 12:37:11 +00:00
TyKind ::Error = > {
2020-12-12 17:18:19 +00:00
if f . display_target . is_source_code ( ) {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::UnknownType ,
) ) ;
}
write! ( f , " {{unknown}} " ) ? ;
}
2021-03-13 13:44:51 +00:00
TyKind ::InferenceVar ( .. ) = > write! ( f , " _ " ) ? ,
2022-09-21 13:04:55 +00:00
TyKind ::Generator ( _ , subst ) = > {
if f . display_target . is_source_code ( ) {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::Generator ,
) ) ;
}
let subst = subst . as_slice ( Interner ) ;
let a : Option < SmallVec < [ & Ty ; 3 ] > > = subst
. get ( subst . len ( ) - 3 .. )
. map ( | args | args . iter ( ) . map ( | arg | arg . ty ( Interner ) ) . collect ( ) )
. flatten ( ) ;
if let Some ( [ resume_ty , yield_ty , ret_ty ] ) = a . as_deref ( ) {
write! ( f , " | " ) ? ;
resume_ty . hir_fmt ( f ) ? ;
write! ( f , " | " ) ? ;
write! ( f , " yields " ) ? ;
yield_ty . hir_fmt ( f ) ? ;
write! ( f , " -> " ) ? ;
ret_ty . hir_fmt ( f ) ? ;
} else {
// This *should* be unreachable, but fallback just in case.
write! ( f , " {{generator}} " ) ? ;
}
}
2021-04-08 11:51:04 +00:00
TyKind ::GeneratorWitness ( .. ) = > write! ( f , " {{generator witness}} " ) ? ,
2020-02-14 14:01:25 +00:00
}
Ok ( ( ) )
}
}
2023-04-28 17:14:30 +00:00
fn hir_fmt_generics (
f : & mut HirFormatter < '_ > ,
parameters : & Substitution ,
generic_def : Option < hir_def ::GenericDefId > ,
) -> Result < ( ) , HirDisplayError > {
let db = f . db ;
if parameters . len ( Interner ) > 0 {
let parameters_to_write = if f . display_target . is_source_code ( ) | | f . omit_verbose_types ( ) {
match generic_def
. map ( | generic_def_id | db . generic_defaults ( generic_def_id ) )
. filter ( | defaults | ! defaults . is_empty ( ) )
{
None = > parameters . as_slice ( Interner ) ,
Some ( default_parameters ) = > {
fn should_show (
parameter : & GenericArg ,
default_parameters : & [ Binders < GenericArg > ] ,
i : usize ,
parameters : & Substitution ,
) -> bool {
if parameter . ty ( Interner ) . map ( | x | x . kind ( Interner ) ) = = Some ( & TyKind ::Error )
{
return true ;
}
if let Some ( ConstValue ::Concrete ( c ) ) =
parameter . constant ( Interner ) . map ( | x | & x . data ( Interner ) . value )
{
if c . interned = = ConstScalar ::Unknown {
return true ;
}
}
let default_parameter = match default_parameters . get ( i ) {
Some ( x ) = > x ,
None = > return true ,
} ;
let actual_default =
default_parameter . clone ( ) . substitute ( Interner , & parameters ) ;
parameter ! = & actual_default
}
let mut default_from = 0 ;
for ( i , parameter ) in parameters . iter ( Interner ) . enumerate ( ) {
if should_show ( parameter , & default_parameters , i , parameters ) {
default_from = i + 1 ;
}
}
& parameters . as_slice ( Interner ) [ 0 .. default_from ]
}
}
} else {
parameters . as_slice ( Interner )
} ;
if ! parameters_to_write . is_empty ( ) {
write! ( f , " < " ) ? ;
if f . display_target . is_source_code ( ) {
let mut first = true ;
for generic_arg in parameters_to_write {
if ! first {
write! ( f , " , " ) ? ;
}
first = false ;
if generic_arg . ty ( Interner ) . map ( | ty | ty . kind ( Interner ) ) = = Some ( & TyKind ::Error )
{
write! ( f , " _ " ) ? ;
} else {
generic_arg . hir_fmt ( f ) ? ;
}
}
} else {
f . write_joined ( parameters_to_write , " , " ) ? ;
}
write! ( f , " > " ) ? ;
}
}
Ok ( ( ) )
}
2021-02-28 21:12:07 +00:00
impl HirDisplay for CallableSig {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2020-12-09 17:06:56 +00:00
write! ( f , " fn( " ) ? ;
f . write_joined ( self . params ( ) , " , " ) ? ;
if self . is_varargs {
if self . params ( ) . is_empty ( ) {
write! ( f , " ... " ) ? ;
} else {
write! ( f , " , ... " ) ? ;
}
}
write! ( f , " ) " ) ? ;
let ret = self . ret ( ) ;
2021-04-03 18:22:59 +00:00
if ! ret . is_unit ( ) {
2021-04-06 12:16:07 +00:00
write! ( f , " -> " ) ? ;
ret . hir_fmt ( f ) ? ;
2020-12-09 17:06:56 +00:00
}
Ok ( ( ) )
}
}
2023-02-10 13:34:58 +00:00
fn fn_traits ( db : & dyn DefDatabase , trait_ : TraitId ) -> impl Iterator < Item = TraitId > + '_ {
2021-03-09 18:09:02 +00:00
let krate = trait_ . lookup ( db ) . container . krate ( ) ;
2021-06-29 15:35:37 +00:00
utils ::fn_traits ( db , krate )
2021-01-12 19:19:13 +00:00
}
2021-06-15 08:53:20 +00:00
#[ derive(Clone, Copy, PartialEq, Eq) ]
pub enum SizedByDefault {
NotSized ,
2021-06-15 18:28:37 +00:00
Sized { anchor : CrateId } ,
}
impl SizedByDefault {
fn is_sized_trait ( self , trait_ : TraitId , db : & dyn DefDatabase ) -> bool {
match self {
Self ::NotSized = > false ,
Self ::Sized { anchor } = > {
2021-12-10 19:01:24 +00:00
let sized_trait = db
2023-01-21 16:29:07 +00:00
. lang_item ( anchor , LangItem ::Sized )
2021-12-10 19:01:24 +00:00
. and_then ( | lang_item | lang_item . as_trait ( ) ) ;
2021-06-15 18:28:37 +00:00
Some ( trait_ ) = = sized_trait
}
}
}
2021-06-15 08:53:20 +00:00
}
2021-02-20 19:43:04 +00:00
pub fn write_bounds_like_dyn_trait_with_prefix (
2023-01-14 12:27:32 +00:00
f : & mut HirFormatter < '_ > ,
2021-02-20 19:43:04 +00:00
prefix : & str ,
2021-03-21 12:22:22 +00:00
predicates : & [ QuantifiedWhereClause ] ,
2021-06-15 08:53:20 +00:00
default_sized : SizedByDefault ,
2021-02-20 19:43:04 +00:00
) -> Result < ( ) , HirDisplayError > {
2022-12-23 18:42:58 +00:00
write! ( f , " {prefix} " ) ? ;
2021-06-15 18:28:37 +00:00
if ! predicates . is_empty ( )
| | predicates . is_empty ( ) & & matches! ( default_sized , SizedByDefault ::Sized { .. } )
{
2021-02-20 19:43:04 +00:00
write! ( f , " " ) ? ;
2023-01-14 12:27:32 +00:00
write_bounds_like_dyn_trait ( f , predicates , default_sized )
2021-02-20 19:43:04 +00:00
} else {
Ok ( ( ) )
}
}
fn write_bounds_like_dyn_trait (
2023-01-14 12:27:32 +00:00
f : & mut HirFormatter < '_ > ,
2021-03-21 12:22:22 +00:00
predicates : & [ QuantifiedWhereClause ] ,
2021-06-15 08:53:20 +00:00
default_sized : SizedByDefault ,
2020-04-25 14:57:59 +00:00
) -> Result < ( ) , HirDisplayError > {
2020-02-14 14:01:25 +00:00
// Note: This code is written to produce nice results (i.e.
// corresponding to surface Rust) for types that can occur in
// actual Rust. It will have weird results if the predicates
// aren't as expected (i.e. self types = $0, projection
// predicates for a certain trait come after the Implemented
// predicate for that trait).
let mut first = true ;
let mut angle_open = false ;
2021-01-12 19:19:13 +00:00
let mut is_fn_trait = false ;
2021-06-15 18:28:37 +00:00
let mut is_sized = false ;
2020-02-14 14:01:25 +00:00
for p in predicates . iter ( ) {
2021-03-21 12:22:22 +00:00
match p . skip_binders ( ) {
2021-03-20 09:46:36 +00:00
WhereClause ::Implemented ( trait_ref ) = > {
2021-03-18 20:53:19 +00:00
let trait_ = trait_ref . hir_trait_id ( ) ;
2021-06-15 18:28:37 +00:00
if default_sized . is_sized_trait ( trait_ , f . db . upcast ( ) ) {
is_sized = true ;
if matches! ( default_sized , SizedByDefault ::Sized { .. } ) {
2021-06-15 22:23:04 +00:00
// Don't print +Sized, but rather +?Sized if absent.
continue ;
2021-06-15 08:53:20 +00:00
}
2021-06-15 22:23:04 +00:00
}
2021-01-12 19:19:13 +00:00
if ! is_fn_trait {
is_fn_trait = fn_traits ( f . db . upcast ( ) , trait_ ) . any ( | it | it = = trait_ ) ;
}
if ! is_fn_trait & & angle_open {
2020-02-14 14:01:25 +00:00
write! ( f , " > " ) ? ;
2020-08-13 20:13:34 +00:00
angle_open = false ;
2020-02-14 14:01:25 +00:00
}
if ! first {
write! ( f , " + " ) ? ;
}
2021-04-08 11:51:04 +00:00
// We assume that the self type is ^0.0 (i.e. the
2020-02-14 14:01:25 +00:00
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
2023-01-14 12:27:32 +00:00
f . start_location_link ( trait_ . into ( ) ) ;
2021-01-12 19:19:13 +00:00
write! ( f , " {} " , f . db . trait_data ( trait_ ) . name ) ? ;
2023-01-14 12:27:32 +00:00
f . end_location_link ( ) ;
2021-12-19 16:58:39 +00:00
if let [ _ , params @ .. ] = & * trait_ref . substitution . as_slice ( Interner ) {
2021-01-12 19:19:13 +00:00
if is_fn_trait {
2021-04-01 19:04:02 +00:00
if let Some ( args ) =
2021-12-19 16:58:39 +00:00
params . first ( ) . and_then ( | it | it . assert_ty_ref ( Interner ) . as_tuple ( ) )
2021-04-01 19:04:02 +00:00
{
2021-01-12 19:19:13 +00:00
write! ( f , " ( " ) ? ;
2021-12-19 16:58:39 +00:00
f . write_joined ( args . as_slice ( Interner ) , " , " ) ? ;
2021-01-12 19:19:13 +00:00
write! ( f , " ) " ) ? ;
}
} else if ! params . is_empty ( ) {
write! ( f , " < " ) ? ;
f . write_joined ( params , " , " ) ? ;
// there might be assoc type bindings, so we leave the angle brackets open
angle_open = true ;
}
2020-02-14 14:01:25 +00:00
}
}
2021-03-20 09:46:36 +00:00
WhereClause ::AliasEq ( alias_eq ) if is_fn_trait = > {
2021-01-12 19:19:13 +00:00
is_fn_trait = false ;
2021-05-25 13:23:52 +00:00
if ! alias_eq . ty . is_unit ( ) {
write! ( f , " -> " ) ? ;
alias_eq . ty . hir_fmt ( f ) ? ;
}
2021-01-12 19:19:13 +00:00
}
2021-03-20 09:46:36 +00:00
WhereClause ::AliasEq ( AliasEq { ty , alias } ) = > {
2020-02-14 14:01:25 +00:00
// in types in actual Rust, these will always come
// after the corresponding Implemented predicate
if angle_open {
write! ( f , " , " ) ? ;
} else {
write! ( f , " < " ) ? ;
angle_open = true ;
}
2021-03-19 01:07:15 +00:00
if let AliasTy ::Projection ( proj ) = alias {
2022-10-27 08:05:22 +00:00
let assoc_ty_id = from_assoc_type_id ( proj . associated_ty_id ) ;
let type_alias = f . db . type_alias_data ( assoc_ty_id ) ;
2023-01-14 12:27:32 +00:00
f . start_location_link ( assoc_ty_id . into ( ) ) ;
2022-10-27 08:05:22 +00:00
write! ( f , " {} " , type_alias . name ) ? ;
2023-01-14 12:27:32 +00:00
f . end_location_link ( ) ;
2022-10-27 08:05:22 +00:00
let proj_arg_count = generics ( f . db . upcast ( ) , assoc_ty_id . into ( ) ) . len_self ( ) ;
if proj_arg_count > 0 {
write! ( f , " < " ) ? ;
f . write_joined (
& proj . substitution . as_slice ( Interner ) [ .. proj_arg_count ] ,
" , " ,
) ? ;
write! ( f , " > " ) ? ;
}
write! ( f , " = " ) ? ;
2021-03-19 01:07:15 +00:00
}
ty . hir_fmt ( f ) ? ;
2020-02-14 14:01:25 +00:00
}
2021-04-08 11:51:04 +00:00
// FIXME implement these
WhereClause ::LifetimeOutlives ( _ ) = > { }
WhereClause ::TypeOutlives ( _ ) = > { }
2020-02-14 14:01:25 +00:00
}
first = false ;
}
if angle_open {
write! ( f , " > " ) ? ;
}
2023-01-14 12:27:32 +00:00
if let SizedByDefault ::Sized { anchor } = default_sized {
let sized_trait =
2023-01-21 16:29:07 +00:00
f . db . lang_item ( anchor , LangItem ::Sized ) . and_then ( | lang_item | lang_item . as_trait ( ) ) ;
2021-06-15 18:28:37 +00:00
if ! is_sized {
2023-01-14 12:27:32 +00:00
if ! first {
write! ( f , " + " ) ? ;
}
if let Some ( sized_trait ) = sized_trait {
f . start_location_link ( sized_trait . into ( ) ) ;
}
write! ( f , " ?Sized " ) ? ;
2021-06-15 08:53:20 +00:00
} else if first {
2023-01-14 12:27:32 +00:00
if let Some ( sized_trait ) = sized_trait {
f . start_location_link ( sized_trait . into ( ) ) ;
}
2021-06-15 08:53:20 +00:00
write! ( f , " Sized " ) ? ;
}
2023-01-14 12:27:32 +00:00
if let Some ( _ ) = sized_trait {
f . end_location_link ( ) ;
}
2021-06-15 08:53:20 +00:00
}
2020-02-14 14:01:25 +00:00
Ok ( ( ) )
}
2022-07-20 13:06:15 +00:00
fn fmt_trait_ref (
f : & mut HirFormatter < '_ > ,
2023-01-14 12:27:32 +00:00
tr : & TraitRef ,
2022-07-20 13:06:15 +00:00
use_as : bool ,
) -> Result < ( ) , HirDisplayError > {
2021-04-07 18:26:27 +00:00
if f . should_truncate ( ) {
2022-12-23 18:42:58 +00:00
return write! ( f , " {TYPE_HINT_TRUNCATION} " ) ;
2021-04-07 18:26:27 +00:00
}
2020-02-14 14:01:25 +00:00
2021-12-19 16:58:39 +00:00
tr . self_type_parameter ( Interner ) . hir_fmt ( f ) ? ;
2021-04-07 18:26:27 +00:00
if use_as {
write! ( f , " as " ) ? ;
} else {
write! ( f , " : " ) ? ;
2020-02-14 14:01:25 +00:00
}
2023-01-14 12:27:32 +00:00
let trait_ = tr . hir_trait_id ( ) ;
f . start_location_link ( trait_ . into ( ) ) ;
write! ( f , " {} " , f . db . trait_data ( trait_ ) . name ) ? ;
f . end_location_link ( ) ;
2021-12-19 16:58:39 +00:00
if tr . substitution . len ( Interner ) > 1 {
2021-04-07 18:26:27 +00:00
write! ( f , " < " ) ? ;
2021-12-19 16:58:39 +00:00
f . write_joined ( & tr . substitution . as_slice ( Interner ) [ 1 .. ] , " , " ) ? ;
2021-04-07 18:26:27 +00:00
write! ( f , " > " ) ? ;
}
Ok ( ( ) )
2020-02-14 14:01:25 +00:00
}
impl HirDisplay for TraitRef {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2023-01-14 12:27:32 +00:00
fmt_trait_ref ( f , self , false )
2020-02-14 14:01:25 +00:00
}
}
2021-03-20 09:46:36 +00:00
impl HirDisplay for WhereClause {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2020-02-14 14:01:25 +00:00
if f . should_truncate ( ) {
2022-12-23 18:42:58 +00:00
return write! ( f , " {TYPE_HINT_TRUNCATION} " ) ;
2020-02-14 14:01:25 +00:00
}
match self {
2021-03-20 09:46:36 +00:00
WhereClause ::Implemented ( trait_ref ) = > trait_ref . hir_fmt ( f ) ? ,
WhereClause ::AliasEq ( AliasEq { alias : AliasTy ::Projection ( projection_ty ) , ty } ) = > {
2020-02-14 14:01:25 +00:00
write! ( f , " < " ) ? ;
2023-01-14 12:27:32 +00:00
fmt_trait_ref ( f , & projection_ty . trait_ref ( f . db ) , true ) ? ;
write! ( f , " >:: " , ) ? ;
let type_alias = from_assoc_type_id ( projection_ty . associated_ty_id ) ;
f . start_location_link ( type_alias . into ( ) ) ;
write! ( f , " {} " , f . db . type_alias_data ( type_alias ) . name , ) ? ;
f . end_location_link ( ) ;
write! ( f , " = " ) ? ;
2021-03-19 01:07:15 +00:00
ty . hir_fmt ( f ) ? ;
2020-02-14 14:01:25 +00:00
}
2021-03-20 09:51:00 +00:00
WhereClause ::AliasEq ( _ ) = > write! ( f , " {{error}} " ) ? ,
2021-04-08 11:51:04 +00:00
// FIXME implement these
WhereClause ::TypeOutlives ( .. ) = > { }
WhereClause ::LifetimeOutlives ( .. ) = > { }
2020-02-14 14:01:25 +00:00
}
Ok ( ( ) )
}
}
2021-04-05 18:46:15 +00:00
impl HirDisplay for LifetimeOutlives {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-04-05 18:46:15 +00:00
self . a . hir_fmt ( f ) ? ;
write! ( f , " : " ) ? ;
self . b . hir_fmt ( f )
}
}
2020-12-11 12:49:32 +00:00
impl HirDisplay for Lifetime {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-04-05 18:46:15 +00:00
self . interned ( ) . hir_fmt ( f )
}
}
impl HirDisplay for LifetimeData {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2020-12-11 12:49:32 +00:00
match self {
2021-04-06 09:45:41 +00:00
LifetimeData ::BoundVar ( idx ) = > idx . hir_fmt ( f ) ,
2021-04-05 18:46:15 +00:00
LifetimeData ::InferenceVar ( _ ) = > write! ( f , " _ " ) ,
LifetimeData ::Placeholder ( idx ) = > {
let id = lt_from_placeholder_idx ( f . db , * idx ) ;
2020-12-11 12:49:32 +00:00
let generics = generics ( f . db . upcast ( ) , id . parent ) ;
let param_data = & generics . params . lifetimes [ id . local_id ] ;
2021-04-05 18:46:15 +00:00
write! ( f , " {} " , param_data . name )
2020-12-11 12:49:32 +00:00
}
2021-04-05 18:46:15 +00:00
LifetimeData ::Static = > write! ( f , " 'static " ) ,
LifetimeData ::Erased = > Ok ( ( ) ) ,
LifetimeData ::Phantom ( _ , _ ) = > Ok ( ( ) ) ,
2020-12-11 12:49:32 +00:00
}
}
}
2021-03-20 10:23:59 +00:00
impl HirDisplay for DomainGoal {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2020-10-06 12:40:27 +00:00
match self {
2021-03-20 10:23:59 +00:00
DomainGoal ::Holds ( wc ) = > {
write! ( f , " Holds( " ) ? ;
wc . hir_fmt ( f ) ? ;
2021-04-08 11:51:04 +00:00
write! ( f , " ) " ) ? ;
2020-10-28 16:58:16 +00:00
}
2021-04-08 11:51:04 +00:00
_ = > write! ( f , " ? " ) ? ,
2020-10-06 12:40:27 +00:00
}
2021-04-08 11:51:04 +00:00
Ok ( ( ) )
2020-02-14 14:01:25 +00:00
}
}
2021-03-14 12:03:39 +00:00
pub fn write_visibility (
module_id : ModuleId ,
vis : Visibility ,
2022-07-20 13:02:08 +00:00
f : & mut HirFormatter < '_ > ,
2021-03-14 12:03:39 +00:00
) -> Result < ( ) , HirDisplayError > {
match vis {
Visibility ::Public = > write! ( f , " pub " ) ,
Visibility ::Module ( vis_id ) = > {
let def_map = module_id . def_map ( f . db . upcast ( ) ) ;
let root_module_id = def_map . module_id ( def_map . root ( ) ) ;
if vis_id = = module_id {
// pub(self) or omitted
Ok ( ( ) )
} else if root_module_id = = vis_id {
write! ( f , " pub(crate) " )
} else if module_id . containing_module ( f . db . upcast ( ) ) = = Some ( vis_id ) {
write! ( f , " pub(super) " )
} else {
write! ( f , " pub(in ...) " )
}
}
}
}
impl HirDisplay for TypeRef {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-03-14 12:03:39 +00:00
match self {
TypeRef ::Never = > write! ( f , " ! " ) ? ,
TypeRef ::Placeholder = > write! ( f , " _ " ) ? ,
TypeRef ::Tuple ( elems ) = > {
write! ( f , " ( " ) ? ;
f . write_joined ( elems , " , " ) ? ;
if elems . len ( ) = = 1 {
write! ( f , " , " ) ? ;
}
write! ( f , " ) " ) ? ;
}
TypeRef ::Path ( path ) = > path . hir_fmt ( f ) ? ,
TypeRef ::RawPtr ( inner , mutability ) = > {
let mutability = match mutability {
hir_def ::type_ref ::Mutability ::Shared = > " *const " ,
hir_def ::type_ref ::Mutability ::Mut = > " *mut " ,
} ;
2022-12-23 18:42:58 +00:00
write! ( f , " {mutability} " ) ? ;
2021-03-14 12:03:39 +00:00
inner . hir_fmt ( f ) ? ;
}
TypeRef ::Reference ( inner , lifetime , mutability ) = > {
let mutability = match mutability {
hir_def ::type_ref ::Mutability ::Shared = > " " ,
hir_def ::type_ref ::Mutability ::Mut = > " mut " ,
} ;
write! ( f , " & " ) ? ;
if let Some ( lifetime ) = lifetime {
write! ( f , " {} " , lifetime . name ) ? ;
}
2022-12-23 18:42:58 +00:00
write! ( f , " {mutability} " ) ? ;
2021-03-14 12:03:39 +00:00
inner . hir_fmt ( f ) ? ;
}
2021-05-12 11:39:48 +00:00
TypeRef ::Array ( inner , len ) = > {
2021-03-14 12:03:39 +00:00
write! ( f , " [ " ) ? ;
inner . hir_fmt ( f ) ? ;
2022-12-23 18:42:58 +00:00
write! ( f , " ; {len}] " ) ? ;
2021-03-14 12:03:39 +00:00
}
TypeRef ::Slice ( inner ) = > {
write! ( f , " [ " ) ? ;
inner . hir_fmt ( f ) ? ;
write! ( f , " ] " ) ? ;
}
2022-11-04 20:07:15 +00:00
& TypeRef ::Fn ( ref parameters , is_varargs , is_unsafe ) = > {
2022-02-18 09:12:52 +00:00
// FIXME: Function pointer qualifiers.
2022-11-04 20:07:15 +00:00
if is_unsafe {
write! ( f , " unsafe " ) ? ;
}
2021-03-14 12:03:39 +00:00
write! ( f , " fn( " ) ? ;
2022-02-21 10:29:38 +00:00
if let Some ( ( ( _ , return_type ) , function_parameters ) ) = parameters . split_last ( ) {
for index in 0 .. function_parameters . len ( ) {
let ( param_name , param_type ) = & function_parameters [ index ] ;
if let Some ( name ) = param_name {
2022-12-23 18:42:58 +00:00
write! ( f , " {name}: " ) ? ;
2022-02-21 10:29:38 +00:00
}
2022-02-15 19:27:56 +00:00
2022-02-21 10:29:38 +00:00
param_type . hir_fmt ( f ) ? ;
2022-02-15 14:39:22 +00:00
2022-02-21 10:29:38 +00:00
if index ! = function_parameters . len ( ) - 1 {
write! ( f , " , " ) ? ;
}
2022-02-15 14:39:22 +00:00
}
2022-11-04 20:07:15 +00:00
if is_varargs {
2022-02-21 10:29:38 +00:00
write! ( f , " {}... " , if parameters . len ( ) = = 1 { " " } else { " , " } ) ? ;
}
write! ( f , " ) " ) ? ;
match & return_type {
2022-02-15 14:58:06 +00:00
TypeRef ::Tuple ( tup ) if tup . is_empty ( ) = > { }
_ = > {
write! ( f , " -> " ) ? ;
2022-02-21 10:29:38 +00:00
return_type . hir_fmt ( f ) ? ;
2022-02-15 14:58:06 +00:00
}
2021-03-14 12:03:39 +00:00
}
}
}
TypeRef ::ImplTrait ( bounds ) = > {
write! ( f , " impl " ) ? ;
f . write_joined ( bounds , " + " ) ? ;
}
TypeRef ::DynTrait ( bounds ) = > {
write! ( f , " dyn " ) ? ;
f . write_joined ( bounds , " + " ) ? ;
}
2021-04-12 14:24:48 +00:00
TypeRef ::Macro ( macro_call ) = > {
let macro_call = macro_call . to_node ( f . db . upcast ( ) ) ;
2023-04-17 15:31:39 +00:00
let ctx = hir_def ::lower ::LowerCtx ::with_hygiene (
f . db . upcast ( ) ,
& Hygiene ::new_unhygienic ( ) ,
) ;
2021-04-12 14:24:48 +00:00
match macro_call . path ( ) {
2021-05-06 21:23:50 +00:00
Some ( path ) = > match Path ::from_src ( path , & ctx ) {
2021-04-12 14:24:48 +00:00
Some ( path ) = > path . hir_fmt ( f ) ? ,
None = > write! ( f , " {{macro}} " ) ? ,
} ,
None = > write! ( f , " {{macro}} " ) ? ,
}
write! ( f , " !(..) " ) ? ;
}
TypeRef ::Error = > write! ( f , " {{error}} " ) ? ,
2021-03-14 12:03:39 +00:00
}
Ok ( ( ) )
}
}
impl HirDisplay for TypeBound {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-03-14 12:03:39 +00:00
match self {
2021-06-06 18:41:15 +00:00
TypeBound ::Path ( path , modifier ) = > {
match modifier {
TraitBoundModifier ::None = > ( ) ,
TraitBoundModifier ::Maybe = > write! ( f , " ? " ) ? ,
}
path . hir_fmt ( f )
}
2021-03-14 12:03:39 +00:00
TypeBound ::Lifetime ( lifetime ) = > write! ( f , " {} " , lifetime . name ) ,
2021-06-29 23:34:51 +00:00
TypeBound ::ForLifetime ( lifetimes , path ) = > {
write! ( f , " for<{}> " , lifetimes . iter ( ) . format ( " , " ) ) ? ;
path . hir_fmt ( f )
}
2021-03-14 12:03:39 +00:00
TypeBound ::Error = > write! ( f , " {{error}} " ) ,
}
}
}
impl HirDisplay for Path {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-03-14 12:03:39 +00:00
match ( self . type_anchor ( ) , self . kind ( ) ) {
( Some ( anchor ) , _ ) = > {
write! ( f , " < " ) ? ;
anchor . hir_fmt ( f ) ? ;
write! ( f , " > " ) ? ;
}
( _ , PathKind ::Plain ) = > { }
2021-09-07 09:49:46 +00:00
( _ , PathKind ::Abs ) = > { }
2021-03-14 12:03:39 +00:00
( _ , PathKind ::Crate ) = > write! ( f , " crate " ) ? ,
( _ , PathKind ::Super ( 0 ) ) = > write! ( f , " self " ) ? ,
( _ , PathKind ::Super ( n ) ) = > {
2021-09-07 09:49:46 +00:00
for i in 0 .. * n {
if i > 0 {
write! ( f , " :: " ) ? ;
}
write! ( f , " super " ) ? ;
2021-03-14 12:03:39 +00:00
}
}
2022-02-25 17:38:51 +00:00
( _ , PathKind ::DollarCrate ( id ) ) = > {
// Resolve `$crate` to the crate's display name.
// FIXME: should use the dependency name instead if available, but that depends on
// the crate invoking `HirDisplay`
let crate_graph = f . db . crate_graph ( ) ;
let name = crate_graph [ * id ]
. display_name
. as_ref ( )
. map ( | name | name . canonical_name ( ) )
. unwrap_or ( " $crate " ) ;
write! ( f , " {name} " ) ?
}
2021-03-14 12:03:39 +00:00
}
for ( seg_idx , segment ) in self . segments ( ) . iter ( ) . enumerate ( ) {
2021-09-07 08:54:02 +00:00
if ! matches! ( self . kind ( ) , PathKind ::Plain ) | | seg_idx > 0 {
2021-03-14 12:03:39 +00:00
write! ( f , " :: " ) ? ;
}
write! ( f , " {} " , segment . name ) ? ;
if let Some ( generic_args ) = segment . args_and_bindings {
// We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
// Do we actually format expressions?
2021-11-19 18:58:00 +00:00
if generic_args . desugared_from_fn {
// First argument will be a tuple, which already includes the parentheses.
2021-11-21 00:39:22 +00:00
// If the tuple only contains 1 item, write it manually to avoid the trailing `,`.
if let hir_def ::path ::GenericArg ::Type ( TypeRef ::Tuple ( v ) ) =
& generic_args . args [ 0 ]
{
if v . len ( ) = = 1 {
write! ( f , " ( " ) ? ;
v [ 0 ] . hir_fmt ( f ) ? ;
write! ( f , " ) " ) ? ;
} else {
generic_args . args [ 0 ] . hir_fmt ( f ) ? ;
}
}
2021-11-19 18:58:00 +00:00
if let Some ( ret ) = & generic_args . bindings [ 0 ] . type_ref {
2021-11-21 00:39:22 +00:00
if ! matches! ( ret , TypeRef ::Tuple ( v ) if v . is_empty ( ) ) {
write! ( f , " -> " ) ? ;
ret . hir_fmt ( f ) ? ;
}
2021-11-19 18:58:00 +00:00
}
return Ok ( ( ) ) ;
}
2021-03-14 12:03:39 +00:00
write! ( f , " < " ) ? ;
let mut first = true ;
2023-02-14 16:37:20 +00:00
for arg in generic_args . args . iter ( ) {
2021-03-14 12:03:39 +00:00
if first {
first = false ;
if generic_args . has_self_type {
// FIXME: Convert to `<Ty as Trait>` form.
write! ( f , " Self = " ) ? ;
}
} else {
write! ( f , " , " ) ? ;
}
arg . hir_fmt ( f ) ? ;
}
2023-02-14 16:24:40 +00:00
for binding in generic_args . bindings . iter ( ) {
2021-03-14 12:03:39 +00:00
if first {
first = false ;
} else {
write! ( f , " , " ) ? ;
}
write! ( f , " {} " , binding . name ) ? ;
match & binding . type_ref {
Some ( ty ) = > {
write! ( f , " = " ) ? ;
ty . hir_fmt ( f ) ?
}
None = > {
write! ( f , " : " ) ? ;
2023-02-14 16:18:46 +00:00
f . write_joined ( binding . bounds . iter ( ) , " + " ) ? ;
2021-03-14 12:03:39 +00:00
}
}
}
write! ( f , " > " ) ? ;
}
}
Ok ( ( ) )
}
}
2021-04-01 19:04:02 +00:00
impl HirDisplay for hir_def ::path ::GenericArg {
2022-07-20 13:02:08 +00:00
fn hir_fmt ( & self , f : & mut HirFormatter < '_ > ) -> Result < ( ) , HirDisplayError > {
2021-03-14 12:03:39 +00:00
match self {
2021-04-01 19:04:02 +00:00
hir_def ::path ::GenericArg ::Type ( ty ) = > ty . hir_fmt ( f ) ,
2022-12-23 18:42:58 +00:00
hir_def ::path ::GenericArg ::Const ( c ) = > write! ( f , " {c} " ) ,
2021-04-01 19:04:02 +00:00
hir_def ::path ::GenericArg ::Lifetime ( lifetime ) = > write! ( f , " {} " , lifetime . name ) ,
2021-03-14 12:03:39 +00:00
}
}
}