use std::fmt::{Formatter, Result};
use crate::rust_ir::*;
use crate::split::Split;
use chalk_ir::interner::Interner;
use itertools::Itertools;
use super::{
display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust,
state::InternalWriterState,
};
macro_rules! write_flags {
($writer:ident, $val:expr, $struct_name:ident { $($n:ident $(: $extra_arg:tt)?),* }) => {
match $val {
$struct_name {
$($n,)*
} => {
$(if $n {
write!($writer, "#[{}]\n", write_flags!(@default $n $(: $extra_arg)*))?;
})*
}
}
};
(@default $n:ident : $name:literal) => {
$name
};
(@default $n:ident ) => {
stringify!($n)
};
}
impl<'a, I: Interner> RenderAsRust<I> for (&'a CoroutineDatum<I>, &'a CoroutineWitnessDatum<I>) {
fn fmt(&self, _s: &InternalWriterState<'_, I>, _f: &'_ mut Formatter<'_>) -> Result {
unimplemented!()
}
}
impl<I: Interner> RenderAsRust<I> for AdtDatum<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
let s = &s.add_debrujin_index(None);
let value = self.binders.skip_binders();
write_flags!(
f,
self.flags,
AdtFlags {
upstream,
fundamental,
phantom_data
}
);
let repr = s.db().adt_repr(self.id);
if repr.c {
write!(f, "#[repr(C)]")?;
}
if repr.packed {
write!(f, "#[repr(packed)]")?;
}
if let Some(t) = &repr.int {
write!(f, "#[repr({})]", t.display(s))?;
}
match self.kind {
AdtKind::Struct => write!(f, "struct {}", self.id.display(s),)?,
AdtKind::Enum => write!(f, "enum {}", self.id.display(s),)?,
AdtKind::Union => write!(f, "union {}", self.id.display(s),)?,
}
write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.binders.binders), ", ")?;
if !value.where_clauses.is_empty() {
let s = &s.add_indent();
write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?;
} else {
write!(f, " ")?;
}
write!(f, "{{")?;
let s = &s.add_indent();
match self.kind {
AdtKind::Struct | AdtKind::Union => {
write_joined_non_empty_list!(
f,
"\n{}\n",
value.variants[0]
.fields
.iter()
.enumerate()
.map(|(idx, field)| {
format!("{}field_{}: {}", s.indent(), idx, field.display(s))
}),
",\n"
)?;
}
AdtKind::Enum => {
for (variant_idx, variant) in value.variants.iter().enumerate() {
write!(f, "\n{}variant_{} {{", s.indent(), variant_idx)?;
let s = &s.add_indent();
write_joined_non_empty_list!(
f,
"\n{}\n",
variant.fields.iter().enumerate().map(|(idx, field)| {
format!("{}field_{}: {}", s.indent(), idx, field.display(s))
}),
",\n"
)?;
write!(f, "{}}},", s.indent())?;
}
}
}
write!(f, "}}")?;
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for Polarity {
fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
if !self.is_positive() {
write!(f, "!")?;
}
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for TraitDatum<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
let s = &s.add_debrujin_index(Some(0));
let value = self.binders.skip_binders();
write_flags!(
f,
self.flags,
TraitFlags {
auto,
marker,
upstream,
fundamental,
non_enumerable,
coinductive
}
);
if s.db().is_object_safe(self.id) {
writeln!(f, "#[object_safe]")?;
}
if let Some(well_known) = self.well_known {
let name = match well_known {
WellKnownTrait::Sized => "sized",
WellKnownTrait::Copy => "copy",
WellKnownTrait::Clone => "clone",
WellKnownTrait::Drop => "drop",
WellKnownTrait::FnOnce => "fn_once",
WellKnownTrait::FnMut => "fn_mut",
WellKnownTrait::Fn => "fn",
WellKnownTrait::Unsize => "unsize",
WellKnownTrait::Unpin => "unpin",
WellKnownTrait::CoerceUnsized => "coerce_unsized",
WellKnownTrait::DiscriminantKind => "discriminant_kind",
WellKnownTrait::Coroutine => "coroutine",
WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn",
WellKnownTrait::Tuple => "tuple_trait",
WellKnownTrait::Pointee => "pointee",
WellKnownTrait::FnPtr => "fn_ptr_trait",
};
writeln!(f, "#[lang({})]", name)?;
}
let binders = s.binder_var_display(&self.binders.binders).skip(1);
write!(f, "trait {}", self.id.display(s))?;
write_joined_non_empty_list!(f, "<{}>", binders, ", ")?;
if !value.where_clauses.is_empty() {
let s = &s.add_indent();
write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?;
} else {
write!(f, " ")?;
}
write!(f, "{{")?;
let s = &s.add_indent();
write_joined_non_empty_list!(
f,
"\n{}\n",
self.associated_ty_ids.iter().map(|assoc_ty_id| {
let assoc_ty_data = s.db().associated_ty_data(*assoc_ty_id);
format!("{}{}", s.indent(), (*assoc_ty_data).display(s))
}),
"\n"
)?;
write!(f, "}}")?;
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for ImplDatum<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
let interner = s.db().interner();
let s = &s.add_debrujin_index(None);
let binders = s.binder_var_display(&self.binders.binders);
let value = self.binders.skip_binders();
if self.impl_type == ImplType::External {
writeln!(f, "#[upstream]")?;
}
write!(f, "impl")?;
let trait_ref = &value.trait_ref;
write_joined_non_empty_list!(f, "<{}>", binders, ", ")?;
let full_trait_name = display_type_with_generics(
s,
trait_ref.trait_id,
&trait_ref.substitution.as_slice(interner)[1..],
);
write!(
f,
" {}{} for {}",
self.polarity.display(s),
full_trait_name,
trait_ref.self_type_parameter(interner).display(s)
)?;
if !value.where_clauses.is_empty() {
let s = &s.add_indent();
write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?;
} else {
write!(f, " ")?;
}
write!(f, "{{")?;
{
let s = &s.add_indent();
let assoc_ty_values = self.associated_ty_value_ids.iter().map(|assoc_ty_value| {
s.db()
.associated_ty_value(*assoc_ty_value)
.display(s)
.to_string()
});
write_joined_non_empty_list!(f, "\n{}\n", assoc_ty_values, "\n")?;
}
write!(f, "}}")?;
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for OpaqueTyDatum<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result {
let s = &s.add_debrujin_index(None);
let bounds = self.bound.skip_binders();
write!(f, "opaque type {}", self.opaque_ty_id.display(s))?;
write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.bound.binders), ", ")?;
{
let s = &s.add_debrujin_index(Some(0));
let clauses = bounds.bounds.skip_binders();
write!(
f,
": {} = ",
display_self_where_clauses_as_bounds(s, clauses)
)?;
}
write!(
f,
"{};",
s.db().hidden_opaque_type(self.opaque_ty_id).display(s)
)?;
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for AssociatedTyDatum<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
let trait_datum = s.db().trait_datum(self.trait_id);
let trait_param_names_in_trait_env = s.binder_var_indices(&trait_datum.binders.binders);
let s = &s.add_debrujin_index(None);
let param_names_in_assoc_ty_env = s
.binder_var_indices(&self.binders.binders)
.collect::<Vec<_>>();
let (trait_param_names_in_assoc_ty_env, _) = s
.db()
.split_associated_ty_parameters(¶m_names_in_assoc_ty_env, self);
let s = &s.add_parameter_mapping(
trait_param_names_in_assoc_ty_env.iter().copied(),
trait_param_names_in_trait_env,
);
let binder_display_in_assoc_ty = s
.binder_var_display(&self.binders.binders)
.collect::<Vec<_>>();
let (_, assoc_ty_params) = s
.db()
.split_associated_ty_parameters(&binder_display_in_assoc_ty, self);
write!(f, "type {}", self.id.display(s))?;
write_joined_non_empty_list!(f, "<{}>", assoc_ty_params, ", ")?;
let datum_bounds = &self.binders.skip_binders();
if !datum_bounds.bounds.is_empty() {
write!(f, ": ")?;
}
let bounds = datum_bounds
.bounds
.iter()
.map(|bound| bound.display(s).to_string())
.format(" + ");
write!(f, "{}", bounds)?;
if !datum_bounds.where_clauses.is_empty() {
let where_s = &s.add_indent();
let where_clauses = datum_bounds.where_clauses.display(where_s);
write!(f, "\n{}where\n{}", s.indent(), where_clauses)?;
}
write!(f, ";")?;
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for AssociatedTyValue<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
let assoc_ty_data = s.db().associated_ty_data(self.associated_ty_id);
let impl_datum = s.db().impl_datum(self.impl_id);
let impl_param_names_in_impl_env = s.binder_var_indices(&impl_datum.binders.binders);
let s = &s.add_debrujin_index(None);
let value = self.value.skip_binders();
let param_names_in_assoc_ty_value_env = s
.binder_var_indices(&self.value.binders)
.collect::<Vec<_>>();
let (impl_params_in_assoc_ty_value_env, _assoc_ty_value_params) = s
.db()
.split_associated_ty_value_parameters(¶m_names_in_assoc_ty_value_env, self);
let s = &s.add_parameter_mapping(
impl_params_in_assoc_ty_value_env.iter().cloned(),
impl_param_names_in_impl_env,
);
let display_params = s
.binder_var_display(&self.value.binders)
.collect::<Vec<_>>();
let (_impl_display, assoc_ty_value_display) = s
.db()
.split_associated_ty_value_parameters(&display_params, self);
write!(f, "{}type {}", s.indent(), assoc_ty_data.id.display(s))?;
write_joined_non_empty_list!(f, "<{}>", assoc_ty_value_display, ", ")?;
write!(f, " = {};", value.ty.display(s))?;
Ok(())
}
}
impl<I: Interner> RenderAsRust<I> for FnDefDatum<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result {
let s = &s.add_debrujin_index(None);
let bound_datum = self.binders.skip_binders();
write!(f, "fn {}", s.db().fn_def_name(self.id))?;
let binders = s.binder_var_display(&self.binders.binders);
write_joined_non_empty_list!(f, "<{}>", binders, ", ")?;
{
let s = &s.add_debrujin_index(None);
let inputs_and_output = bound_datum.inputs_and_output.skip_binders();
let arguments = inputs_and_output
.argument_types
.iter()
.enumerate()
.map(|(idx, arg)| format!("arg_{}: {}", idx, arg.display(s)))
.format(", ");
write!(f, "({})", arguments)?;
write!(f, " -> {}", inputs_and_output.return_type.display(s))?;
}
if !bound_datum.where_clauses.is_empty() {
let s = &s.add_indent();
write!(f, "\nwhere\n{}", bound_datum.where_clauses.display(s))?;
}
write!(f, ";")?;
Ok(())
}
}