Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/expr_store/pretty.rs')
| -rw-r--r-- | crates/hir-def/src/expr_store/pretty.rs | 711 |
1 files changed, 637 insertions, 74 deletions
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs index 82ad756dc2..f12a9b7a54 100644 --- a/crates/hir-def/src/expr_store/pretty.rs +++ b/crates/hir-def/src/expr_store/pretty.rs @@ -1,56 +1,83 @@ //! A pretty-printer for HIR. +#![allow(dead_code)] -use std::fmt::{self, Write}; +use std::{ + fmt::{self, Write}, + mem, +}; +use hir_expand::{Lookup, mod_path::PathKind}; use itertools::Itertools; use span::Edition; use crate::{ - hir::{Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement}, - pretty::{print_generic_args, print_path, print_type_ref}, + AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId, + expr_store::path::{GenericArg, GenericArgs}, + hir::{ + Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement, + generics::{GenericParams, WherePredicate}, + }, + lang_item::LangItemTarget, + signatures::{FnFlags, FunctionSignature, StructSignature}, + type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef}, }; +use crate::{LifetimeParamId, signatures::StructFlags}; +use crate::{item_tree::FieldsShape, signatures::FieldData}; use super::*; +macro_rules! w { + ($dst:expr, $($arg:tt)*) => { + { let _ = write!($dst, $($arg)*); } + }; +} + +macro_rules! wln { + ($dst:expr) => { + { $dst.newline(); } + }; + ($dst:expr, $($arg:tt)*) => { + { let _ = w!($dst, $($arg)*); $dst.newline(); } + }; +} + #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(super) enum LineFormat { +pub enum LineFormat { Oneline, Newline, Indentation, } -pub(super) fn print_body_hir( +pub fn print_body_hir( db: &dyn DefDatabase, body: &Body, owner: DefWithBodyId, edition: Edition, ) -> String { let header = match owner { - DefWithBodyId::FunctionId(it) => it - .lookup(db) - .id - .resolved(db, |it| format!("fn {}", it.name.display(db.upcast(), edition))), + DefWithBodyId::FunctionId(it) => { + it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition))) + } DefWithBodyId::StaticId(it) => it .lookup(db) .id - .resolved(db, |it| format!("static {} = ", it.name.display(db.upcast(), edition))), + .resolved(db, |it| format!("static {} = ", it.name.display(db, edition))), DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| { format!( "const {} = ", match &it.name { - Some(name) => name.display(db.upcast(), edition).to_string(), + Some(name) => name.display(db, edition).to_string(), None => "_".to_owned(), } ) }), - DefWithBodyId::InTypeConstId(_) => "In type const = ".to_owned(), DefWithBodyId::VariantId(it) => { let loc = it.lookup(db); let enum_loc = loc.parent.lookup(db); format!( "enum {}::{}", - enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db.upcast(), edition), - loc.id.item_tree(db)[loc.id.value].name.display(db.upcast(), edition), + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), + loc.id.item_tree(db)[loc.id.value].name.display(db, edition), ) } }; @@ -63,32 +90,21 @@ pub(super) fn print_body_hir( line_format: LineFormat::Newline, edition, }; - if let DefWithBodyId::FunctionId(it) = owner { + if let DefWithBodyId::FunctionId(_) = owner { p.buf.push('('); - let function_data = db.function_data(it); - let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type); if let Some(self_param) = body.self_param { p.print_binding(self_param); - p.buf.push_str(": "); - if let Some(ty) = params.next() { - p.print_type_ref(*ty, &function_data.types_map); - p.buf.push_str(", "); - } + p.buf.push_str(", "); } - body.params.iter().zip(params).for_each(|(¶m, ty)| { - p.print_pat(param); - p.buf.push_str(": "); - p.print_type_ref(*ty, &function_data.types_map); + body.params.iter().for_each(|param| { + p.print_pat(*param); p.buf.push_str(", "); }); // remove the last ", " in param list - if body.params.len() > 0 { + if !body.params.is_empty() { p.buf.truncate(p.buf.len() - 2); } p.buf.push(')'); - // return type - p.buf.push_str(" -> "); - p.print_type_ref(*ret_type, &function_data.types_map); p.buf.push(' '); } p.print_expr(body.body_expr); @@ -98,7 +114,298 @@ pub(super) fn print_body_hir( p.buf } -pub(super) fn print_expr_hir( +pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String { + let header = match owner { + VariantId::StructId(it) => { + it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition))) + } + VariantId::EnumVariantId(enum_variant_id) => { + let loc = enum_variant_id.lookup(db); + let enum_loc = loc.parent.lookup(db); + format!( + "enum {}::{}", + enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition), + loc.id.item_tree(db)[loc.id.value].name.display(db, edition), + ) + } + VariantId::UnionId(union_id) => union_id + .lookup(db) + .id + .resolved(db, |it| format!("union {}", it.name.display(db, edition))), + }; + + let fields = db.variant_fields(owner); + + let mut p = Printer { + db, + store: &fields.store, + buf: header, + indent_level: 0, + line_format: LineFormat::Newline, + edition, + }; + match fields.shape { + FieldsShape::Record => wln!(p, " {{"), + FieldsShape::Tuple => wln!(p, "("), + FieldsShape::Unit => (), + } + + for (_, data) in fields.fields().iter() { + let FieldData { name, type_ref, visibility, is_unsafe } = data; + match visibility { + crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => { + w!(p, "{}", interned.display(db, p.edition)) + } + crate::item_tree::RawVisibility::Public => w!(p, "pub "), + } + if *is_unsafe { + w!(p, "unsafe "); + } + w!(p, "{}: ", name.display(db, p.edition)); + p.print_type_ref(*type_ref); + } + + match fields.shape { + FieldsShape::Record => wln!(p, "}}"), + FieldsShape::Tuple => wln!(p, ");"), + FieldsShape::Unit => wln!(p, ";"), + } + p.buf +} + +pub fn print_signature(db: &dyn DefDatabase, owner: GenericDefId, edition: Edition) -> String { + match owner { + GenericDefId::AdtId(id) => match id { + AdtId::StructId(id) => { + let signature = db.struct_signature(id); + print_struct(db, &signature, edition) + } + AdtId::UnionId(id) => { + format!("unimplemented {id:?}") + } + AdtId::EnumId(id) => { + format!("unimplemented {id:?}") + } + }, + GenericDefId::ConstId(id) => format!("unimplemented {id:?}"), + GenericDefId::FunctionId(id) => { + let signature = db.function_signature(id); + print_function(db, &signature, edition) + } + GenericDefId::ImplId(id) => format!("unimplemented {id:?}"), + GenericDefId::StaticId(id) => format!("unimplemented {id:?}"), + GenericDefId::TraitAliasId(id) => format!("unimplemented {id:?}"), + GenericDefId::TraitId(id) => format!("unimplemented {id:?}"), + GenericDefId::TypeAliasId(id) => format!("unimplemented {id:?}"), + } +} + +pub fn print_path( + db: &dyn DefDatabase, + store: &ExpressionStore, + path: &Path, + edition: Edition, +) -> String { + let mut p = Printer { + db, + store, + buf: String::new(), + indent_level: 0, + line_format: LineFormat::Newline, + edition, + }; + p.print_path(path); + p.buf +} + +pub fn print_struct( + db: &dyn DefDatabase, + StructSignature { name, generic_params, store, flags, shape, repr }: &StructSignature, + edition: Edition, +) -> String { + let mut p = Printer { + db, + store, + buf: String::new(), + indent_level: 0, + line_format: LineFormat::Newline, + edition, + }; + if let Some(repr) = repr { + if repr.c() { + wln!(p, "#[repr(C)]"); + } + if let Some(align) = repr.align { + wln!(p, "#[repr(align({}))]", align.bytes()); + } + if let Some(pack) = repr.pack { + wln!(p, "#[repr(pack({}))]", pack.bytes()); + } + } + if flags.contains(StructFlags::FUNDAMENTAL) { + wln!(p, "#[fundamental]"); + } + w!(p, "struct "); + w!(p, "{}", name.display(db, edition)); + print_generic_params(db, generic_params, &mut p); + match shape { + FieldsShape::Record => wln!(p, " {{...}}"), + FieldsShape::Tuple => wln!(p, "(...)"), + FieldsShape::Unit => (), + } + + print_where_clauses(db, generic_params, &mut p); + + match shape { + FieldsShape::Record => wln!(p), + FieldsShape::Tuple => wln!(p, ";"), + FieldsShape::Unit => wln!(p, ";"), + } + + p.buf +} + +pub fn print_function( + db: &dyn DefDatabase, + FunctionSignature { + name, + generic_params, + store, + params, + ret_type, + abi, + flags, + legacy_const_generics_indices, + }: &FunctionSignature, + edition: Edition, +) -> String { + let mut p = Printer { + db, + store, + buf: String::new(), + indent_level: 0, + line_format: LineFormat::Newline, + edition, + }; + if flags.contains(FnFlags::CONST) { + w!(p, "const "); + } + if flags.contains(FnFlags::ASYNC) { + w!(p, "async "); + } + if flags.contains(FnFlags::UNSAFE) { + w!(p, "unsafe "); + } + if flags.contains(FnFlags::EXPLICIT_SAFE) { + w!(p, "safe "); + } + if let Some(abi) = abi { + w!(p, "extern \"{}\" ", abi.as_str()); + } + w!(p, "fn "); + w!(p, "{}", name.display(db, edition)); + print_generic_params(db, generic_params, &mut p); + w!(p, "("); + for (i, param) in params.iter().enumerate() { + if i != 0 { + w!(p, ", "); + } + if legacy_const_generics_indices.as_ref().is_some_and(|idx| idx.contains(&(i as u32))) { + w!(p, "const: "); + } + p.print_type_ref(*param); + } + w!(p, ")"); + if let Some(ret_type) = ret_type { + w!(p, " -> "); + p.print_type_ref(*ret_type); + } + + print_where_clauses(db, generic_params, &mut p); + wln!(p, " {{...}}"); + + p.buf +} + +fn print_where_clauses(db: &dyn DefDatabase, generic_params: &GenericParams, p: &mut Printer<'_>) { + if !generic_params.where_predicates.is_empty() { + w!(p, "\nwhere\n"); + p.indented(|p| { + for (i, pred) in generic_params.where_predicates.iter().enumerate() { + if i != 0 { + w!(p, ",\n"); + } + match pred { + WherePredicate::TypeBound { target, bound } => { + p.print_type_ref(*target); + w!(p, ": "); + p.print_type_bounds(std::slice::from_ref(bound)); + } + WherePredicate::Lifetime { target, bound } => { + p.print_lifetime_ref(*target); + w!(p, ": "); + p.print_lifetime_ref(*bound); + } + WherePredicate::ForLifetime { lifetimes, target, bound } => { + w!(p, "for<"); + for (i, lifetime) in lifetimes.iter().enumerate() { + if i != 0 { + w!(p, ", "); + } + w!(p, "{}", lifetime.display(db, p.edition)); + } + w!(p, "> "); + p.print_type_ref(*target); + w!(p, ": "); + p.print_type_bounds(std::slice::from_ref(bound)); + } + } + } + }); + wln!(p); + } +} + +fn print_generic_params(db: &dyn DefDatabase, generic_params: &GenericParams, p: &mut Printer<'_>) { + if !generic_params.is_empty() { + w!(p, "<"); + let mut first = true; + for (_i, param) in generic_params.iter_lt() { + if !first { + w!(p, ", "); + } + first = false; + w!(p, "{}", param.name.display(db, p.edition)); + } + for (i, param) in generic_params.iter_type_or_consts() { + if !first { + w!(p, ", "); + } + first = false; + if let Some(const_param) = param.const_param() { + w!(p, "const {}: ", const_param.name.display(db, p.edition)); + p.print_type_ref(const_param.ty); + if let Some(default) = const_param.default { + w!(p, " = "); + p.print_expr(default.expr); + } + } + if let Some(type_param) = param.type_param() { + match &type_param.name { + Some(name) => w!(p, "{}", name.display(db, p.edition)), + None => w!(p, "Param[{}]", i.into_raw()), + } + if let Some(default) = type_param.default { + w!(p, " = "); + p.print_type_ref(default); + } + } + } + w!(p, ">"); + } +} + +pub fn print_expr_hir( db: &dyn DefDatabase, store: &ExpressionStore, _owner: DefWithBodyId, @@ -117,7 +424,7 @@ pub(super) fn print_expr_hir( p.buf } -pub(super) fn print_pat_hir( +pub fn print_pat_hir( db: &dyn DefDatabase, store: &ExpressionStore, _owner: DefWithBodyId, @@ -137,21 +444,6 @@ pub(super) fn print_pat_hir( p.buf } -macro_rules! w { - ($dst:expr, $($arg:tt)*) => { - { let _ = write!($dst, $($arg)*); } - }; -} - -macro_rules! wln { - ($dst:expr) => { - { $dst.newline(); } - }; - ($dst:expr, $($arg:tt)*) => { - { let _ = w!($dst, $($arg)*); $dst.newline(); } - }; -} - struct Printer<'a> { db: &'a dyn DefDatabase, store: &'a ExpressionStore, @@ -238,7 +530,7 @@ impl Printer<'_> { Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"), Expr::OffsetOf(offset_of) => { w!(self, "builtin#offset_of("); - self.print_type_ref(offset_of.container, &self.store.types); + self.print_type_ref(offset_of.container); let edition = self.edition; w!( self, @@ -246,7 +538,7 @@ impl Printer<'_> { offset_of .fields .iter() - .format_with(".", |field, f| f(&field.display(self.db.upcast(), edition))) + .format_with(".", |field, f| f(&field.display(self.db, edition))) ); } Expr::Path(path) => self.print_path(path), @@ -268,7 +560,7 @@ impl Printer<'_> { } Expr::Loop { body, label } => { if let Some(lbl) = label { - w!(self, "{}: ", self.store[*lbl].name.display(self.db.upcast(), self.edition)); + w!(self, "{}: ", self.store[*lbl].name.display(self.db, self.edition)); } w!(self, "loop "); self.print_expr(*body); @@ -288,11 +580,10 @@ impl Printer<'_> { } Expr::MethodCall { receiver, method_name, args, generic_args } => { self.print_expr(*receiver); - w!(self, ".{}", method_name.display(self.db.upcast(), self.edition)); + w!(self, ".{}", method_name.display(self.db, self.edition)); if let Some(args) = generic_args { w!(self, "::<"); - let edition = self.edition; - print_generic_args(self.db, args, &self.store.types, self, edition).unwrap(); + self.print_generic_args(args); w!(self, ">"); } w!(self, "("); @@ -327,13 +618,13 @@ impl Printer<'_> { Expr::Continue { label } => { w!(self, "continue"); if let Some(lbl) = label { - w!(self, " {}", self.store[*lbl].name.display(self.db.upcast(), self.edition)); + w!(self, " {}", self.store[*lbl].name.display(self.db, self.edition)); } } Expr::Break { expr, label } => { w!(self, "break"); if let Some(lbl) = label { - w!(self, " {}", self.store[*lbl].name.display(self.db.upcast(), self.edition)); + w!(self, " {}", self.store[*lbl].name.display(self.db, self.edition)); } if let Some(expr) = expr { self.whitespace(); @@ -378,7 +669,7 @@ impl Printer<'_> { let edition = self.edition; self.indented(|p| { for field in &**fields { - w!(p, "{}: ", field.name.display(self.db.upcast(), edition)); + w!(p, "{}: ", field.name.display(self.db, edition)); p.print_expr(field.expr); wln!(p, ","); } @@ -392,7 +683,7 @@ impl Printer<'_> { } Expr::Field { expr, name } => { self.print_expr(*expr); - w!(self, ".{}", name.display(self.db.upcast(), self.edition)); + w!(self, ".{}", name.display(self.db, self.edition)); } Expr::Await { expr } => { self.print_expr(*expr); @@ -401,7 +692,7 @@ impl Printer<'_> { Expr::Cast { expr, type_ref } => { self.print_expr(*expr); w!(self, " as "); - self.print_type_ref(*type_ref, &self.store.types); + self.print_type_ref(*type_ref); } Expr::Ref { expr, rawness, mutability } => { w!(self, "&"); @@ -489,13 +780,13 @@ impl Printer<'_> { self.print_pat(*pat); if let Some(ty) = ty { w!(self, ": "); - self.print_type_ref(*ty, &self.store.types); + self.print_type_ref(*ty); } } w!(self, "|"); if let Some(ret_ty) = ret_type { w!(self, " -> "); - self.print_type_ref(*ret_ty, &self.store.types); + self.print_type_ref(*ret_ty); } self.whitespace(); self.print_expr(*body); @@ -531,7 +822,7 @@ impl Printer<'_> { Expr::Literal(lit) => self.print_literal(lit), Expr::Block { id: _, statements, tail, label } => { let label = label.map(|lbl| { - format!("{}: ", self.store[lbl].name.display(self.db.upcast(), self.edition)) + format!("{}: ", self.store[lbl].name.display(self.db, self.edition)) }); self.print_block(label.as_deref(), statements, tail); } @@ -617,7 +908,7 @@ impl Printer<'_> { let oneline = matches!(self.line_format, LineFormat::Oneline); self.indented(|p| { for (idx, arg) in args.iter().enumerate() { - let field_name = arg.name.display(self.db.upcast(), edition).to_string(); + let field_name = arg.name.display(self.db, edition).to_string(); let mut same_name = false; if let Pat::Bind { id, subpat: None } = &self.store[arg.pat] { @@ -731,7 +1022,7 @@ impl Printer<'_> { self.print_pat(*pat); if let Some(ty) = type_ref { w!(self, ": "); - self.print_type_ref(*ty, &self.store.types); + self.print_type_ref(*ty); } if let Some(init) = initializer { w!(self, " = "); @@ -782,16 +1073,6 @@ impl Printer<'_> { } } - fn print_type_ref(&mut self, ty: TypeRefId, map: &TypesMap) { - let edition = self.edition; - print_type_ref(self.db, ty, map, self, edition).unwrap(); - } - - fn print_path(&mut self, path: &Path) { - let edition = self.edition; - print_path(self.db, path, &self.store.types, self, edition).unwrap(); - } - fn print_binding(&mut self, id: BindingId) { let Binding { name, mode, .. } = &self.store.bindings[id]; let mode = match mode { @@ -800,6 +1081,288 @@ impl Printer<'_> { BindingAnnotation::Ref => "ref ", BindingAnnotation::RefMut => "ref mut ", }; - w!(self, "{}{}", mode, name.display(self.db.upcast(), self.edition)); + w!(self, "{}{}", mode, name.display(self.db, self.edition)); + } + + fn print_path(&mut self, path: &Path) { + if let Path::LangItem(it, s) = path { + w!(self, "builtin#lang("); + macro_rules! write_name { + ($it:ident) => {{ + let loc = $it.lookup(self.db); + let tree = loc.item_tree_id().item_tree(self.db); + let name = &tree[loc.id.value].name; + w!(self, "{}", name.display(self.db, self.edition)); + }}; + } + match *it { + LangItemTarget::ImplDef(it) => w!(self, "{it:?}"), + LangItemTarget::EnumId(it) => write_name!(it), + LangItemTarget::Function(it) => write_name!(it), + LangItemTarget::Static(it) => write_name!(it), + LangItemTarget::Struct(it) => write_name!(it), + LangItemTarget::Union(it) => write_name!(it), + LangItemTarget::TypeAlias(it) => write_name!(it), + LangItemTarget::Trait(it) => write_name!(it), + LangItemTarget::EnumVariant(it) => write_name!(it), + } + + if let Some(s) = s { + w!(self, "::{}", s.display(self.db, self.edition)); + } + return w!(self, ")"); + } + match path.type_anchor() { + Some(anchor) => { + w!(self, "<"); + self.print_type_ref(anchor); + w!(self, ">::"); + } + None => match path.kind() { + PathKind::Plain => {} + &PathKind::SELF => w!(self, "self"), + PathKind::Super(n) => { + for i in 0..*n { + if i == 0 { + w!(self, "super"); + } else { + w!(self, "::super"); + } + } + } + PathKind::Crate => w!(self, "crate"), + PathKind::Abs => {} + PathKind::DollarCrate(krate) => w!( + self, + "{}", + krate + .extra_data(self.db) + .display_name + .as_ref() + .map(|it| it.crate_name().symbol().as_str()) + .unwrap_or("$crate") + ), + }, + } + + for (i, segment) in path.segments().iter().enumerate() { + if i != 0 || !matches!(path.kind(), PathKind::Plain) { + w!(self, "::"); + } + + w!(self, "{}", segment.name.display(self.db, self.edition)); + if let Some(generics) = segment.args_and_bindings { + w!(self, "::<"); + self.print_generic_args(generics); + + w!(self, ">"); + } + } + } + + pub(crate) fn print_generic_args(&mut self, generics: &GenericArgs) { + let mut first = true; + let args = if generics.has_self_type { + let (self_ty, args) = generics.args.split_first().unwrap(); + w!(self, "Self="); + self.print_generic_arg(self_ty); + first = false; + args + } else { + &generics.args + }; + for arg in args { + if !first { + w!(self, ", "); + } + first = false; + self.print_generic_arg(arg); + } + for binding in generics.bindings.iter() { + if !first { + w!(self, ", "); + } + first = false; + w!(self, "{}", binding.name.display(self.db, self.edition)); + if !binding.bounds.is_empty() { + w!(self, ": "); + self.print_type_bounds(&binding.bounds); + } + if let Some(ty) = binding.type_ref { + w!(self, " = "); + self.print_type_ref(ty); + } + } + } + + pub(crate) fn print_generic_arg(&mut self, arg: &GenericArg) { + match arg { + GenericArg::Type(ty) => self.print_type_ref(*ty), + GenericArg::Const(ConstRef { expr }) => self.print_expr(*expr), + GenericArg::Lifetime(lt) => self.print_lifetime_ref(*lt), + } + } + + pub(crate) fn print_type_param(&mut self, param: TypeParamId) { + let generic_params = self.db.generic_params(param.parent()); + + match generic_params[param.local_id()].name() { + Some(name) => w!(self, "{}", name.display(self.db, self.edition)), + None => w!(self, "Param[{}]", param.local_id().into_raw()), + } + } + + pub(crate) fn print_lifetime_param(&mut self, param: LifetimeParamId) { + let generic_params = self.db.generic_params(param.parent); + w!(self, "{}", generic_params[param.local_id].name.display(self.db, self.edition)) + } + + pub(crate) fn print_lifetime_ref(&mut self, lt_ref: LifetimeRefId) { + match &self.store[lt_ref] { + LifetimeRef::Static => w!(self, "'static"), + LifetimeRef::Named(lt) => { + w!(self, "{}", lt.display(self.db, self.edition)) + } + LifetimeRef::Placeholder => w!(self, "'_"), + LifetimeRef::Error => w!(self, "'{{error}}"), + &LifetimeRef::Param(p) => self.print_lifetime_param(p), + } + } + + pub(crate) fn print_type_ref(&mut self, type_ref: TypeRefId) { + // FIXME: deduplicate with `HirDisplay` impl + match &self.store[type_ref] { + TypeRef::Never => w!(self, "!"), + &TypeRef::TypeParam(p) => self.print_type_param(p), + TypeRef::Placeholder => w!(self, "_"), + TypeRef::Tuple(fields) => { + w!(self, "("); + for (i, field) in fields.iter().enumerate() { + if i != 0 { + w!(self, ", "); + } + self.print_type_ref(*field); + } + w!(self, ")"); + } + TypeRef::Path(path) => self.print_path(path), + TypeRef::RawPtr(pointee, mtbl) => { + let mtbl = match mtbl { + Mutability::Shared => "*const", + Mutability::Mut => "*mut", + }; + w!(self, "{mtbl} "); + self.print_type_ref(*pointee); + } + TypeRef::Reference(ref_) => { + let mtbl = match ref_.mutability { + Mutability::Shared => "", + Mutability::Mut => "mut ", + }; + w!(self, "&"); + if let Some(lt) = &ref_.lifetime { + self.print_lifetime_ref(*lt); + w!(self, " "); + } + w!(self, "{mtbl}"); + self.print_type_ref(ref_.ty); + } + TypeRef::Array(array) => { + w!(self, "["); + self.print_type_ref(array.ty); + w!(self, "; "); + self.print_generic_arg(&GenericArg::Const(array.len)); + w!(self, "]"); + } + TypeRef::Slice(elem) => { + w!(self, "["); + self.print_type_ref(*elem); + w!(self, "]"); + } + TypeRef::Fn(fn_) => { + let ((_, return_type), args) = + fn_.params.split_last().expect("TypeRef::Fn is missing return type"); + if fn_.is_unsafe { + w!(self, "unsafe "); + } + if let Some(abi) = &fn_.abi { + w!(self, "extern "); + w!(self, "{}", abi.as_str()); + w!(self, " "); + } + w!(self, "fn("); + for (i, (_, typeref)) in args.iter().enumerate() { + if i != 0 { + w!(self, ", "); + } + self.print_type_ref(*typeref); + } + if fn_.is_varargs { + if !args.is_empty() { + w!(self, ", "); + } + w!(self, "..."); + } + w!(self, ") -> "); + self.print_type_ref(*return_type); + } + TypeRef::Error => w!(self, "{{error}}"), + TypeRef::ImplTrait(bounds) => { + w!(self, "impl "); + self.print_type_bounds(bounds); + } + TypeRef::DynTrait(bounds) => { + w!(self, "dyn "); + self.print_type_bounds(bounds); + } + } + } + + pub(crate) fn print_type_bounds(&mut self, bounds: &[TypeBound]) { + for (i, bound) in bounds.iter().enumerate() { + if i != 0 { + w!(self, " + "); + } + + match bound { + TypeBound::Path(path, modifier) => { + match modifier { + TraitBoundModifier::None => (), + TraitBoundModifier::Maybe => w!(self, "?"), + } + self.print_path(&self.store[*path]); + } + TypeBound::ForLifetime(lifetimes, path) => { + w!( + self, + "for<{}> ", + lifetimes + .iter() + .map(|it| it.display(self.db, self.edition)) + .format(", ") + .to_string() + ); + self.print_path(&self.store[*path]); + } + TypeBound::Lifetime(lt) => self.print_lifetime_ref(*lt), + TypeBound::Use(args) => { + w!(self, "use<"); + let mut first = true; + for arg in args { + if !mem::take(&mut first) { + w!(self, ", "); + } + match arg { + UseArgRef::Name(it) => { + w!(self, "{}", it.display(self.db, self.edition)) + } + UseArgRef::Lifetime(it) => self.print_lifetime_ref(*it), + } + } + w!(self, ">") + } + TypeBound::Error => w!(self, "{{unknown}}"), + } + } } } |