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.rs711
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(|(&param, 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}}"),
+ }
+ }
}
}