1
1
use std:: mem;
2
2
3
+ use rustc_data_structures:: sync:: { Lock , Lrc } ;
3
4
use rustc_infer:: infer:: InferCtxt ;
4
5
use rustc_infer:: traits:: solve:: MaybeCause ;
5
6
use rustc_infer:: traits:: Obligation ;
6
7
use rustc_infer:: traits:: {
7
- query:: NoSolution , FulfillmentError , FulfillmentErrorCode , MismatchedProjectionTypes ,
8
- PredicateObligation , SelectionError , TraitEngine ,
8
+ query:: NoSolution , FulfilledObligation , FulfillmentError , FulfillmentErrorCode ,
9
+ MismatchedProjectionTypes , PredicateObligation , SelectionError , TraitEngine ,
9
10
} ;
10
11
use rustc_middle:: ty;
11
12
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
@@ -32,11 +33,40 @@ pub struct FulfillmentCtxt<'tcx> {
32
33
/// gets rolled back. Because of this we explicitly check that we only
33
34
/// use the context in exactly this snapshot.
34
35
usable_in_snapshot : usize ,
36
+
37
+ tracked_obligations : Option < Lrc < Lock < Vec < FulfilledObligation < ' tcx > > > > > ,
35
38
}
36
39
37
40
impl < ' tcx > FulfillmentCtxt < ' tcx > {
38
41
pub fn new ( infcx : & InferCtxt < ' tcx > ) -> FulfillmentCtxt < ' tcx > {
39
- FulfillmentCtxt { obligations : Vec :: new ( ) , usable_in_snapshot : infcx. num_open_snapshots ( ) }
42
+ let tracked_obligations = if infcx. tcx . sess . opts . unstable_opts . track_trait_obligations {
43
+ Some ( Lrc :: clone ( & infcx. fulfilled_obligations ) )
44
+ } else {
45
+ None
46
+ } ;
47
+
48
+ FulfillmentCtxt {
49
+ obligations : Vec :: new ( ) ,
50
+ usable_in_snapshot : infcx. num_open_snapshots ( ) ,
51
+ tracked_obligations,
52
+ }
53
+ }
54
+
55
+ fn track_fulfillment_errors < ' b , ' a : ' b > (
56
+ & ' a self ,
57
+ errors : impl IntoIterator < Item = & ' b FulfillmentError < ' tcx > > ,
58
+ ) {
59
+ if let Some ( tracked_obligations) = & self . tracked_obligations {
60
+ tracked_obligations. borrow_mut ( ) . extend (
61
+ errors. into_iter ( ) . map ( |error| FulfilledObligation :: Failure ( error. clone ( ) ) ) ,
62
+ ) ;
63
+ }
64
+ }
65
+
66
+ fn track_fulfillment_success ( & self , predicate : & PredicateObligation < ' tcx > ) {
67
+ if let Some ( tracked_obligations) = & self . tracked_obligations {
68
+ tracked_obligations. borrow_mut ( ) . push ( FulfilledObligation :: Success ( predicate. clone ( ) ) ) ;
69
+ }
40
70
}
41
71
}
42
72
@@ -52,7 +82,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
52
82
}
53
83
54
84
fn collect_remaining_errors ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < FulfillmentError < ' tcx > > {
55
- self . obligations
85
+ let errors = self
86
+ . obligations
56
87
. drain ( ..)
57
88
. map ( |obligation| {
58
89
let code = infcx. probe ( |_| {
@@ -81,7 +112,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
81
112
root_obligation : obligation,
82
113
}
83
114
} )
84
- . collect ( )
115
+ . collect ( ) ;
116
+
117
+ self . track_fulfillment_errors ( & errors) ;
118
+
119
+ errors
85
120
}
86
121
87
122
fn select_where_possible ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < FulfillmentError < ' tcx > > {
@@ -97,7 +132,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
97
132
let goal = obligation. clone ( ) . into ( ) ;
98
133
let ( changed, certainty, nested_goals) =
99
134
match infcx. evaluate_root_goal ( goal, GenerateProofTree :: IfEnabled ) . 0 {
100
- Ok ( result) => result,
135
+ Ok ( result) => {
136
+ self . track_fulfillment_success ( & obligation) ;
137
+ result
138
+ }
101
139
Err ( NoSolution ) => {
102
140
errors. push ( FulfillmentError {
103
141
obligation : obligation. clone ( ) ,
@@ -176,6 +214,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
176
214
}
177
215
}
178
216
217
+ self . track_fulfillment_errors ( & errors) ;
218
+
179
219
errors
180
220
}
181
221
0 commit comments