1
1
# Proof trees
2
2
3
- The trait solver can optionally emit a "proof tree", a tree representation of what
4
- happened while trying to prove a goal.
5
-
6
- The used datastructures for which are currently stored in
7
- [ ` rustc_middle::traits::solve::inspect ` ] .
8
-
9
- ## What are they used for
10
-
11
- There are 3 intended uses for proof trees. These uses are not yet implemented as
12
- the representation of proof trees itself is currently still unstable.
13
-
14
- They should be used by type system diagnostics to get information about
15
- why a goal failed or remained ambiguous. They should be used by rustdoc to get the
16
- auto-trait implementations for user-defined types, and they should be usable to
17
- vastly improve the debugging experience of the trait solver.
18
-
19
- For debugging you can use ` -Zdump-solver-proof-tree ` which dumps the proof tree
20
- for all goals proven by the trait solver in the current session.
21
-
22
- ## Requirements and design constraints for proof trees
3
+ While the trait solver itself only returns whether a goal holds and the necessary
4
+ constraints, we sometimes also want to know what happened while trying to prove
5
+ it. While the trait solver should generally be treated as a black box by the rest
6
+ of the compiler, we cannot completely ignore its internals and provide "proof trees"
7
+ as an interface for this. To use them you implement the [ ` ProofTreeVisitor ` ] trait,
8
+ see its existing implementations for examples. The most notable uses are to compute
9
+ the [ intercrate ambiguity causes for coherence errors] [ intercrate-ambig ] ,
10
+ [ improving trait solver errors] [ solver-errors ] , and
11
+ [ eagerly inferring closure signatures] [ closure-sig ] .
12
+
13
+ ## Computing proof trees
23
14
24
15
The trait solver uses [ Canonicalization] and uses completely separate ` InferCtxt ` for
25
16
each nested goal. Both diagnostics and auto-traits in rustdoc need to correctly
@@ -29,22 +20,28 @@ canonicalize to `exists<T0> Vec<Vec<T0>>: Debug`, instantiate that goal as
29
20
` exists<T0> Vec<T0>: Debug ` , instantiate this as ` Vec<?0>: Debug ` which then results
30
21
in a nested ` ?0: Debug ` goal which is ambiguous.
31
22
32
- We need to be able to figure out that ` ?x ` corresponds to ` ?0 ` in the nested queries.
33
-
34
- The debug output should also accurately represent the state at each point in the solver.
35
- This means that even though a goal like ` fn(?0): FnOnce(i32) ` infers ` ?0 ` to ` i32 ` , the
36
- proof tree should still store ` fn(<some infer var>): FnOnce(i32) ` instead of
37
- ` fn(i32): FnOnce(i32) ` until we actually infer ` ?0 ` to ` i32 ` .
38
-
39
- ## The current implementation and how to extract information from proof trees.
40
-
41
- Proof trees will be quite involved as they should accurately represent everything the
42
- trait solver does, which includes fixpoint iterations and performance optimizations.
43
-
44
- We intend to provide a lossy user interface for all usecases.
45
-
46
- TODO: implement this user interface and explain how it can be used here.
47
-
48
-
49
- [ `rustc_middle::traits::solve::inspect` ] : https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/traits/solve/inspect/index.html
23
+ We compute proof trees by passing a [ ` ProofTreeBuilder ` ] to the search graph which is
24
+ converting the evaluation steps of the trait solver into a tree. When storing any
25
+ data using inference variables or placeholders, the data is canonicalized together
26
+ with the list of all unconstrained inference variables created during this computation.
27
+ This [ ` CanonicalState ` ] is then instantiated in the parent inference context while
28
+ walking the proof tree, using the list of inference variables to connect all the
29
+ canonicalized values created during this evaluation.
30
+
31
+ ## Debugging the solver
32
+
33
+ We previously also tried to use proof trees to debug the solver implementation. This
34
+ has different design requirements than analyzing it programmatically. The recommended
35
+ way to debug the trait solver is by using ` tracing ` . The trait solver only uses the
36
+ ` debug ` tracing level for its general 'shape' and ` trace ` for additional detail.
37
+ ` RUSTC_LOG=rustc_next_trait_solver=debug ` therefore gives you a general outline
38
+ and ` RUSTC_LOG=rustc_next_trait_solver=trace ` can then be used if more precise
39
+ information is required.
40
+
41
+ [ `ProofTreeVisitor` ] : https://github.com/rust-lang/rust/blob/d6c8169c186ab16a3404cd0d0866674018e8a19e/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs#L403
42
+ [ `ProofTreeBuilder` ] : https://github.com/rust-lang/rust/blob/d6c8169c186ab16a3404cd0d0866674018e8a19e/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs#L40
43
+ [ `CanonicalState` ] : https://github.com/rust-lang/rust/blob/d6c8169c186ab16a3404cd0d0866674018e8a19e/compiler/rustc_type_ir/src/solve/inspect.rs#L31-L47
44
+ [ intercrate-ambig ] : https://github.com/rust-lang/rust/blob/d6c8169c186ab16a3404cd0d0866674018e8a19e/compiler/rustc_trait_selection/src/traits/coherence.rs#L742-L748
45
+ [ solver-errors ] : https://github.com/rust-lang/rust/blob/d6c8169c186ab16a3404cd0d0866674018e8a19e/compiler/rustc_trait_selection/src/solve/fulfill.rs#L343-L356
46
+ [ closure-sig ] : https://github.com/rust-lang/rust/blob/d6c8169c186ab16a3404cd0d0866674018e8a19e/compiler/rustc_hir_typeck/src/closure.rs#L333-L339
50
47
[ Canonicalization ] : ./canonicalization.md
0 commit comments