10
10
11
11
use dep_graph:: DepGraph ;
12
12
use infer:: { InferCtxt , InferOk } ;
13
- use ty:: { self , Ty , TypeFoldable , ToPolyTraitRef , TyCtxt } ;
13
+ use ty:: { self , Ty , TypeFoldable , ToPolyTraitRef , TyCtxt , ToPredicate } ;
14
+ use ty:: subst:: { Substs , Subst } ;
14
15
use rustc_data_structures:: obligation_forest:: { ObligationForest , Error } ;
15
16
use rustc_data_structures:: obligation_forest:: { ForestObligation , ObligationProcessor } ;
16
17
use std:: marker:: PhantomData ;
@@ -22,10 +23,9 @@ use util::nodemap::{FnvHashSet, NodeMap};
22
23
use super :: CodeAmbiguity ;
23
24
use super :: CodeProjectionError ;
24
25
use super :: CodeSelectionError ;
25
- use super :: FulfillmentError ;
26
- use super :: FulfillmentErrorCode ;
27
- use super :: ObligationCause ;
28
- use super :: PredicateObligation ;
26
+ use super :: { FulfillmentError , FulfillmentErrorCode , SelectionError } ;
27
+ use super :: { ObligationCause , BuiltinDerivedObligation } ;
28
+ use super :: { PredicateObligation , TraitObligation , Obligation } ;
29
29
use super :: project;
30
30
use super :: select:: SelectionContext ;
31
31
use super :: Unimplemented ;
@@ -51,6 +51,7 @@ pub struct GlobalFulfilledPredicates<'tcx> {
51
51
/// along. Once all type inference constraints have been generated, the
52
52
/// method `select_all_or_error` can be used to report any remaining
53
53
/// ambiguous cases as errors.
54
+
54
55
pub struct FulfillmentContext < ' tcx > {
55
56
// A list of all obligations that have been registered with this
56
57
// fulfillment context.
@@ -84,6 +85,10 @@ pub struct FulfillmentContext<'tcx> {
84
85
// obligations (otherwise, it's easy to fail to walk to a
85
86
// particular node-id).
86
87
region_obligations : NodeMap < Vec < RegionObligation < ' tcx > > > ,
88
+
89
+ // A list of obligations that need to be deferred to
90
+ // a later time for them to be properly fulfilled.
91
+ deferred_obligations : Vec < DeferredObligation < ' tcx > > ,
87
92
}
88
93
89
94
#[ derive( Clone ) ]
@@ -99,13 +104,98 @@ pub struct PendingPredicateObligation<'tcx> {
99
104
pub stalled_on : Vec < Ty < ' tcx > > ,
100
105
}
101
106
107
+ /// An obligation which cannot be fulfilled in the context
108
+ /// it was registered in, such as auto trait obligations on
109
+ /// `impl Trait`, which require the concrete type to be
110
+ /// available, only guaranteed after finishing type-checking.
111
+ #[ derive( Clone , Debug ) ]
112
+ pub struct DeferredObligation < ' tcx > {
113
+ pub predicate : ty:: PolyTraitPredicate < ' tcx > ,
114
+ pub cause : ObligationCause < ' tcx >
115
+ }
116
+
117
+ impl < ' a , ' gcx , ' tcx > DeferredObligation < ' tcx > {
118
+ /// If possible, create a `DeferredObligation` from
119
+ /// a trait predicate which had failed selection,
120
+ /// but could succeed later.
121
+ pub fn from_select_error ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
122
+ obligation : & TraitObligation < ' tcx > ,
123
+ selection_err : & SelectionError < ' tcx > )
124
+ -> Option < DeferredObligation < ' tcx > > {
125
+ if let Unimplemented = * selection_err {
126
+ if DeferredObligation :: must_defer ( tcx, & obligation. predicate ) {
127
+ return Some ( DeferredObligation {
128
+ predicate : obligation. predicate . clone ( ) ,
129
+ cause : obligation. cause . clone ( )
130
+ } ) ;
131
+ }
132
+ }
133
+
134
+ None
135
+ }
136
+
137
+ /// Returns true if the given trait predicate can be
138
+ /// fulfilled at a later time.
139
+ pub fn must_defer ( tcx : TyCtxt < ' a , ' gcx , ' tcx > ,
140
+ predicate : & ty:: PolyTraitPredicate < ' tcx > )
141
+ -> bool {
142
+ // Auto trait obligations on `impl Trait`.
143
+ if tcx. trait_has_default_impl ( predicate. def_id ( ) ) {
144
+ let substs = predicate. skip_binder ( ) . trait_ref . substs ;
145
+ if substs. types . as_slice ( ) . len ( ) == 1 && substs. regions . is_empty ( ) {
146
+ if let ty:: TyAnon ( ..) = predicate. skip_binder ( ) . self_ty ( ) . sty {
147
+ return true ;
148
+ }
149
+ }
150
+ }
151
+
152
+ false
153
+ }
154
+
155
+ /// If possible, return the nested obligations required
156
+ /// to fulfill this obligation.
157
+ pub fn try_select ( & self , tcx : TyCtxt < ' a , ' gcx , ' tcx > )
158
+ -> Option < Vec < PredicateObligation < ' tcx > > > {
159
+ if let ty:: TyAnon ( def_id, substs) = self . predicate . skip_binder ( ) . self_ty ( ) . sty {
160
+ // We can resolve the `impl Trait` to its concrete type.
161
+ if let Some ( ty_scheme) = tcx. opt_lookup_item_type ( def_id) {
162
+ let concrete_ty = ty_scheme. ty . subst ( tcx, substs) ;
163
+ let concrete_substs = Substs :: new_trait ( vec ! [ ] , vec ! [ ] , concrete_ty) ;
164
+ let predicate = ty:: TraitRef {
165
+ def_id : self . predicate . def_id ( ) ,
166
+ substs : tcx. mk_substs ( concrete_substs)
167
+ } . to_predicate ( ) ;
168
+
169
+ let original_obligation = Obligation :: new ( self . cause . clone ( ) ,
170
+ self . predicate . clone ( ) ) ;
171
+ let cause = original_obligation. derived_cause ( BuiltinDerivedObligation ) ;
172
+ return Some ( vec ! [ Obligation :: new( cause, predicate) ] ) ;
173
+ }
174
+ }
175
+
176
+ None
177
+ }
178
+
179
+ /// Return the `PredicateObligation` this was created from.
180
+ pub fn to_obligation ( & self ) -> PredicateObligation < ' tcx > {
181
+ let predicate = ty:: Predicate :: Trait ( self . predicate . clone ( ) ) ;
182
+ Obligation :: new ( self . cause . clone ( ) , predicate)
183
+ }
184
+
185
+ /// Return an error as if this obligation had failed.
186
+ pub fn to_error ( & self ) -> FulfillmentError < ' tcx > {
187
+ FulfillmentError :: new ( self . to_obligation ( ) , CodeSelectionError ( Unimplemented ) )
188
+ }
189
+ }
190
+
102
191
impl < ' a , ' gcx , ' tcx > FulfillmentContext < ' tcx > {
103
192
/// Creates a new fulfillment context.
104
193
pub fn new ( ) -> FulfillmentContext < ' tcx > {
105
194
FulfillmentContext {
106
195
predicates : ObligationForest :: new ( ) ,
107
196
rfc1592_obligations : Vec :: new ( ) ,
108
197
region_obligations : NodeMap ( ) ,
198
+ deferred_obligations : vec ! [ ] ,
109
199
}
110
200
}
111
201
@@ -224,10 +314,16 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
224
314
{
225
315
self . select_where_possible ( infcx) ?;
226
316
317
+ // Fail all of the deferred obligations that haven't
318
+ // been otherwise removed from the context.
319
+ let deferred_errors = self . deferred_obligations . iter ( )
320
+ . map ( |d| d. to_error ( ) ) ;
321
+
227
322
let errors: Vec < _ > =
228
323
self . predicates . to_errors ( CodeAmbiguity )
229
324
. into_iter ( )
230
325
. map ( |e| to_fulfillment_error ( e) )
326
+ . chain ( deferred_errors)
231
327
. collect ( ) ;
232
328
if errors. is_empty ( ) {
233
329
Ok ( ( ) )
@@ -248,6 +344,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
248
344
self . predicates . pending_obligations ( )
249
345
}
250
346
347
+ pub fn take_deferred_obligations ( & mut self ) -> Vec < DeferredObligation < ' tcx > > {
348
+ mem:: replace ( & mut self . deferred_obligations , vec ! [ ] )
349
+ }
350
+
251
351
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
252
352
/// only attempts to select obligations that haven't been seen before.
253
353
fn select ( & mut self , selcx : & mut SelectionContext < ' a , ' gcx , ' tcx > )
@@ -261,9 +361,10 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
261
361
262
362
// Process pending obligations.
263
363
let outcome = self . predicates . process_obligations ( & mut FulfillProcessor {
264
- selcx : selcx,
265
- region_obligations : & mut self . region_obligations ,
266
- rfc1592_obligations : & mut self . rfc1592_obligations
364
+ selcx : selcx,
365
+ region_obligations : & mut self . region_obligations ,
366
+ rfc1592_obligations : & mut self . rfc1592_obligations ,
367
+ deferred_obligations : & mut self . deferred_obligations
267
368
} ) ;
268
369
debug ! ( "select: outcome={:?}" , outcome) ;
269
370
@@ -298,7 +399,8 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
298
399
struct FulfillProcessor < ' a , ' b : ' a , ' gcx : ' tcx , ' tcx : ' b > {
299
400
selcx : & ' a mut SelectionContext < ' b , ' gcx , ' tcx > ,
300
401
region_obligations : & ' a mut NodeMap < Vec < RegionObligation < ' tcx > > > ,
301
- rfc1592_obligations : & ' a mut Vec < PredicateObligation < ' tcx > >
402
+ rfc1592_obligations : & ' a mut Vec < PredicateObligation < ' tcx > > ,
403
+ deferred_obligations : & ' a mut Vec < DeferredObligation < ' tcx > >
302
404
}
303
405
304
406
impl < ' a , ' b , ' gcx , ' tcx > ObligationProcessor for FulfillProcessor < ' a , ' b , ' gcx , ' tcx > {
@@ -312,7 +414,8 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
312
414
process_predicate ( self . selcx ,
313
415
obligation,
314
416
self . region_obligations ,
315
- self . rfc1592_obligations )
417
+ self . rfc1592_obligations ,
418
+ self . deferred_obligations )
316
419
. map ( |os| os. map ( |os| os. into_iter ( ) . map ( |o| PendingPredicateObligation {
317
420
obligation : o,
318
421
stalled_on : vec ! [ ]
@@ -354,7 +457,8 @@ fn process_predicate<'a, 'gcx, 'tcx>(
354
457
selcx : & mut SelectionContext < ' a , ' gcx , ' tcx > ,
355
458
pending_obligation : & mut PendingPredicateObligation < ' tcx > ,
356
459
region_obligations : & mut NodeMap < Vec < RegionObligation < ' tcx > > > ,
357
- rfc1592_obligations : & mut Vec < PredicateObligation < ' tcx > > )
460
+ rfc1592_obligations : & mut Vec < PredicateObligation < ' tcx > > ,
461
+ deferred_obligations : & mut Vec < DeferredObligation < ' tcx > > )
358
462
-> Result < Option < Vec < PredicateObligation < ' tcx > > > ,
359
463
FulfillmentErrorCode < ' tcx > >
360
464
{
@@ -422,7 +526,22 @@ fn process_predicate<'a, 'gcx, 'tcx>(
422
526
Err ( selection_err) => {
423
527
info ! ( "selecting trait `{:?}` at depth {} yielded Err" ,
424
528
data, obligation. recursion_depth) ;
425
- Err ( CodeSelectionError ( selection_err) )
529
+
530
+ let defer = DeferredObligation :: from_select_error ( selcx. tcx ( ) ,
531
+ & trait_obligation,
532
+ & selection_err) ;
533
+ if let Some ( deferred_obligation) = defer {
534
+ if let Some ( nested) = deferred_obligation. try_select ( selcx. tcx ( ) ) {
535
+ Ok ( Some ( nested) )
536
+ } else {
537
+ // Pretend that the obligation succeeded,
538
+ // but record it for later.
539
+ deferred_obligations. push ( deferred_obligation) ;
540
+ Ok ( Some ( vec ! [ ] ) )
541
+ }
542
+ } else {
543
+ Err ( CodeSelectionError ( selection_err) )
544
+ }
426
545
}
427
546
}
428
547
}
@@ -629,6 +748,12 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> {
629
748
// already has the required read edges, so we don't need
630
749
// to add any more edges here.
631
750
if data. is_global ( ) {
751
+ // Don't cache predicates which were fulfilled
752
+ // by deferring them for later fulfillment.
753
+ if DeferredObligation :: must_defer ( tcx, data) {
754
+ return ;
755
+ }
756
+
632
757
if let Some ( data) = tcx. lift_to_global ( data) {
633
758
if self . set . insert ( data. clone ( ) ) {
634
759
debug ! ( "add_if_global: global predicate `{:?}` added" , data) ;
0 commit comments