Skip to main content

hir_ty/next_solver/
format_proof_tree.rs

1use rustc_type_ir::{solve::GoalSource, solve::inspect::GoalEvaluation};
2use serde_derive::{Deserialize, Serialize};
3
4use crate::next_solver::inspect::{InspectCandidate, InspectGoal};
5use crate::next_solver::{AnyImplId, infer::InferCtxt};
6use crate::{Span, next_solver::DbInterner};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct ProofTreeData {
10    pub goal: String,
11    pub result: String,
12    pub depth: usize,
13    pub candidates: Vec<CandidateData>,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct CandidateData {
18    pub kind: String,
19    pub result: String,
20    pub impl_header: Option<String>,
21    pub nested_goals: Vec<ProofTreeData>,
22}
23
24pub fn dump_proof_tree_structured<'db>(
25    proof_tree: GoalEvaluation<DbInterner<'db>>,
26    _span: Span,
27    infcx: &InferCtxt<'db>,
28) -> ProofTreeData {
29    let goal_eval = InspectGoal::new(infcx, 0, proof_tree, None, GoalSource::Misc);
30    let mut serializer = ProofTreeSerializer::new(infcx);
31    serializer.serialize_goal(&goal_eval)
32}
33
34struct ProofTreeSerializer<'a, 'db> {
35    infcx: &'a InferCtxt<'db>,
36}
37
38impl<'a, 'db> ProofTreeSerializer<'a, 'db> {
39    fn new(infcx: &'a InferCtxt<'db>) -> Self {
40        Self { infcx }
41    }
42
43    fn serialize_goal(&mut self, goal: &InspectGoal<'_, 'db>) -> ProofTreeData {
44        let candidates = goal.candidates();
45        let candidates_data: Vec<CandidateData> =
46            candidates.iter().map(|c| self.serialize_candidate(c)).collect();
47
48        ProofTreeData {
49            goal: format!("{:?}", goal.goal()),
50            result: format!("{:?}", goal.result()),
51            depth: goal.depth(),
52            candidates: candidates_data,
53        }
54    }
55
56    fn serialize_candidate(&mut self, candidate: &InspectCandidate<'_, 'db>) -> CandidateData {
57        let kind = candidate.kind();
58        let impl_header = self.get_impl_header(candidate);
59
60        let mut nested = Vec::new();
61        self.infcx.probe(|_| {
62            for nested_goal in candidate.instantiate_nested_goals(Span::Dummy) {
63                nested.push(self.serialize_goal(&nested_goal));
64            }
65        });
66
67        CandidateData {
68            kind: format!("{:?}", kind),
69            result: format!("{:?}", candidate.result()),
70            impl_header,
71            nested_goals: nested,
72        }
73    }
74
75    fn get_impl_header(&self, candidate: &InspectCandidate<'_, 'db>) -> Option<String> {
76        use rustc_type_ir::solve::inspect::ProbeKind;
77        match candidate.kind() {
78            ProbeKind::TraitCandidate { source, .. } => {
79                use hir_def::{Lookup, src::HasSource};
80                use rustc_type_ir::solve::CandidateSource;
81                let db = self.infcx.interner.db;
82                match source {
83                    CandidateSource::Impl(impl_def_id) => match impl_def_id {
84                        AnyImplId::ImplId(impl_def_id) => {
85                            let impl_src = impl_def_id.lookup(db).source(db);
86                            Some(impl_src.value.to_string())
87                        }
88                        AnyImplId::BuiltinDeriveImplId(impl_id) => {
89                            let impl_loc = impl_id.loc(db);
90                            let adt_src = match impl_loc.adt {
91                                hir_def::AdtId::StructId(adt) => {
92                                    adt.loc(db).source(db).value.to_string()
93                                }
94                                hir_def::AdtId::UnionId(adt) => {
95                                    adt.loc(db).source(db).value.to_string()
96                                }
97                                hir_def::AdtId::EnumId(adt) => {
98                                    adt.loc(db).source(db).value.to_string()
99                                }
100                            };
101                            Some(format!("#[derive(${})]\n{}", impl_loc.trait_.name(), adt_src))
102                        }
103                    },
104                    _ => None,
105                }
106            }
107            _ => None,
108        }
109    }
110}