@@ -11,7 +11,7 @@ use rustc_middle::ty;
11
11
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
12
12
13
13
use super :: eval_ctxt:: GenerateProofTree ;
14
- use super :: { Certainty , InferCtxtEvalExt } ;
14
+ use super :: { Certainty , Goal , InferCtxtEvalExt } ;
15
15
16
16
/// A trait engine using the new trait solver.
17
17
///
@@ -32,11 +32,34 @@ pub struct FulfillmentCtxt<'tcx> {
32
32
/// gets rolled back. Because of this we explicitly check that we only
33
33
/// use the context in exactly this snapshot.
34
34
usable_in_snapshot : usize ,
35
+
36
+ track_obligations : bool ,
35
37
}
36
38
37
39
impl < ' tcx > FulfillmentCtxt < ' tcx > {
38
40
pub fn new ( infcx : & InferCtxt < ' tcx > ) -> FulfillmentCtxt < ' tcx > {
39
- FulfillmentCtxt { obligations : Vec :: new ( ) , usable_in_snapshot : infcx. num_open_snapshots ( ) }
41
+ FulfillmentCtxt {
42
+ obligations : Vec :: new ( ) ,
43
+ usable_in_snapshot : infcx. num_open_snapshots ( ) ,
44
+ track_obligations : infcx. tcx . sess . opts . unstable_opts . track_trait_obligations ,
45
+ }
46
+ }
47
+
48
+ fn track_evaluated_obligation (
49
+ & self ,
50
+ infcx : & InferCtxt < ' tcx > ,
51
+ obligation : & PredicateObligation < ' tcx > ,
52
+ result : & Result < ( bool , Certainty , Vec < Goal < ' tcx , ty:: Predicate < ' tcx > > > ) , NoSolution > ,
53
+ ) {
54
+ if self . track_obligations {
55
+ if let Some ( inspector) = infcx. obligation_inspector . get ( ) {
56
+ let result = match result {
57
+ Ok ( ( _, c, _) ) => Ok ( * c) ,
58
+ Err ( NoSolution ) => Err ( NoSolution ) ,
59
+ } ;
60
+ ( inspector) ( infcx, & obligation, result) ;
61
+ }
62
+ }
40
63
}
41
64
}
42
65
@@ -52,7 +75,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
52
75
}
53
76
54
77
fn collect_remaining_errors ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < FulfillmentError < ' tcx > > {
55
- self . obligations
78
+ let errors = self
79
+ . obligations
56
80
. drain ( ..)
57
81
. map ( |obligation| {
58
82
let code = infcx. probe ( |_| {
@@ -81,7 +105,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
81
105
root_obligation : obligation,
82
106
}
83
107
} )
84
- . collect ( )
108
+ . collect ( ) ;
109
+
110
+ errors
85
111
}
86
112
87
113
fn select_where_possible ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < FulfillmentError < ' tcx > > {
@@ -95,65 +121,66 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
95
121
let mut has_changed = false ;
96
122
for obligation in mem:: take ( & mut self . obligations ) {
97
123
let goal = obligation. clone ( ) . into ( ) ;
98
- let ( changed, certainty, nested_goals) =
99
- match infcx. evaluate_root_goal ( goal, GenerateProofTree :: IfEnabled ) . 0 {
100
- Ok ( result) => result,
101
- Err ( NoSolution ) => {
102
- errors. push ( FulfillmentError {
103
- obligation : obligation. clone ( ) ,
104
- code : match goal. predicate . kind ( ) . skip_binder ( ) {
105
- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( _) ) => {
106
- FulfillmentErrorCode :: CodeProjectionError (
107
- // FIXME: This could be a `Sorts` if the term is a type
108
- MismatchedProjectionTypes { err : TypeError :: Mismatch } ,
109
- )
110
- }
111
- ty:: PredicateKind :: NormalizesTo ( ..) => {
112
- FulfillmentErrorCode :: CodeProjectionError (
113
- MismatchedProjectionTypes { err : TypeError :: Mismatch } ,
114
- )
115
- }
116
- ty:: PredicateKind :: AliasRelate ( _, _, _) => {
117
- FulfillmentErrorCode :: CodeProjectionError (
118
- MismatchedProjectionTypes { err : TypeError :: Mismatch } ,
119
- )
120
- }
121
- ty:: PredicateKind :: Subtype ( pred) => {
122
- let ( a, b) = infcx. instantiate_binder_with_placeholders (
123
- goal. predicate . kind ( ) . rebind ( ( pred. a , pred. b ) ) ,
124
- ) ;
125
- let expected_found = ExpectedFound :: new ( true , a, b) ;
126
- FulfillmentErrorCode :: CodeSubtypeError (
127
- expected_found,
128
- TypeError :: Sorts ( expected_found) ,
129
- )
130
- }
131
- ty:: PredicateKind :: Coerce ( pred) => {
132
- let ( a, b) = infcx. instantiate_binder_with_placeholders (
133
- goal. predicate . kind ( ) . rebind ( ( pred. a , pred. b ) ) ,
134
- ) ;
135
- let expected_found = ExpectedFound :: new ( false , a, b) ;
136
- FulfillmentErrorCode :: CodeSubtypeError (
137
- expected_found,
138
- TypeError :: Sorts ( expected_found) ,
139
- )
140
- }
141
- ty:: PredicateKind :: Clause ( _)
142
- | ty:: PredicateKind :: ObjectSafe ( _)
143
- | ty:: PredicateKind :: Ambiguous => {
144
- FulfillmentErrorCode :: CodeSelectionError (
145
- SelectionError :: Unimplemented ,
146
- )
147
- }
148
- ty:: PredicateKind :: ConstEquate ( ..) => {
149
- bug ! ( "unexpected goal: {goal:?}" )
150
- }
151
- } ,
152
- root_obligation : obligation,
153
- } ) ;
154
- continue ;
155
- }
156
- } ;
124
+ let result = infcx. evaluate_root_goal ( goal, GenerateProofTree :: IfEnabled ) . 0 ;
125
+ self . track_evaluated_obligation ( infcx, & obligation, & result) ;
126
+ let ( changed, certainty, nested_goals) = match result {
127
+ Ok ( result) => result,
128
+ Err ( NoSolution ) => {
129
+ errors. push ( FulfillmentError {
130
+ obligation : obligation. clone ( ) ,
131
+ code : match goal. predicate . kind ( ) . skip_binder ( ) {
132
+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( _) ) => {
133
+ FulfillmentErrorCode :: CodeProjectionError (
134
+ // FIXME: This could be a `Sorts` if the term is a type
135
+ MismatchedProjectionTypes { err : TypeError :: Mismatch } ,
136
+ )
137
+ }
138
+ ty:: PredicateKind :: NormalizesTo ( ..) => {
139
+ FulfillmentErrorCode :: CodeProjectionError (
140
+ MismatchedProjectionTypes { err : TypeError :: Mismatch } ,
141
+ )
142
+ }
143
+ ty:: PredicateKind :: AliasRelate ( _, _, _) => {
144
+ FulfillmentErrorCode :: CodeProjectionError (
145
+ MismatchedProjectionTypes { err : TypeError :: Mismatch } ,
146
+ )
147
+ }
148
+ ty:: PredicateKind :: Subtype ( pred) => {
149
+ let ( a, b) = infcx. instantiate_binder_with_placeholders (
150
+ goal. predicate . kind ( ) . rebind ( ( pred. a , pred. b ) ) ,
151
+ ) ;
152
+ let expected_found = ExpectedFound :: new ( true , a, b) ;
153
+ FulfillmentErrorCode :: CodeSubtypeError (
154
+ expected_found,
155
+ TypeError :: Sorts ( expected_found) ,
156
+ )
157
+ }
158
+ ty:: PredicateKind :: Coerce ( pred) => {
159
+ let ( a, b) = infcx. instantiate_binder_with_placeholders (
160
+ goal. predicate . kind ( ) . rebind ( ( pred. a , pred. b ) ) ,
161
+ ) ;
162
+ let expected_found = ExpectedFound :: new ( false , a, b) ;
163
+ FulfillmentErrorCode :: CodeSubtypeError (
164
+ expected_found,
165
+ TypeError :: Sorts ( expected_found) ,
166
+ )
167
+ }
168
+ ty:: PredicateKind :: Clause ( _)
169
+ | ty:: PredicateKind :: ObjectSafe ( _)
170
+ | ty:: PredicateKind :: Ambiguous => {
171
+ FulfillmentErrorCode :: CodeSelectionError (
172
+ SelectionError :: Unimplemented ,
173
+ )
174
+ }
175
+ ty:: PredicateKind :: ConstEquate ( ..) => {
176
+ bug ! ( "unexpected goal: {goal:?}" )
177
+ }
178
+ } ,
179
+ root_obligation : obligation,
180
+ } ) ;
181
+ continue ;
182
+ }
183
+ } ;
157
184
// Push any nested goals that we get from unifying our canonical response
158
185
// with our obligation onto the fulfillment context.
159
186
self . obligations . extend ( nested_goals. into_iter ( ) . map ( |goal| {
0 commit comments