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:: { InferCtxt } ;
11
+ use middle:: infer:: { mod , InferCtxt } ;
12
12
use middle:: mem_categorization:: Typer ;
13
- use middle:: ty:: { mod, RegionEscape , Ty } ;
13
+ use middle:: ty:: { mod, AsPredicate , RegionEscape , Ty , ToPolyTraitRef } ;
14
14
use std:: collections:: HashSet ;
15
15
use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
16
16
use std:: default:: Default ;
@@ -23,6 +23,7 @@ use super::CodeAmbiguity;
23
23
use super :: CodeProjectionError ;
24
24
use super :: CodeSelectionError ;
25
25
use super :: FulfillmentError ;
26
+ use super :: Obligation ;
26
27
use super :: ObligationCause ;
27
28
use super :: PredicateObligation ;
28
29
use super :: project;
@@ -109,8 +110,6 @@ impl<'tcx> FulfillmentContext<'tcx> {
109
110
/// `projection_ty` again.
110
111
pub fn normalize_projection_type < ' a > ( & mut self ,
111
112
infcx : & InferCtxt < ' a , ' tcx > ,
112
- param_env : & ty:: ParameterEnvironment < ' tcx > ,
113
- typer : & Typer < ' tcx > ,
114
113
projection_ty : ty:: ProjectionTy < ' tcx > ,
115
114
cause : ObligationCause < ' tcx > )
116
115
-> Ty < ' tcx >
@@ -122,16 +121,18 @@ impl<'tcx> FulfillmentContext<'tcx> {
122
121
123
122
// FIXME(#20304) -- cache
124
123
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
- }
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) ;
131
132
132
- debug ! ( "normalize_associated_type: result={}" , normalized . value . repr( infcx. tcx) ) ;
133
+ debug ! ( "normalize_associated_type: result={}" , ty_var . repr( infcx. tcx) ) ;
133
134
134
- normalized . value
135
+ ty_var
135
136
}
136
137
137
138
pub fn register_builtin_bound < ' a > ( & mut self ,
@@ -142,7 +143,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
142
143
{
143
144
match predicate_for_builtin_bound ( infcx. tcx , cause, builtin_bound, 0 , ty) {
144
145
Ok ( predicate) => {
145
- self . register_predicate_obligation ( infcx, predicate) ;
146
+ self . register_predicate ( infcx, predicate) ;
146
147
}
147
148
Err ( ErrorReported ) => { }
148
149
}
@@ -157,14 +158,10 @@ impl<'tcx> FulfillmentContext<'tcx> {
157
158
register_region_obligation ( infcx. tcx , t_a, r_b, cause, & mut self . region_obligations ) ;
158
159
}
159
160
160
- pub fn register_predicate_obligation < ' a > ( & mut self ,
161
- infcx : & InferCtxt < ' a , ' tcx > ,
162
- obligation : PredicateObligation < ' tcx > )
161
+ pub fn register_predicate < ' a > ( & mut self ,
162
+ infcx : & InferCtxt < ' a , ' tcx > ,
163
+ obligation : PredicateObligation < ' tcx > )
163
164
{
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
-
168
165
if !self . duplicate_set . insert ( obligation. predicate . clone ( ) ) {
169
166
debug ! ( "register_predicate({}) -- already seen, skip" , obligation. repr( infcx. tcx) ) ;
170
167
return ;
@@ -293,7 +290,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
293
290
// Now go through all the successful ones,
294
291
// registering any nested obligations for the future.
295
292
for new_obligation in new_obligations. into_iter ( ) {
296
- self . register_predicate_obligation ( selcx. infcx ( ) , new_obligation) ;
293
+ self . register_predicate ( selcx. infcx ( ) , new_obligation) ;
297
294
}
298
295
}
299
296
@@ -401,18 +398,104 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
401
398
project_obligation. repr( tcx) ,
402
399
result. repr( tcx) ) ;
403
400
match result {
404
- Ok ( Some ( obligations) ) => {
405
- new_obligations. extend ( obligations. into_iter ( ) ) ;
401
+ Ok ( ( ) ) => {
406
402
true
407
403
}
408
- Ok ( None ) => {
404
+ Err ( project:: ProjectionError :: TooManyCandidates ) => {
405
+ // Without more type information, we can't say much.
409
406
false
410
407
}
411
- Err ( err) => {
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) ) => {
412
477
errors. push (
413
478
FulfillmentError :: new (
414
479
obligation. clone ( ) ,
415
- CodeProjectionError ( err) ) ) ;
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) ;
416
499
true
417
500
}
418
501
}
0 commit comments