@@ -11,7 +11,7 @@ use rustc_middle::ty;
1111use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
1212
1313use super :: eval_ctxt:: GenerateProofTree ;
14- use super :: { Certainty , InferCtxtEvalExt } ;
14+ use super :: { Certainty , Goal , InferCtxtEvalExt } ;
1515
1616/// A trait engine using the new trait solver.
1717///
@@ -32,11 +32,34 @@ pub struct FulfillmentCtxt<'tcx> {
3232 /// gets rolled back. Because of this we explicitly check that we only
3333 /// use the context in exactly this snapshot.
3434 usable_in_snapshot : usize ,
35+
36+ track_obligations : bool ,
3537}
3638
3739impl < ' tcx > FulfillmentCtxt < ' tcx > {
3840 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+ }
4063 }
4164}
4265
@@ -52,7 +75,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
5275 }
5376
5477 fn collect_remaining_errors ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < FulfillmentError < ' tcx > > {
55- self . obligations
78+ let errors = self
79+ . obligations
5680 . drain ( ..)
5781 . map ( |obligation| {
5882 let code = infcx. probe ( |_| {
@@ -81,7 +105,9 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
81105 root_obligation : obligation,
82106 }
83107 } )
84- . collect ( )
108+ . collect ( ) ;
109+
110+ errors
85111 }
86112
87113 fn select_where_possible ( & mut self , infcx : & InferCtxt < ' tcx > ) -> Vec < FulfillmentError < ' tcx > > {
@@ -95,65 +121,66 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
95121 let mut has_changed = false ;
96122 for obligation in mem:: take ( & mut self . obligations ) {
97123 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+ } ;
157184 // Push any nested goals that we get from unifying our canonical response
158185 // with our obligation onto the fulfillment context.
159186 self . obligations . extend ( nested_goals. into_iter ( ) . map ( |goal| {
0 commit comments