ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
};
+pub(super) mod tls;
+
#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
pub struct Interner;
type Identifier = TypeAliasId;
type DefId = InternId;
- // FIXME: implement these
fn debug_struct_id(
- _type_kind_id: chalk_ir::StructId<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ type_kind_id: StructId,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
}
- fn debug_trait_id(
- _type_kind_id: chalk_ir::TraitId<Self>,
- _fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- None
+ fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
+ tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
}
- fn debug_assoc_type_id(
- _id: chalk_ir::AssocTypeId<Self>,
- _fmt: &mut fmt::Formatter<'_>,
- ) -> Option<fmt::Result> {
- None
+ fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
+ tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
}
fn debug_alias(
- _projection: &chalk_ir::AliasTy<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ alias: &chalk_ir::AliasTy<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
}
- fn debug_ty(_ty: &chalk_ir::Ty<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- None
+ fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
+ tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
}
fn debug_lifetime(
- _lifetime: &chalk_ir::Lifetime<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ lifetime: &chalk_ir::Lifetime<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt)))
}
fn debug_parameter(
- _parameter: &Parameter<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ parameter: &Parameter<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_parameter(parameter, fmt)))
}
- fn debug_goal(_goal: &Goal<Self>, _fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
- None
+ fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
+ tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt)))
}
fn debug_goals(
- _goals: &chalk_ir::Goals<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ goals: &chalk_ir::Goals<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt)))
}
fn debug_program_clause_implication(
- _pci: &chalk_ir::ProgramClauseImplication<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ pci: &chalk_ir::ProgramClauseImplication<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt)))
}
fn debug_application_ty(
- _application_ty: &chalk_ir::ApplicationTy<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ application_ty: &chalk_ir::ApplicationTy<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_application_ty(application_ty, fmt)))
}
fn debug_substitution(
- _substitution: &chalk_ir::Substitution<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ substitution: &chalk_ir::Substitution<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt)))
}
fn debug_separator_trait_ref(
- _separator_trait_ref: &chalk_ir::SeparatorTraitRef<Self>,
- _fmt: &mut fmt::Formatter<'_>,
+ separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
) -> Option<fmt::Result> {
- None
+ tls::with_current_program(|prog| {
+ Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
+ })
}
fn intern_ty(&self, ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
--- /dev/null
+//! Implementation of Chalk debug helper functions using TLS.
+use std::fmt;
+
+use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName};
+
+use super::{from_chalk, Interner};
+use crate::{db::HirDatabase, CallableDef, TypeCtor};
+use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
+
+pub use unsafe_tls::{set_current_program, with_current_program};
+
+pub struct DebugContext<'a>(&'a (dyn HirDatabase + 'a));
+
+impl DebugContext<'_> {
+ pub fn debug_struct_id(
+ &self,
+ id: super::StructId,
+ f: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ let type_ctor: TypeCtor = from_chalk(self.0, TypeName::Struct(id));
+ match type_ctor {
+ TypeCtor::Bool => write!(f, "bool")?,
+ TypeCtor::Char => write!(f, "char")?,
+ TypeCtor::Int(t) => write!(f, "{}", t)?,
+ TypeCtor::Float(t) => write!(f, "{}", t)?,
+ TypeCtor::Str => write!(f, "str")?,
+ TypeCtor::Slice => write!(f, "slice")?,
+ TypeCtor::Array => write!(f, "array")?,
+ TypeCtor::RawPtr(m) => write!(f, "*{}", m.as_keyword_for_ptr())?,
+ TypeCtor::Ref(m) => write!(f, "&{}", m.as_keyword_for_ref())?,
+ TypeCtor::Never => write!(f, "!")?,
+ TypeCtor::Tuple { .. } => {
+ write!(f, "()")?;
+ }
+ TypeCtor::FnPtr { .. } => {
+ write!(f, "fn")?;
+ }
+ TypeCtor::FnDef(def) => {
+ let name = match def {
+ CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(),
+ CallableDef::StructId(s) => self.0.struct_data(s).name.clone(),
+ CallableDef::EnumVariantId(e) => {
+ let enum_data = self.0.enum_data(e.parent);
+ enum_data.variants[e.local_id].name.clone()
+ }
+ };
+ match def {
+ CallableDef::FunctionId(_) => write!(f, "{{fn {}}}", name)?,
+ CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => {
+ write!(f, "{{ctor {}}}", name)?
+ }
+ }
+ }
+ TypeCtor::Adt(def_id) => {
+ let name = match def_id {
+ AdtId::StructId(it) => self.0.struct_data(it).name.clone(),
+ AdtId::UnionId(it) => self.0.union_data(it).name.clone(),
+ AdtId::EnumId(it) => self.0.enum_data(it).name.clone(),
+ };
+ write!(f, "{}", name)?;
+ }
+ TypeCtor::AssociatedType(type_alias) => {
+ let trait_ = match type_alias.lookup(self.0.upcast()).container {
+ AssocContainerId::TraitId(it) => it,
+ _ => panic!("not an associated type"),
+ };
+ let trait_name = self.0.trait_data(trait_).name.clone();
+ let name = self.0.type_alias_data(type_alias).name.clone();
+ write!(f, "{}::{}", trait_name, name)?;
+ }
+ TypeCtor::Closure { def, expr } => {
+ write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?;
+ }
+ }
+ Ok(())
+ }
+
+ pub fn debug_trait_id(
+ &self,
+ id: super::TraitId,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ let trait_: hir_def::TraitId = from_chalk(self.0, id);
+ let trait_data = self.0.trait_data(trait_);
+ write!(fmt, "{}", trait_data.name)
+ }
+
+ pub fn debug_assoc_type_id(
+ &self,
+ id: super::AssocTypeId,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ let type_alias: TypeAliasId = from_chalk(self.0, id);
+ let type_alias_data = self.0.type_alias_data(type_alias);
+ let trait_ = match type_alias.lookup(self.0.upcast()).container {
+ AssocContainerId::TraitId(t) => t,
+ _ => panic!("associated type not in trait"),
+ };
+ let trait_data = self.0.trait_data(trait_);
+ write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
+ }
+
+ pub fn debug_alias(
+ &self,
+ alias: &AliasTy<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ let type_alias: TypeAliasId = from_chalk(self.0, alias.associated_ty_id);
+ let type_alias_data = self.0.type_alias_data(type_alias);
+ let trait_ = match type_alias.lookup(self.0.upcast()).container {
+ AssocContainerId::TraitId(t) => t,
+ _ => panic!("associated type not in trait"),
+ };
+ let trait_data = self.0.trait_data(trait_);
+ let params = alias.substitution.parameters(&Interner);
+ write!(
+ fmt,
+ "<{:?} as {}<{:?}>>::{}",
+ ¶ms[0],
+ trait_data.name,
+ ¶ms[1..],
+ type_alias_data.name
+ )
+ }
+
+ pub fn debug_ty(
+ &self,
+ ty: &chalk_ir::Ty<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", ty.data(&Interner))
+ }
+
+ pub fn debug_lifetime(
+ &self,
+ lifetime: &Lifetime<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", lifetime.data(&Interner))
+ }
+
+ pub fn debug_parameter(
+ &self,
+ parameter: &Parameter<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
+ }
+
+ pub fn debug_goal(
+ &self,
+ goal: &Goal<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ let goal_data = goal.data(&Interner);
+ write!(fmt, "{:?}", goal_data)
+ }
+
+ pub fn debug_goals(
+ &self,
+ goals: &Goals<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", goals.debug(&Interner))
+ }
+
+ pub fn debug_program_clause_implication(
+ &self,
+ pci: &ProgramClauseImplication<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", pci.debug(&Interner))
+ }
+
+ pub fn debug_application_ty(
+ &self,
+ application_ty: &chalk_ir::ApplicationTy<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", application_ty.debug(&Interner))
+ }
+
+ pub fn debug_substitution(
+ &self,
+ substitution: &chalk_ir::Substitution<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", substitution.debug(&Interner))
+ }
+
+ pub fn debug_separator_trait_ref(
+ &self,
+ separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
+ fmt: &mut fmt::Formatter<'_>,
+ ) -> Result<(), fmt::Error> {
+ write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
+ }
+}
+
+mod unsafe_tls {
+ use super::DebugContext;
+ use crate::db::HirDatabase;
+ use scoped_tls::scoped_thread_local;
+
+ scoped_thread_local!(static PROGRAM: DebugContext);
+
+ pub fn with_current_program<R>(
+ op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
+ ) -> R {
+ if PROGRAM.is_set() {
+ PROGRAM.with(|prog| op(Some(prog)))
+ } else {
+ op(None)
+ }
+ }
+
+ pub fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
+ where
+ OP: FnOnce() -> R,
+ {
+ let ctx = DebugContext(p);
+ // we're transmuting the lifetime in the DebugContext to static. This is
+ // fine because we only keep the reference for the lifetime of this
+ // function, *and* the only way to access the context is through
+ // `with_current_program`, which hides the lifetime through the `for`
+ // type.
+ let static_p: &DebugContext<'static> =
+ unsafe { std::mem::transmute::<&DebugContext, &DebugContext<'static>>(&ctx) };
+ PROGRAM.set(static_p, || op())
+ }
+}