2020-03-27 12:56:18 -05:00
|
|
|
//! Implementation of Chalk debug helper functions using TLS.
|
|
|
|
use std::fmt;
|
|
|
|
|
2020-10-30 12:57:16 -05:00
|
|
|
use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication};
|
2020-04-13 07:39:44 -05:00
|
|
|
use itertools::Itertools;
|
2020-03-27 12:56:18 -05:00
|
|
|
|
2020-09-12 21:24:19 -05:00
|
|
|
use super::{from_chalk, Interner, TypeAliasAsAssocType};
|
2020-10-30 12:57:16 -05:00
|
|
|
use crate::{db::HirDatabase, CallableDefId};
|
|
|
|
use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
|
2020-03-27 12:56:18 -05:00
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) use unsafe_tls::{set_current_program, with_current_program};
|
2020-03-27 12:56:18 -05:00
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase);
|
2020-03-27 12:56:18 -05:00
|
|
|
|
|
|
|
impl DebugContext<'_> {
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_struct_id(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
2020-05-22 10:50:58 -05:00
|
|
|
id: super::AdtId,
|
2020-03-27 12:56:18 -05:00
|
|
|
f: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
2020-10-30 12:57:16 -05:00
|
|
|
let name = match id.0 {
|
|
|
|
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)
|
2020-03-27 12:56:18 -05:00
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_trait_id(
|
2020-03-27 12:56:18 -05:00
|
|
|
&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)
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_assoc_type_id(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
id: super::AssocTypeId,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
2020-09-12 21:24:19 -05:00
|
|
|
let type_alias: TypeAliasId = from_chalk::<TypeAliasAsAssocType, _>(self.0, id).0;
|
2020-03-27 12:56:18 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_opaque_ty_id(
|
2020-04-18 06:36:35 -05:00
|
|
|
&self,
|
|
|
|
opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish()
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_alias(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
2020-04-18 06:36:35 -05:00
|
|
|
alias_ty: &AliasTy<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
match alias_ty {
|
|
|
|
AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt),
|
|
|
|
AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_projection_ty(
|
2020-04-18 06:36:35 -05:00
|
|
|
&self,
|
|
|
|
projection_ty: &chalk_ir::ProjectionTy<Interner>,
|
2020-03-27 12:56:18 -05:00
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
2020-09-12 21:24:19 -05:00
|
|
|
let type_alias: TypeAliasId =
|
|
|
|
from_chalk::<TypeAliasAsAssocType, _>(self.0, projection_ty.associated_ty_id).0;
|
2020-03-27 12:56:18 -05:00
|
|
|
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_);
|
2020-07-11 08:22:46 -05:00
|
|
|
let params = projection_ty.substitution.as_slice(&Interner);
|
2020-04-13 07:39:44 -05:00
|
|
|
write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?;
|
|
|
|
if params.len() > 1 {
|
|
|
|
write!(
|
|
|
|
fmt,
|
|
|
|
"<{}>",
|
|
|
|
¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
write!(fmt, ">::{}", type_alias_data.name)
|
2020-03-27 12:56:18 -05:00
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_opaque_ty(
|
2020-04-18 06:36:35 -05:00
|
|
|
&self,
|
|
|
|
opaque_ty: &chalk_ir::OpaqueTy<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", opaque_ty.opaque_ty_id)
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_ty(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
ty: &chalk_ir::Ty<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", ty.data(&Interner))
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_lifetime(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
lifetime: &Lifetime<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", lifetime.data(&Interner))
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_generic_arg(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
2020-05-22 09:40:42 -05:00
|
|
|
parameter: &GenericArg<Interner>,
|
2020-03-27 12:56:18 -05:00
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_goal(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
goal: &Goal<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
let goal_data = goal.data(&Interner);
|
|
|
|
write!(fmt, "{:?}", goal_data)
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_goals(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
goals: &Goals<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", goals.debug(&Interner))
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_program_clause_implication(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
pci: &ProgramClauseImplication<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", pci.debug(&Interner))
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_substitution(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
substitution: &chalk_ir::Substitution<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", substitution.debug(&Interner))
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_separator_trait_ref(
|
2020-03-27 12:56:18 -05:00
|
|
|
&self,
|
|
|
|
separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
|
|
|
write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
|
|
|
|
}
|
2020-05-22 11:05:48 -05:00
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_fn_def_id(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
2020-05-22 11:15:53 -05:00
|
|
|
fn_def_id: chalk_ir::FnDefId<Interner>,
|
2020-05-22 11:05:48 -05:00
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> Result<(), fmt::Error> {
|
2020-07-16 06:15:00 -05:00
|
|
|
let def: CallableDefId = from_chalk(self.0, fn_def_id);
|
2020-05-22 11:15:53 -05:00
|
|
|
let name = match def {
|
2020-07-16 06:15:00 -05:00
|
|
|
CallableDefId::FunctionId(ff) => self.0.function_data(ff).name.clone(),
|
|
|
|
CallableDefId::StructId(s) => self.0.struct_data(s).name.clone(),
|
|
|
|
CallableDefId::EnumVariantId(e) => {
|
2020-05-22 11:15:53 -05:00
|
|
|
let enum_data = self.0.enum_data(e.parent);
|
|
|
|
enum_data.variants[e.local_id].name.clone()
|
|
|
|
}
|
|
|
|
};
|
|
|
|
match def {
|
2020-07-16 06:15:00 -05:00
|
|
|
CallableDefId::FunctionId(_) => write!(fmt, "{{fn {}}}", name),
|
|
|
|
CallableDefId::StructId(_) | CallableDefId::EnumVariantId(_) => {
|
2020-05-22 11:15:53 -05:00
|
|
|
write!(fmt, "{{ctor {}}}", name)
|
|
|
|
}
|
|
|
|
}
|
2020-05-22 11:05:48 -05:00
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_const(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
_constant: &chalk_ir::Const<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "const")
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_variable_kinds(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
variable_kinds: &chalk_ir::VariableKinds<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", variable_kinds.as_slice(&Interner))
|
|
|
|
}
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_variable_kinds_with_angles(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
variable_kinds: &chalk_ir::VariableKinds<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner))
|
|
|
|
}
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_canonical_var_kinds(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner))
|
|
|
|
}
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_program_clause(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
clause: &chalk_ir::ProgramClause<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", clause.data(&Interner))
|
|
|
|
}
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_program_clauses(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
clauses: &chalk_ir::ProgramClauses<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", clauses.as_slice(&Interner))
|
|
|
|
}
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn debug_quantified_where_clauses(
|
2020-05-22 11:05:48 -05:00
|
|
|
&self,
|
|
|
|
clauses: &chalk_ir::QuantifiedWhereClauses<Interner>,
|
|
|
|
fmt: &mut fmt::Formatter<'_>,
|
|
|
|
) -> fmt::Result {
|
|
|
|
write!(fmt, "{:?}", clauses.as_slice(&Interner))
|
|
|
|
}
|
2020-03-27 12:56:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
mod unsafe_tls {
|
|
|
|
use super::DebugContext;
|
|
|
|
use crate::db::HirDatabase;
|
|
|
|
use scoped_tls::scoped_thread_local;
|
|
|
|
|
|
|
|
scoped_thread_local!(static PROGRAM: DebugContext);
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn with_current_program<R>(
|
2020-03-27 12:56:18 -05:00
|
|
|
op: impl for<'a> FnOnce(Option<&'a DebugContext<'a>>) -> R,
|
|
|
|
) -> R {
|
|
|
|
if PROGRAM.is_set() {
|
|
|
|
PROGRAM.with(|prog| op(Some(prog)))
|
|
|
|
} else {
|
|
|
|
op(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 06:13:32 -06:00
|
|
|
pub(crate) fn set_current_program<OP, R>(p: &dyn HirDatabase, op: OP) -> R
|
2020-03-27 12:56:18 -05:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|