2019-09-30 03:58:53 -05:00
//! FIXME: write short doc here
2019-03-14 16:03:39 -05:00
use std ::fmt ;
2020-02-14 08:01:25 -06:00
use crate ::{
2020-07-16 06:15:00 -05:00
db ::HirDatabase , utils ::generics , ApplicationTy , CallableDefId , FnSig , GenericPredicate ,
2020-06-05 10:41:58 -05:00
Obligation , OpaqueTyId , ProjectionTy , Substs , TraitRef , Ty , TypeCtor ,
2020-02-14 08:01:25 -06:00
} ;
2020-04-25 09:57:59 -05:00
use hir_def ::{
find_path , generics ::TypeParamProvenance , item_scope ::ItemInNs , AdtId , AssocContainerId ,
Lookup , ModuleId ,
} ;
2020-02-14 08:01:25 -06:00
use hir_expand ::name ::Name ;
2019-03-14 16:03:39 -05:00
2020-04-25 09:57:59 -05:00
pub struct HirFormatter < ' a > {
2020-03-13 10:05:46 -05:00
pub db : & ' a dyn HirDatabase ,
2020-04-25 09:57:59 -05:00
fmt : & ' a mut dyn fmt ::Write ,
2019-11-18 11:02:28 -06:00
buf : String ,
curr_size : usize ,
2020-01-22 08:44:05 -06:00
pub ( crate ) max_size : Option < usize > ,
2019-12-23 09:53:35 -06:00
omit_verbose_types : bool ,
2020-04-25 09:57:59 -05:00
display_target : DisplayTarget ,
2019-03-14 16:03:39 -05:00
}
pub trait HirDisplay {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > ;
2019-11-18 11:02:28 -06:00
2020-04-25 09:57:59 -05:00
/// Returns a `Display`able type that is human-readable.
/// Use this for showing types to the user (e.g. diagnostics)
2020-03-13 10:05:46 -05:00
fn display < ' a > ( & ' a self , db : & ' a dyn HirDatabase ) -> HirDisplayWrapper < ' a , Self >
2019-03-14 16:03:39 -05:00
where
Self : Sized ,
{
2020-04-25 09:57:59 -05:00
HirDisplayWrapper {
db ,
t : self ,
max_size : None ,
omit_verbose_types : false ,
display_target : DisplayTarget ::Diagnostics ,
}
2019-11-18 11:02:28 -06:00
}
2020-04-25 09:57:59 -05: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 10:05:46 -05:00
fn display_truncated < ' a > (
2019-11-18 11:02:28 -06:00
& ' a self ,
2020-03-13 10:05:46 -05:00
db : & ' a dyn HirDatabase ,
2019-12-19 08:43:41 -06:00
max_size : Option < usize > ,
2020-03-13 10:05:46 -05:00
) -> HirDisplayWrapper < ' a , Self >
2019-11-18 11:02:28 -06:00
where
Self : Sized ,
{
2020-04-25 09:57:59 -05:00
HirDisplayWrapper {
db ,
t : self ,
max_size ,
omit_verbose_types : true ,
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 ,
) -> 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 ,
2020-10-28 05:20:05 -05:00
#[ cfg(not(test)) ]
2020-04-25 09:57:59 -05:00
display_target : DisplayTarget ::SourceCode { module_id } ,
2020-10-28 05:20:05 -05:00
#[ cfg(test) ]
display_target : DisplayTarget ::Test { module_id } ,
2020-04-25 09:57:59 -05:00
} ) {
Ok ( ( ) ) = > { }
Err ( HirDisplayError ::FmtError ) = > panic! ( " Writing to String can't fail! " ) ,
Err ( HirDisplayError ::DisplaySourceCodeError ( e ) ) = > return Err ( e ) ,
} ;
Ok ( result )
2019-03-14 16:03:39 -05:00
}
}
2020-04-25 09:57:59 -05:00
impl < ' a > HirFormatter < ' a > {
2019-03-14 16:03:39 -05:00
pub fn write_joined < T : HirDisplay > (
& mut self ,
iter : impl IntoIterator < Item = T > ,
sep : & str ,
2020-04-25 09:57:59 -05:00
) -> Result < ( ) , HirDisplayError > {
2019-03-14 16:03:39 -05:00
let mut first = true ;
for e in iter {
if ! first {
write! ( self , " {} " , sep ) ? ;
}
first = false ;
e . hir_fmt ( self ) ? ;
}
Ok ( ( ) )
}
/// This allows using the `write!` macro directly with a `HirFormatter`.
2020-04-25 09:57:59 -05:00
pub fn write_fmt ( & mut self , args : fmt ::Arguments ) -> Result < ( ) , HirDisplayError > {
2019-11-18 11:02:28 -06: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 09:57:59 -05:00
self . fmt . write_str ( & self . buf ) . map_err ( HirDisplayError ::from )
2019-11-18 11:02:28 -06:00
}
pub fn should_truncate ( & self ) -> bool {
2019-12-19 08:43:41 -06:00
if let Some ( max_size ) = self . max_size {
2019-11-18 11:02:28 -06:00
self . curr_size > = max_size
} else {
false
}
2019-03-14 16:03:39 -05:00
}
2019-12-07 16:54:18 -06:00
2019-12-23 09:53:35 -06:00
pub fn omit_verbose_types ( & self ) -> bool {
self . omit_verbose_types
2019-12-07 16:54:18 -06:00
}
}
2020-04-25 09:57:59 -05:00
#[ derive(Clone, Copy) ]
enum DisplayTarget {
/// 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.
SourceCode { module_id : ModuleId } ,
2020-10-28 05:20:05 -05:00
/// Only for test purpose to keep real types
#[ cfg(test) ]
Test { module_id : ModuleId } ,
2020-04-25 09:57:59 -05:00
}
2020-05-10 11:09:22 -05:00
impl DisplayTarget {
fn is_source_code ( & self ) -> bool {
matches! ( self , Self ::SourceCode { .. } )
}
2020-10-28 05:20:05 -05:00
fn is_test ( & self ) -> bool {
#[ cfg(test) ]
{
matches! ( self , Self ::Test { .. } )
}
#[ cfg(not(test)) ]
{
false
}
}
2020-05-10 11:09:22 -05:00
}
2020-04-25 09:57:59 -05:00
#[ derive(Debug) ]
pub enum DisplaySourceCodeError {
PathNotFound ,
}
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 ,
display_target : DisplayTarget ,
}
2019-03-14 16:03:39 -05:00
2020-03-13 10:05:46 -05:00
impl < ' a , T > fmt ::Display for HirDisplayWrapper < ' a , T >
2019-03-14 16:03:39 -05:00
where
T : HirDisplay ,
{
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
2020-04-25 09:57:59 -05:00
match self . t . hir_fmt ( & mut HirFormatter {
db : self . db ,
2019-11-18 11:02:28 -06:00
fmt : f ,
buf : String ::with_capacity ( 20 ) ,
curr_size : 0 ,
2020-04-25 09:57:59 -05:00
max_size : self . max_size ,
omit_verbose_types : self . omit_verbose_types ,
display_target : self . display_target ,
} ) {
Ok ( ( ) ) = > Ok ( ( ) ) ,
Err ( HirDisplayError ::FmtError ) = > Err ( fmt ::Error ) ,
Err ( HirDisplayError ::DisplaySourceCodeError ( _ ) ) = > {
// This should never happen
panic! ( " HirDisplay failed when calling Display::fmt! " )
}
}
2019-03-14 16:03:39 -05:00
}
}
2020-02-14 08:01:25 -06:00
const TYPE_HINT_TRUNCATION : & str = " … " ;
impl HirDisplay for & Ty {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
HirDisplay ::hir_fmt ( * self , f )
}
}
impl HirDisplay for ApplicationTy {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
match self . ctor {
TypeCtor ::Bool = > write! ( f , " bool " ) ? ,
TypeCtor ::Char = > write! ( f , " char " ) ? ,
TypeCtor ::Int ( t ) = > write! ( f , " {} " , t ) ? ,
TypeCtor ::Float ( t ) = > write! ( f , " {} " , t ) ? ,
TypeCtor ::Str = > write! ( f , " str " ) ? ,
TypeCtor ::Slice = > {
let t = self . parameters . as_single ( ) ;
write! ( f , " [{}] " , t . display ( f . db ) ) ? ;
}
TypeCtor ::Array = > {
let t = self . parameters . as_single ( ) ;
write! ( f , " [{}; _] " , t . display ( f . db ) ) ? ;
}
TypeCtor ::RawPtr ( m ) = > {
let t = self . parameters . as_single ( ) ;
2020-10-06 07:40:27 -05:00
let ty_display = t . display ( f . db ) ;
write! ( f , " *{} " , m . as_keyword_for_ptr ( ) ) ? ;
if matches! ( t , Ty ::Dyn ( predicates ) if predicates . len ( ) > 1 ) {
write! ( f , " ( " ) ? ;
write! ( f , " {} " , ty_display ) ? ;
write! ( f , " ) " ) ? ;
} else {
write! ( f , " {} " , ty_display ) ? ;
}
2020-02-14 08:01:25 -06:00
}
TypeCtor ::Ref ( m ) = > {
let t = self . parameters . as_single ( ) ;
let ty_display = if f . omit_verbose_types ( ) {
t . display_truncated ( f . db , f . max_size )
} else {
t . display ( f . db )
} ;
2020-10-06 07:40:27 -05:00
write! ( f , " &{} " , m . as_keyword_for_ref ( ) ) ? ;
if matches! ( t , Ty ::Dyn ( predicates ) if predicates . len ( ) > 1 ) {
write! ( f , " ( " ) ? ;
write! ( f , " {} " , ty_display ) ? ;
write! ( f , " ) " ) ? ;
} else {
write! ( f , " {} " , ty_display ) ? ;
}
2020-02-14 08:01:25 -06:00
}
TypeCtor ::Never = > write! ( f , " ! " ) ? ,
TypeCtor ::Tuple { .. } = > {
let ts = & self . parameters ;
if ts . len ( ) = = 1 {
write! ( f , " ({},) " , ts [ 0 ] . display ( f . db ) ) ? ;
} else {
write! ( f , " ( " ) ? ;
f . write_joined ( & * ts . 0 , " , " ) ? ;
write! ( f , " ) " ) ? ;
}
}
2020-07-14 11:23:45 -05:00
TypeCtor ::FnPtr { is_varargs , .. } = > {
let sig = FnSig ::from_fn_ptr_substs ( & self . parameters , is_varargs ) ;
2020-02-14 08:01:25 -06:00
write! ( f , " fn( " ) ? ;
f . write_joined ( sig . params ( ) , " , " ) ? ;
2020-07-14 11:23:45 -05:00
if is_varargs {
if sig . params ( ) . is_empty ( ) {
write! ( f , " ... " ) ? ;
} else {
write! ( f , " , ... " ) ? ;
}
}
2020-04-05 10:25:47 -05:00
write! ( f , " ) " ) ? ;
let ret = sig . ret ( ) ;
if * ret ! = Ty ::unit ( ) {
2020-07-20 15:50:41 -05:00
let ret_display = if f . omit_verbose_types ( ) {
ret . display_truncated ( f . db , f . max_size )
} else {
ret . display ( f . db )
} ;
write! ( f , " -> {} " , ret_display ) ? ;
2020-04-05 10:25:47 -05:00
}
2020-02-14 08:01:25 -06:00
}
TypeCtor ::FnDef ( def ) = > {
let sig = f . db . callable_item_signature ( def ) . subst ( & self . parameters ) ;
2020-03-28 16:25:29 -05:00
match def {
2020-07-16 06:15:00 -05:00
CallableDefId ::FunctionId ( ff ) = > {
write! ( f , " fn {} " , f . db . function_data ( ff ) . name ) ?
}
CallableDefId ::StructId ( s ) = > write! ( f , " {} " , f . db . struct_data ( s ) . name ) ? ,
CallableDefId ::EnumVariantId ( e ) = > {
2020-03-28 16:25:29 -05:00
write! ( f , " {} " , f . db . enum_data ( e . parent ) . variants [ e . local_id ] . name ) ?
2020-02-14 08:01:25 -06:00
}
} ;
if self . parameters . len ( ) > 0 {
2020-03-13 10:05:46 -05:00
let generics = generics ( f . db . upcast ( ) , def . into ( ) ) ;
2020-02-14 08:01:25 -06:00
let ( parent_params , self_param , type_params , _impl_trait_params ) =
generics . provenance_split ( ) ;
let total_len = parent_params + self_param + type_params ;
// We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
if total_len > 0 {
write! ( f , " < " ) ? ;
f . write_joined ( & self . parameters . 0 [ .. total_len ] , " , " ) ? ;
write! ( f , " > " ) ? ;
}
}
write! ( f , " ( " ) ? ;
f . write_joined ( sig . params ( ) , " , " ) ? ;
2020-04-05 10:25:47 -05:00
write! ( f , " ) " ) ? ;
let ret = sig . ret ( ) ;
if * ret ! = Ty ::unit ( ) {
2020-07-20 15:50:41 -05:00
let ret_display = if f . omit_verbose_types ( ) {
ret . display_truncated ( f . db , f . max_size )
} else {
ret . display ( f . db )
} ;
write! ( f , " -> {} " , ret_display ) ? ;
2020-04-05 10:25:47 -05:00
}
2020-02-14 08:01:25 -06:00
}
TypeCtor ::Adt ( def_id ) = > {
2020-04-25 09:57:59 -05:00
match f . display_target {
DisplayTarget ::Diagnostics = > {
let name = match def_id {
AdtId ::StructId ( it ) = > f . db . struct_data ( it ) . name . clone ( ) ,
AdtId ::UnionId ( it ) = > f . db . union_data ( it ) . name . clone ( ) ,
AdtId ::EnumId ( it ) = > f . db . enum_data ( it ) . name . clone ( ) ,
} ;
write! ( f , " {} " , name ) ? ;
}
DisplayTarget ::SourceCode { module_id } = > {
if let Some ( path ) = find_path ::find_path (
f . db . upcast ( ) ,
ItemInNs ::Types ( def_id . into ( ) ) ,
module_id ,
) {
write! ( f , " {} " , path ) ? ;
} else {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::PathNotFound ,
) ) ;
}
}
2020-10-28 05:20:05 -05:00
#[ cfg(test) ]
DisplayTarget ::Test { module_id } = > {
if let Some ( path ) = find_path ::find_path (
f . db . upcast ( ) ,
ItemInNs ::Types ( def_id . into ( ) ) ,
module_id ,
) {
write! ( f , " {} " , path ) ? ;
} else {
return Err ( HirDisplayError ::DisplaySourceCodeError (
DisplaySourceCodeError ::PathNotFound ,
) ) ;
}
}
2020-04-25 09:57:59 -05:00
}
2020-02-14 08:01:25 -06:00
if self . parameters . len ( ) > 0 {
2020-10-28 05:20:05 -05:00
let parameters_to_write = if f . display_target . is_source_code ( )
| | f . display_target . is_test ( )
| | f . omit_verbose_types ( )
{
match self
. ctor
. as_generic_def ( )
. map ( | generic_def_id | f . db . generic_defaults ( generic_def_id ) )
. filter ( | defaults | ! defaults . is_empty ( ) )
{
None = > self . parameters . 0. as_ref ( ) ,
Some ( default_parameters ) = > {
let mut default_from = 0 ;
for ( i , parameter ) in self . parameters . iter ( ) . enumerate ( ) {
match ( parameter , default_parameters . get ( i ) ) {
( & Ty ::Unknown , _ ) | ( _ , None ) = > {
default_from = i + 1 ;
}
( _ , Some ( default_parameter ) ) = > {
let actual_default = default_parameter
. clone ( )
. subst ( & self . parameters . prefix ( i ) ) ;
if parameter ! = & actual_default {
2020-06-26 09:36:59 -05:00
default_from = i + 1 ;
2020-05-10 11:09:22 -05:00
}
2020-02-14 08:01:25 -06:00
}
}
}
2020-10-28 05:20:05 -05:00
& self . parameters . 0 [ 0 .. default_from ]
2020-02-14 08:01:25 -06:00
}
2020-10-28 05:20:05 -05:00
}
} else {
self . parameters . 0. as_ref ( )
} ;
2020-05-10 11:09:22 -05:00
if ! parameters_to_write . is_empty ( ) {
write! ( f , " < " ) ? ;
f . write_joined ( parameters_to_write , " , " ) ? ;
write! ( f , " > " ) ? ;
}
2020-02-14 08:01:25 -06:00
}
}
TypeCtor ::AssociatedType ( type_alias ) = > {
2020-03-13 10:05:46 -05:00
let trait_ = match type_alias . lookup ( f . db . upcast ( ) ) . container {
2020-02-14 08:01:25 -06:00
AssocContainerId ::TraitId ( it ) = > it ,
_ = > panic! ( " not an associated type " ) ,
} ;
2020-03-31 11:00:23 -05:00
let trait_ = f . db . trait_data ( trait_ ) ;
let type_alias = f . db . type_alias_data ( type_alias ) ;
2020-10-27 14:23:09 -05:00
2020-10-28 05:20:05 -05:00
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f . display_target . is_test ( ) | | self . parameters . len ( ) > 1 {
2020-10-27 14:23:09 -05:00
write! ( f , " {}::{} " , trait_ . name , type_alias . name ) ? ;
if self . parameters . len ( ) > 0 {
write! ( f , " < " ) ? ;
f . write_joined ( & * self . parameters . 0 , " , " ) ? ;
write! ( f , " > " ) ? ;
}
} else {
if self . parameters . len ( ) = = 1 {
write! (
f ,
" <{} as {}>::{} " ,
self . parameters . as_single ( ) . display ( f . db ) ,
trait_ . name ,
type_alias . name
) ? ;
} else {
write! ( f , " {}::{} " , trait_ . name , type_alias . name ) ? ;
}
2020-02-14 08:01:25 -06:00
}
}
2020-09-12 21:24:19 -05:00
TypeCtor ::ForeignType ( type_alias ) = > {
let type_alias = f . db . type_alias_data ( type_alias ) ;
write! ( f , " {} " , type_alias . name ) ? ;
if self . parameters . len ( ) > 0 {
write! ( f , " < " ) ? ;
f . write_joined ( & * self . parameters . 0 , " , " ) ? ;
write! ( f , " > " ) ? ;
}
}
2020-03-04 16:00:44 -06:00
TypeCtor ::OpaqueType ( opaque_ty_id ) = > {
2020-09-10 07:01:23 -05:00
match opaque_ty_id {
2020-06-05 10:41:58 -05:00
OpaqueTyId ::ReturnTypeImplTrait ( func , idx ) = > {
2020-03-04 16:00:44 -06:00
let datas =
f . db . return_type_impl_traits ( func ) . expect ( " impl trait id without data " ) ;
let data = ( * datas )
. as_ref ( )
. map ( | rpit | rpit . impl_traits [ idx as usize ] . bounds . clone ( ) ) ;
2020-09-10 07:01:23 -05:00
let bounds = data . subst ( & self . parameters ) ;
write! ( f , " impl " ) ? ;
write_bounds_like_dyn_trait ( & bounds . value , f ) ? ;
// FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
2020-03-04 16:00:44 -06:00
}
2020-09-10 07:01:23 -05:00
OpaqueTyId ::AsyncBlockTypeImplTrait ( .. ) = > {
write! ( f , " impl Future<Output = " ) ? ;
self . parameters [ 0 ] . hir_fmt ( f ) ? ;
write! ( f , " > " ) ? ;
}
}
2020-03-04 16:00:44 -06:00
}
2020-02-14 08:01:25 -06:00
TypeCtor ::Closure { .. } = > {
2020-03-27 12:56:18 -05:00
let sig = self . parameters [ 0 ] . callable_sig ( f . db ) ;
if let Some ( sig ) = sig {
if sig . params ( ) . is_empty ( ) {
write! ( f , " || " ) ? ;
} else if f . omit_verbose_types ( ) {
write! ( f , " |{}| " , TYPE_HINT_TRUNCATION ) ? ;
} else {
write! ( f , " | " ) ? ;
f . write_joined ( sig . params ( ) , " , " ) ? ;
write! ( f , " | " ) ? ;
} ;
2020-07-20 15:50:41 -05:00
let ret_display = if f . omit_verbose_types ( ) {
sig . ret ( ) . display_truncated ( f . db , f . max_size )
} else {
sig . ret ( ) . display ( f . db )
} ;
write! ( f , " -> {} " , ret_display ) ? ;
2020-02-14 08:01:25 -06:00
} else {
2020-03-27 12:56:18 -05:00
write! ( f , " {{closure}} " ) ? ;
}
2020-02-14 08:01:25 -06:00
}
}
Ok ( ( ) )
}
}
impl HirDisplay for ProjectionTy {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
2020-03-31 11:00:23 -05:00
let trait_ = f . db . trait_data ( self . trait_ ( f . db ) ) ;
write! ( f , " <{} as {} " , self . parameters [ 0 ] . display ( f . db ) , trait_ . name ) ? ;
2020-02-14 08:01:25 -06:00
if self . parameters . len ( ) > 1 {
write! ( f , " < " ) ? ;
f . write_joined ( & self . parameters [ 1 .. ] , " , " ) ? ;
write! ( f , " > " ) ? ;
}
write! ( f , " >::{} " , f . db . type_alias_data ( self . associated_ty ) . name ) ? ;
Ok ( ( ) )
}
}
impl HirDisplay for Ty {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
match self {
Ty ::Apply ( a_ty ) = > a_ty . hir_fmt ( f ) ? ,
Ty ::Projection ( p_ty ) = > p_ty . hir_fmt ( f ) ? ,
Ty ::Placeholder ( id ) = > {
2020-03-13 10:05:46 -05:00
let generics = generics ( f . db . upcast ( ) , id . parent ) ;
2020-02-14 08:01:25 -06:00
let param_data = & generics . params . types [ id . local_id ] ;
match param_data . provenance {
TypeParamProvenance ::TypeParamList | TypeParamProvenance ::TraitSelf = > {
write! ( f , " {} " , param_data . name . clone ( ) . unwrap_or_else ( Name ::missing ) ) ?
}
TypeParamProvenance ::ArgumentImplTrait = > {
write! ( f , " impl " ) ? ;
let bounds = f . db . generic_predicates_for_param ( * id ) ;
let substs = Substs ::type_params_for_generics ( & generics ) ;
write_bounds_like_dyn_trait (
& bounds . iter ( ) . map ( | b | b . clone ( ) . subst ( & substs ) ) . collect ::< Vec < _ > > ( ) ,
f ,
) ? ;
}
}
}
2020-04-05 11:24:18 -05:00
Ty ::Bound ( idx ) = > write! ( f , " ?{}.{} " , idx . debruijn . depth ( ) , idx . index ) ? ,
2020-03-04 16:00:44 -06:00
Ty ::Dyn ( predicates ) = > {
write! ( f , " dyn " ) ? ;
2020-03-31 11:00:23 -05:00
write_bounds_like_dyn_trait ( predicates , f ) ? ;
2020-02-14 08:01:25 -06:00
}
2020-03-04 16:00:44 -06:00
Ty ::Opaque ( opaque_ty ) = > {
2020-09-10 07:01:23 -05:00
match opaque_ty . opaque_ty_id {
2020-06-05 10:41:58 -05:00
OpaqueTyId ::ReturnTypeImplTrait ( func , idx ) = > {
2020-03-04 16:00:44 -06:00
let datas =
f . db . return_type_impl_traits ( func ) . expect ( " impl trait id without data " ) ;
let data = ( * datas )
. as_ref ( )
. map ( | rpit | rpit . impl_traits [ idx as usize ] . bounds . clone ( ) ) ;
2020-09-10 07:01:23 -05:00
let bounds = data . subst ( & opaque_ty . parameters ) ;
write! ( f , " impl " ) ? ;
write_bounds_like_dyn_trait ( & bounds . value , f ) ? ;
}
OpaqueTyId ::AsyncBlockTypeImplTrait ( .. ) = > {
write! ( f , " {{async block}} " ) ? ;
2020-03-04 16:00:44 -06:00
}
} ;
}
2020-02-14 08:01:25 -06:00
Ty ::Unknown = > write! ( f , " {{unknown}} " ) ? ,
Ty ::Infer ( .. ) = > write! ( f , " _ " ) ? ,
}
Ok ( ( ) )
}
}
fn write_bounds_like_dyn_trait (
predicates : & [ GenericPredicate ] ,
2020-03-13 10:05:46 -05:00
f : & mut HirFormatter ,
2020-04-25 09:57:59 -05:00
) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06: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 ;
for p in predicates . iter ( ) {
match p {
GenericPredicate ::Implemented ( trait_ref ) = > {
if angle_open {
write! ( f , " > " ) ? ;
2020-08-13 15:13:34 -05:00
angle_open = false ;
2020-02-14 08:01:25 -06:00
}
if ! first {
write! ( f , " + " ) ? ;
}
// We assume that the self type is $0 (i.e. the
// existential) here, which is the only thing that's
// possible in actual Rust, and hence don't print it
2020-03-31 11:00:23 -05:00
write! ( f , " {} " , f . db . trait_data ( trait_ref . trait_ ) . name ) ? ;
2020-02-14 08:01:25 -06:00
if trait_ref . substs . len ( ) > 1 {
write! ( f , " < " ) ? ;
f . write_joined ( & trait_ref . substs [ 1 .. ] , " , " ) ? ;
// there might be assoc type bindings, so we leave the angle brackets open
angle_open = true ;
}
}
GenericPredicate ::Projection ( projection_pred ) = > {
// 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 ;
}
2020-03-31 11:00:23 -05:00
let type_alias = f . db . type_alias_data ( projection_pred . projection_ty . associated_ty ) ;
write! ( f , " {} = " , type_alias . name ) ? ;
2020-02-14 08:01:25 -06:00
projection_pred . ty . hir_fmt ( f ) ? ;
}
GenericPredicate ::Error = > {
if angle_open {
// impl Trait<X, {error}>
write! ( f , " , " ) ? ;
} else if ! first {
// impl Trait + {error}
write! ( f , " + " ) ? ;
}
p . hir_fmt ( f ) ? ;
}
}
first = false ;
}
if angle_open {
write! ( f , " > " ) ? ;
}
Ok ( ( ) )
}
impl TraitRef {
2020-04-25 09:57:59 -05:00
fn hir_fmt_ext ( & self , f : & mut HirFormatter , use_as : bool ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
self . substs [ 0 ] . hir_fmt ( f ) ? ;
if use_as {
write! ( f , " as " ) ? ;
} else {
write! ( f , " : " ) ? ;
}
2020-03-31 11:00:23 -05:00
write! ( f , " {} " , f . db . trait_data ( self . trait_ ) . name ) ? ;
2020-02-14 08:01:25 -06:00
if self . substs . len ( ) > 1 {
write! ( f , " < " ) ? ;
f . write_joined ( & self . substs [ 1 .. ] , " , " ) ? ;
write! ( f , " > " ) ? ;
}
Ok ( ( ) )
}
}
impl HirDisplay for TraitRef {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
self . hir_fmt_ext ( f , false )
}
}
impl HirDisplay for & GenericPredicate {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
HirDisplay ::hir_fmt ( * self , f )
}
}
impl HirDisplay for GenericPredicate {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-02-14 08:01:25 -06:00
if f . should_truncate ( ) {
return write! ( f , " {} " , TYPE_HINT_TRUNCATION ) ;
}
match self {
GenericPredicate ::Implemented ( trait_ref ) = > trait_ref . hir_fmt ( f ) ? ,
GenericPredicate ::Projection ( projection_pred ) = > {
write! ( f , " < " ) ? ;
projection_pred . projection_ty . trait_ref ( f . db ) . hir_fmt_ext ( f , true ) ? ;
write! (
f ,
" >::{} = {} " ,
f . db . type_alias_data ( projection_pred . projection_ty . associated_ty ) . name ,
projection_pred . ty . display ( f . db )
) ? ;
}
GenericPredicate ::Error = > write! ( f , " {{error}} " ) ? ,
}
Ok ( ( ) )
}
}
impl HirDisplay for Obligation {
2020-04-25 09:57:59 -05:00
fn hir_fmt ( & self , f : & mut HirFormatter ) -> Result < ( ) , HirDisplayError > {
2020-10-06 07:40:27 -05:00
match self {
Obligation ::Trait ( tr ) = > write! ( f , " Implements({}) " , tr . display ( f . db ) ) ,
2020-02-14 08:01:25 -06:00
Obligation ::Projection ( proj ) = > write! (
f ,
" Normalize({} => {}) " ,
proj . projection_ty . display ( f . db ) ,
proj . ty . display ( f . db )
2020-10-06 07:40:27 -05:00
) ,
}
2020-02-14 08:01:25 -06:00
}
}