blob: e3402bf67bc86e16a10f929a1d3aacd9741d9af0 [file] [log] [blame]
//! 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<I: Interner> RenderAsRust<I> for TyKind<I> {
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 <X as Iterator>::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, "<fn_def>"),
TyKind::Closure(..) => write!(f, "<closure>"),
TyKind::Foreign(..) => write!(f, "<foreign>"),
TyKind::Coroutine(..) => write!(f, "<coroutine>"),
TyKind::CoroutineWitness(..) => write!(f, "<coroutine_witness>"),
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, "<placeholder>"),
}
}
}
impl<I: Interner> RenderAsRust<I> for AliasTy<I> {
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<I: Interner> RenderAsRust<I> for ProjectionTy<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
// <X as Y<A1, A2, A3>>::Z<B1, B2, B3>
// 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<I: Interner> RenderAsRust<I> for OpaqueTy<I> {
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<I: Interner> RenderAsRust<I> for FnPointer<I> {
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<I: Interner> RenderAsRust<I> 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<I: Interner> RenderAsRust<I> for LifetimeData<I> {
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<I: Interner> RenderAsRust<I> for ConstData<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
write!(f, "{}", self.value.display(s))
}
}
impl<I: Interner> RenderAsRust<I> for ConstValue<I> {
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, "<const placeholder>"),
ConstValue::Concrete(value) => write!(f, "{:?}", value.interned),
}
}
}
impl<I: Interner> RenderAsRust<I> for GenericArgData<I> {
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<I: Interner> RenderAsRust<I> for Ty<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
// delegate to TyKind
self.kind(s.db().interner()).fmt(s, f)
}
}
impl<I: Interner> RenderAsRust<I> for Lifetime<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
// delegate to LifetimeData
self.data(s.db().interner()).fmt(s, f)
}
}
impl<I: Interner> RenderAsRust<I> for Const<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result {
self.data(s.db().interner()).fmt(s, f)
}
}
impl<I: Interner> RenderAsRust<I> for GenericArg<I> {
fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result {
// delegate to GenericArgData
self.data(s.db().interner()).fmt(s, f)
}
}