//! Writer logic for types. //! //! Contains the highly-recursive logic for writing `TyKind` and its variants. use std::fmt::{Formatter, Result}; 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, }; impl RenderAsRust for TyKind { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { let interner = s.db().interner(); match self { TyKind::Adt(sid, substitution) => { write!(f, "{}", sid.display(s))?; let parameters = substitution.as_slice(interner); let parameters = parameters.iter().map(|param| param.display(s)); write_joined_non_empty_list!(f, "<{}>", parameters, ", ") } TyKind::AssociatedType(assoc_type_id, substitution) => { // (Iterator::Item)(x) // should be written in Rust as ::Item let datum = s.db().associated_ty_data(*assoc_type_id); assert!( substitution .iter(interner) .filter_map(move |p| p.ty(interner)) .count() >= 1, "AssociatedType should have at least 1 parameter" ); write!( f, "<{} as {}>::{}", substitution .iter(interner) .filter_map(move |p| p.ty(interner)) .next() .unwrap() .display(s), datum.trait_id.display(s), datum.id.display(s), )?; let params = substitution.as_slice(interner); write_joined_non_empty_list!( f, "<{}>", params[1..].iter().map(|ty| ty.display(s)), "," ) } TyKind::Scalar(scalar) => write!(f, "{}", scalar.display(s)), TyKind::Tuple(arity, substitution) => { write!( f, "({}{})", substitution .as_slice(interner) .iter() .map(|p| p.display(s)) .format(", "), if *arity == 1 { // need trailing single comma "," } else { "" } ) } TyKind::OpaqueType(opaque_ty_id, substitution) => write!( f, "{}", display_type_with_generics(s, *opaque_ty_id, substitution.as_slice(interner)) ), TyKind::Raw(mutability, ty) => match mutability { Mutability::Mut => write!(f, "*mut {}", ty.display(s)), Mutability::Not => write!(f, "*const {}", ty.display(s)), }, TyKind::Ref(mutability, lifetime, ty) => match mutability { Mutability::Mut => write!(f, "&{} mut {}", lifetime.display(s), ty.display(s)), Mutability::Not => write!(f, "&{} {}", lifetime.display(s), ty.display(s)), }, TyKind::Str => write!(f, "str"), TyKind::Slice(ty) => write!(f, "[{}]", ty.display(s)), TyKind::Error => write!(f, "{{error}}"), TyKind::Never => write!(f, "!"), // FIXME: write out valid types for these variants TyKind::FnDef(..) => write!(f, ""), TyKind::Closure(..) => write!(f, ""), TyKind::Foreign(..) => write!(f, ""), TyKind::Generator(..) => write!(f, ""), TyKind::GeneratorWitness(..) => write!(f, ""), TyKind::Array(ty, const_) => write!(f, "[{}; {}]", ty.display(s), const_.display(s),), TyKind::Dyn(dyn_ty) => { // the lifetime needs to be outside of the bounds, so we // introduce a new scope for the bounds { let s = &s.add_debrujin_index(None); // dyn_ty.bounds.binders creates a Self binding for the trait let bounds = dyn_ty.bounds.skip_binders(); write!( f, "dyn {}", display_self_where_clauses_as_bounds(s, bounds.as_slice(interner)), )?; } write!(f, " + {}", dyn_ty.lifetime.display(s))?; Ok(()) } TyKind::BoundVar(bound_var) => write!(f, "{}", s.display_bound_var(bound_var)), TyKind::InferenceVar(_, _) => write!(f, "_"), TyKind::Alias(alias_ty) => alias_ty.fmt(s, f), TyKind::Function(func) => func.fmt(s, f), TyKind::Placeholder(_) => write!(f, ""), } } } impl RenderAsRust for AliasTy { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { match self { AliasTy::Projection(projection_ty) => projection_ty.fmt(s, f), AliasTy::Opaque(opaque_ty) => opaque_ty.fmt(s, f), } } } impl RenderAsRust for ProjectionTy { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // >::Z // Now, we split out A*, Y/Z and B*: // trait_params is X, A1, A2, A3, // assoc_type_params is B1, B2, B3, // assoc_ty_datum stores info about Y and Z. let (assoc_ty_datum, trait_params, assoc_type_params) = s.db().split_projection(self); write!( f, "<{} as {}>::{}", trait_params[0].display(s), display_type_with_generics(s, assoc_ty_datum.trait_id, &trait_params[1..]), assoc_ty_datum.id.display(s), )?; write_joined_non_empty_list!( f, "<{}>", assoc_type_params.iter().map(|param| param.display(s)), ", " )?; Ok(()) } } impl RenderAsRust for OpaqueTy { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { let interner = s.db().interner(); write!( f, "{}", display_type_with_generics(s, self.opaque_ty_id, self.substitution.as_slice(interner),) ) } } impl RenderAsRust for FnPointer { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { let interner = s.db().interner(); let s = &s.add_debrujin_index(None); if self.num_binders > 0 { write!( f, "for<{}> ", (0..self.num_binders) .map(|n| format!("'{}", s.name_for_introduced_bound_var(n))) .format(", ") )?; } let parameters = self.substitution.0.as_slice(interner); write!( f, "fn({}) -> {}", parameters[..parameters.len() - 1] .iter() .map(|param| param.display(s)) .format(", "), parameters[parameters.len() - 1].display(s), ) } } impl RenderAsRust for Scalar { fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { use chalk_ir::{FloatTy::*, IntTy::*, UintTy::*}; write!( f, "{}", match self { Scalar::Bool => "bool", Scalar::Char => "char", Scalar::Int(int) => match int { Isize => "isize", I8 => "i8", I16 => "i16", I32 => "i32", I64 => "i64", I128 => "i128", }, Scalar::Uint(uint) => match uint { Usize => "usize", U8 => "u8", U16 => "u16", U32 => "u32", U64 => "u64", U128 => "u128", }, Scalar::Float(float) => match float { F32 => "f32", F64 => "f64", }, } ) } } impl RenderAsRust for LifetimeData { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { match self { LifetimeData::BoundVar(v) => write!(f, "'{}", s.display_bound_var(v)), LifetimeData::InferenceVar(_) => write!(f, "'_"), LifetimeData::Placeholder(ix) => { write!(f, "'_placeholder_{}_{}", ix.ui.counter, ix.idx) } LifetimeData::Static => write!(f, "'static"), LifetimeData::Erased => write!(f, "'_"), // Matching the void ensures at compile time that this code is // unreachable LifetimeData::Phantom(void, _) => match *void {}, } } } impl RenderAsRust for ConstData { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { write!(f, "{}", self.value.display(s)) } } impl RenderAsRust for ConstValue { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { match self { ConstValue::BoundVar(v) => write!(f, "{}", s.display_bound_var(v)), ConstValue::InferenceVar(_) => write!(f, "_"), ConstValue::Placeholder(_) => write!(f, ""), ConstValue::Concrete(value) => write!(f, "{:?}", value.interned), } } } impl RenderAsRust for GenericArgData { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { match self { GenericArgData::Ty(ty) => write!(f, "{}", ty.display(s)), GenericArgData::Lifetime(lt) => write!(f, "{}", lt.display(s)), GenericArgData::Const(const_ty) => write!(f, "{}", const_ty.display(s)), } } } impl RenderAsRust for Ty { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // delegate to TyKind self.kind(s.db().interner()).fmt(s, f) } } impl RenderAsRust for Lifetime { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // delegate to LifetimeData self.data(s.db().interner()).fmt(s, f) } } impl RenderAsRust for Const { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { self.data(s.db().interner()).fmt(s, f) } } impl RenderAsRust for GenericArg { fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { // delegate to GenericArgData self.data(s.db().interner()).fmt(s, f) } }