8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use middle:: infer:: { mod , InferCtxt } ;
11
+ use middle:: infer:: { InferCtxt } ;
12
12
use middle:: mem_categorization:: Typer ;
13
- use middle:: ty:: { mod, AsPredicate , RegionEscape , Ty , ToPolyTraitRef } ;
13
+ use middle:: ty:: { mod, RegionEscape , Ty } ;
14
14
use std:: collections:: HashSet ;
15
15
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
16
16
use std:: default:: Default ;
@@ -23,7 +23,6 @@ use super::CodeAmbiguity;
23
23
use super :: CodeProjectionError ;
24
24
use super :: CodeSelectionError ;
25
25
use super :: FulfillmentError ;
26
- use super :: Obligation ;
27
26
use super :: ObligationCause ;
28
27
use super :: PredicateObligation ;
29
28
use super :: project;
@@ -110,6 +109,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
110
109
/// `projection_ty` again.
111
110
pub fn normalize_projection_type < ' a > ( & mut self ,
112
111
infcx : & InferCtxt < ' a , ' tcx > ,
112
+ param_env : & ty:: ParameterEnvironment < ' tcx > ,
113
+ typer : & Typer < ' tcx > ,
113
114
projection_ty : ty:: ProjectionTy < ' tcx > ,
114
115
cause : ObligationCause < ' tcx > )
115
116
-> Ty < ' tcx >
@@ -121,18 +122,16 @@ impl<'tcx> FulfillmentContext<'tcx> {
121
122
122
123
// FIXME(#20304) -- cache
123
124
124
- let ty_var = infcx. next_ty_var ( ) ;
125
- let projection =
126
- ty:: Binder ( ty:: ProjectionPredicate {
127
- projection_ty : projection_ty,
128
- ty : ty_var
129
- } ) ;
130
- let obligation = Obligation :: new ( cause, projection. as_predicate ( ) ) ;
131
- self . register_predicate ( infcx, obligation) ;
125
+ let mut selcx = SelectionContext :: new ( infcx, param_env, typer) ;
126
+ let normalized = project:: normalize_projection_type ( & mut selcx, projection_ty, cause, 0 ) ;
127
+
128
+ for obligation in normalized. obligations . into_iter ( ) {
129
+ self . register_predicate_obligation ( infcx, obligation) ;
130
+ }
132
131
133
- debug ! ( "normalize_associated_type: result={}" , ty_var . repr( infcx. tcx) ) ;
132
+ debug ! ( "normalize_associated_type: result={}" , normalized . value . repr( infcx. tcx) ) ;
134
133
135
- ty_var
134
+ normalized . value
136
135
}
137
136
138
137
pub fn register_builtin_bound < ' a > ( & mut self ,
@@ -143,7 +142,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
143
142
{
144
143
match predicate_for_builtin_bound ( infcx. tcx , cause, builtin_bound, 0 , ty) {
145
144
Ok ( predicate) => {
146
- self . register_predicate ( infcx, predicate) ;
145
+ self . register_predicate_obligation ( infcx, predicate) ;
147
146
}
148
147
Err ( ErrorReported ) => { }
149
148
}
@@ -158,10 +157,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
158
157
register_region_obligation ( infcx. tcx , t_a, r_b, cause, & mut self . region_obligations ) ;
159
158
}
160
159
161
- pub fn register_predicate < ' a > ( & mut self ,
162
- infcx : & InferCtxt < ' a , ' tcx > ,
163
- obligation : PredicateObligation < ' tcx > )
160
+ pub fn register_predicate_obligation < ' a > ( & mut self ,
161
+ infcx : & InferCtxt < ' a , ' tcx > ,
162
+ obligation : PredicateObligation < ' tcx > )
164
163
{
164
+ // this helps to reduce duplicate errors, as well as making
165
+ // debug output much nicer to read and so on.
166
+ let obligation = infcx. resolve_type_vars_if_possible ( & obligation) ;
167
+
165
168
if !self . duplicate_set . insert ( obligation. predicate . clone ( ) ) {
166
169
debug ! ( "register_predicate({}) -- already seen, skip" , obligation. repr( infcx. tcx) ) ;
167
170
return ;
@@ -290,7 +293,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
290
293
// Now go through all the successful ones,
291
294
// registering any nested obligations for the future.
292
295
for new_obligation in new_obligations. into_iter ( ) {
293
- self . register_predicate ( selcx. infcx ( ) , new_obligation) ;
296
+ self . register_predicate_obligation ( selcx. infcx ( ) , new_obligation) ;
294
297
}
295
298
}
296
299
@@ -398,104 +401,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
398
401
project_obligation. repr( tcx) ,
399
402
result. repr( tcx) ) ;
400
403
match result {
401
- Ok ( ( ) ) => {
404
+ Ok ( Some ( obligations) ) => {
405
+ new_obligations. extend ( obligations. into_iter ( ) ) ;
402
406
true
403
407
}
404
- Err ( project:: ProjectionError :: TooManyCandidates ) => {
405
- // Without more type information, we can't say much.
408
+ Ok ( None ) => {
406
409
false
407
410
}
408
- Err ( project:: ProjectionError :: NoCandidate ) => {
409
- // This means that we have a type like `<T as
410
- // Trait>::name = U` but we couldn't find any more
411
- // information. This could just be that we're in a
412
- // function like:
413
- //
414
- // fn foo<T:Trait>(...)
415
- //
416
- // in which case this is not an error. But it
417
- // might also mean we're in a situation where we
418
- // don't actually know that `T : Trait` holds,
419
- // which would be weird (e.g., if `T` was not a
420
- // parameter type but a normal type, like `int`).
421
- //
422
- // So what we do is to (1) add a requirement that
423
- // `T : Trait` (just in case) and (2) try to unify
424
- // `U` with `<T as Trait>::name`.
425
-
426
- if !ty:: binds_late_bound_regions ( selcx. tcx ( ) , data) {
427
- // Check that `T : Trait` holds.
428
- let trait_ref = data. to_poly_trait_ref ( ) ;
429
- new_obligations. push ( obligation. with ( trait_ref. as_predicate ( ) ) ) ;
430
-
431
- // Fallback to `<T as Trait>::name`. If this
432
- // fails, then the output must be at least
433
- // somewhat constrained, and we cannot verify
434
- // that constraint, so yield an error.
435
- let ty_projection = ty:: mk_projection ( tcx,
436
- trait_ref. 0 . clone ( ) ,
437
- data. 0 . projection_ty . item_name ) ;
438
-
439
- debug ! ( "process_predicate: falling back to projection {}" ,
440
- ty_projection. repr( selcx. tcx( ) ) ) ;
441
-
442
- match infer:: mk_eqty ( selcx. infcx ( ) ,
443
- true ,
444
- infer:: EquatePredicate ( obligation. cause . span ) ,
445
- ty_projection,
446
- data. 0 . ty ) {
447
- Ok ( ( ) ) => { }
448
- Err ( _) => {
449
- debug ! ( "process_predicate: fallback failed to unify; error" ) ;
450
- errors. push (
451
- FulfillmentError :: new (
452
- obligation. clone ( ) ,
453
- CodeSelectionError ( Unimplemented ) ) ) ;
454
- }
455
- }
456
-
457
- true
458
- } else {
459
- // If we have something like
460
- //
461
- // for<'a> <T<'a> as Trait>::name == &'a int
462
- //
463
- // there is no "canonical form" for us to
464
- // make, so just report the lack of candidates
465
- // as an error.
466
-
467
- debug ! ( "process_predicate: can't fallback, higher-ranked" ) ;
468
- errors. push (
469
- FulfillmentError :: new (
470
- obligation. clone ( ) ,
471
- CodeSelectionError ( Unimplemented ) ) ) ;
472
-
473
- true
474
- }
475
- }
476
- Err ( project:: ProjectionError :: MismatchedTypes ( e) ) => {
411
+ Err ( err) => {
477
412
errors. push (
478
413
FulfillmentError :: new (
479
414
obligation. clone ( ) ,
480
- CodeProjectionError ( e) ) ) ;
481
- true
482
- }
483
- Err ( project:: ProjectionError :: TraitSelectionError ( _) ) => {
484
- // There was an error matching `T : Trait` (which
485
- // is a pre-requisite for `<T as Trait>::Name`
486
- // being valid). We could just report the error
487
- // now, but that tends to lead to double error
488
- // reports for the user (one for the obligation `T
489
- // : Trait`, typically incurred somewhere else,
490
- // and one from here). Instead, we'll create the
491
- // `T : Trait` obligation and add THAT as a
492
- // requirement. This will (eventually) trigger the
493
- // same error, but it will also wind up flagged as
494
- // a duplicate if another requirement that `T :
495
- // Trait` arises from somewhere else.
496
- let trait_predicate = data. to_poly_trait_ref ( ) ;
497
- let trait_obligation = obligation. with ( trait_predicate. as_predicate ( ) ) ;
498
- new_obligations. push ( trait_obligation) ;
415
+ CodeProjectionError ( err) ) ) ;
499
416
true
500
417
}
501
418
}
0 commit comments