use rustc_type_ir::{solve::GoalSource, solve::inspect::GoalEvaluation}; use serde_derive::{Deserialize, Serialize}; use crate::next_solver::inspect::{InspectCandidate, InspectGoal}; use crate::next_solver::{AnyImplId, infer::InferCtxt}; use crate::next_solver::{DbInterner, Span}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProofTreeData { pub goal: String, pub result: String, pub depth: usize, pub candidates: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CandidateData { pub kind: String, pub result: String, pub impl_header: Option, pub nested_goals: Vec, } pub fn dump_proof_tree_structured<'db>( proof_tree: GoalEvaluation>, _span: Span, infcx: &InferCtxt<'db>, ) -> ProofTreeData { let goal_eval = InspectGoal::new(infcx, 0, proof_tree, None, GoalSource::Misc); let mut serializer = ProofTreeSerializer::new(infcx); serializer.serialize_goal(&goal_eval) } struct ProofTreeSerializer<'a, 'db> { infcx: &'a InferCtxt<'db>, } impl<'a, 'db> ProofTreeSerializer<'a, 'db> { fn new(infcx: &'a InferCtxt<'db>) -> Self { Self { infcx } } fn serialize_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> ProofTreeData { let candidates = goal.candidates(); let candidates_data: Vec = candidates.iter().map(|c| self.serialize_candidate(c)).collect(); ProofTreeData { goal: format!("{:?}", goal.goal()), result: format!("{:?}", goal.result()), depth: goal.depth(), candidates: candidates_data, } } fn serialize_candidate(&mut self, candidate: &InspectCandidate<'_, 'db>) -> CandidateData { let kind = candidate.kind(); let impl_header = self.get_impl_header(candidate); let mut nested = Vec::new(); self.infcx.probe(|_| { for nested_goal in candidate.instantiate_nested_goals() { nested.push(self.serialize_goal(&nested_goal)); } }); CandidateData { kind: format!("{:?}", kind), result: format!("{:?}", candidate.result()), impl_header, nested_goals: nested, } } fn get_impl_header(&self, candidate: &InspectCandidate<'_, 'db>) -> Option { use rustc_type_ir::solve::inspect::ProbeKind; match candidate.kind() { ProbeKind::TraitCandidate { source, .. } => { use hir_def::{Lookup, src::HasSource}; use rustc_type_ir::solve::CandidateSource; let db = self.infcx.interner.db; match source { CandidateSource::Impl(impl_def_id) => match impl_def_id { AnyImplId::ImplId(impl_def_id) => { let impl_src = impl_def_id.lookup(db).source(db); Some(impl_src.value.to_string()) } AnyImplId::BuiltinDeriveImplId(impl_id) => { let impl_loc = impl_id.loc(db); let adt_src = match impl_loc.adt { hir_def::AdtId::StructId(adt) => { adt.loc(db).source(db).value.to_string() } hir_def::AdtId::UnionId(adt) => { adt.loc(db).source(db).value.to_string() } hir_def::AdtId::EnumId(adt) => { adt.loc(db).source(db).value.to_string() } }; Some(format!("#[derive(${})]\n{}", impl_loc.trait_.name(), adt_src)) } }, _ => None, } } _ => None, } } }