//! Writer logic for top level items. //! //! Contains code specific to top-level items and other structures specific to a //! single top-level item. 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, }; /// Used in `AdtDatum` and `TraitDatum` to write n flags from a flags struct /// to a writer. Each flag field turns into an if expression + write!, so we can /// just list the names and not repeat this pattern over and over. /// /// This macro will error if unknown flags are specified. This will also error /// if any flags are missing. /// /// # Usage /// /// ```rust,ignore /// write_flags!(f, self.flags, XFlags { red, green }) /// ``` /// /// Turns into /// /// ```rust,ignore /// match self.flags { /// XFlags { red, green } => { /// if red { /// write!(f, "#[red]")?; /// } /// if green { /// write!(f, "#[green]")?; /// } /// } /// } /// ``` macro_rules! write_flags { ($writer:ident, $val:expr, $struct_name:ident { $($n:ident $(: $extra_arg:tt)?),* }) => { match $val { // if any fields are missing, the destructuring will error $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 for (&'a GeneratorDatum, &'a GeneratorWitnessDatum) { fn fmt(&self, _s: &InternalWriterState<'_, I>, _f: &'_ mut Formatter<'_>) -> Result { unimplemented!() } } impl RenderAsRust for AdtDatum { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // When support for Self in structs is added, self_binding should be // changed to Some(0) let s = &s.add_debrujin_index(None); let value = self.binders.skip_binders(); // flags write_flags!( f, self.flags, AdtFlags { // Ordering matters upstream, fundamental, phantom_data } ); // repr 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))?; } // name 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), ", ")?; // where clauses if !value.where_clauses.is_empty() { let s = &s.add_indent(); write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; } else { write!(f, " ")?; } // body 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 RenderAsRust for Polarity { fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { if !self.is_positive() { write!(f, "!")?; } Ok(()) } } impl RenderAsRust for TraitDatum { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { let s = &s.add_debrujin_index(Some(0)); let value = self.binders.skip_binders(); // flags write_flags!( f, self.flags, TraitFlags { auto, marker, upstream, fundamental, non_enumerable, coinductive } ); // object safe if s.db().is_object_safe(self.id) { writeln!(f, "#[object_safe]")?; } // well-known 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::Generator => "generator", WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn", WellKnownTrait::Tuple => "tuple_trait", }; writeln!(f, "#[lang({})]", name)?; } // trait declaration 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, ", ")?; // where clauses if !value.where_clauses.is_empty() { let s = &s.add_indent(); write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; } else { write!(f, " ")?; } // body 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 RenderAsRust for ImplDatum { 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(); // annotations // #[upstream] // ^^^^^^^^^^^ // impl Foo for Bar where T: Baz { } if self.impl_type == ImplType::External { writeln!(f, "#[upstream]")?; } // impl keyword // impl Foo for Bar where T: Baz { } // ^^^^ write!(f, "impl")?; let trait_ref = &value.trait_ref; // generic binders // impl Foo for Bar where T: Baz // ^^^ write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; // trait, type and parameters // impl Foo for Bar where T: Baz { } // ^^^^^^^^^^^^^^^^^ let full_trait_name = display_type_with_generics( s, trait_ref.trait_id, // Ignore automatically added Self parameter by skipping first parameter &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) )?; // where clauses // impl Foo for Bar where T: Baz { } // ^^^^^^^^^^^^ if !value.where_clauses.is_empty() { let s = &s.add_indent(); write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; } else { write!(f, " ")?; } // body // impl Foo for Bar where T: Baz { } // ^^^ 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 RenderAsRust for OpaqueTyDatum { 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 RenderAsRust for AssociatedTyDatum { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // In lowering, a completely new empty environment is created for each // AssociatedTyDatum, and it's given generic parameters for each generic // parameter that its trait had. We want to map the new binders for // those generic parameters back into their original names. To do that, // first find their original names (trait_binder_names), then the names // they have inside the AssociatedTyDatum (assoc_ty_names_for_trait_params), // and then add that mapping to the WriterState when writing bounds and // where clauses. let trait_datum = s.db().trait_datum(self.trait_id); // inverted Debrujin indices for the trait's parameters in the trait // environment let trait_param_names_in_trait_env = s.binder_var_indices(&trait_datum.binders.binders); let s = &s.add_debrujin_index(None); // inverted Debrujin indices for the trait's parameters in the // associated type environment let param_names_in_assoc_ty_env = s .binder_var_indices(&self.binders.binders) .collect::>(); // inverted Debrujin indices to render the trait's parameters in the // associated type environment 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, ); // rendered names for the associated type's generics in the associated // type environment let binder_display_in_assoc_ty = s .binder_var_display(&self.binders.binders) .collect::>(); 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, ": ")?; } // bounds is `A: V, B: D, C = E`? // type Foo: X + Y + Z; let bounds = datum_bounds .bounds .iter() .map(|bound| bound.display(s).to_string()) .format(" + "); write!(f, "{}", bounds)?; // where_clause is 'X: Y, Z: D' // type Foo<...>: ... where X: Y, Z: D; // note: it's a quantified clause b/c we could have `for<'a> T: Foo<'a>` // within 'where' 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 RenderAsRust for AssociatedTyValue { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // see comments for a similar empty env operation in AssociatedTyDatum's // impl of RenderAsRust. 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::>(); 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::>(); 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 RenderAsRust for FnDefDatum { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { let s = &s.add_debrujin_index(None); let bound_datum = self.binders.skip_binders(); // declaration // fn foo(arg: u32, arg2: T) -> Result where T: Bar // ^^^^^^ write!(f, "fn {}", s.db().fn_def_name(self.id))?; // binders // fn foo(arg: u32, arg2: T) -> Result where T: Bar // ^^^ 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(); // arguments // fn foo(arg: u32, arg2: T) -> Result where T: Bar // ^^^^^^^^^^^^^^^^^^^ let arguments = inputs_and_output .argument_types .iter() .enumerate() .map(|(idx, arg)| format!("arg_{}: {}", idx, arg.display(s))) .format(", "); write!(f, "({})", arguments)?; // return Type // fn foo(arg: u32, arg2: T) -> Result where T: Bar // ^^^^^^^^^^^^^ write!(f, " -> {}", inputs_and_output.return_type.display(s))?; } // where clause // fn foo(arg: u32, arg2: T) -> Result where T: Bar // ^^^^^^^^^^^^ 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(()) } }