88// option. This file may not be copied, modified, or distributed
99// except according to those terms.
1010
11- use middle:: infer:: { mod , InferCtxt } ;
11+ use middle:: infer:: { InferCtxt } ;
1212use middle:: mem_categorization:: Typer ;
13- use middle:: ty:: { mod, AsPredicate , RegionEscape , Ty , ToPolyTraitRef } ;
13+ use middle:: ty:: { mod, RegionEscape , Ty } ;
1414use std:: collections:: HashSet ;
1515use std:: collections:: hash_map:: Entry :: { Occupied , Vacant } ;
1616use std:: default:: Default ;
@@ -23,7 +23,6 @@ use super::CodeAmbiguity;
2323use super :: CodeProjectionError ;
2424use super :: CodeSelectionError ;
2525use super :: FulfillmentError ;
26- use super :: Obligation ;
2726use super :: ObligationCause ;
2827use super :: PredicateObligation ;
2928use super :: project;
@@ -110,6 +109,8 @@ impl<'tcx> FulfillmentContext<'tcx> {
110109 /// `projection_ty` again.
111110 pub fn normalize_projection_type < ' a > ( & mut self ,
112111 infcx : & InferCtxt < ' a , ' tcx > ,
112+ param_env : & ty:: ParameterEnvironment < ' tcx > ,
113+ typer : & Typer < ' tcx > ,
113114 projection_ty : ty:: ProjectionTy < ' tcx > ,
114115 cause : ObligationCause < ' tcx > )
115116 -> Ty < ' tcx >
@@ -121,18 +122,16 @@ impl<'tcx> FulfillmentContext<'tcx> {
121122
122123 // FIXME(#20304) -- cache
123124
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+ }
132131
133- debug ! ( "normalize_associated_type: result={}" , ty_var . repr( infcx. tcx) ) ;
132+ debug ! ( "normalize_associated_type: result={}" , normalized . value . repr( infcx. tcx) ) ;
134133
135- ty_var
134+ normalized . value
136135 }
137136
138137 pub fn register_builtin_bound < ' a > ( & mut self ,
@@ -143,7 +142,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
143142 {
144143 match predicate_for_builtin_bound ( infcx. tcx , cause, builtin_bound, 0 , ty) {
145144 Ok ( predicate) => {
146- self . register_predicate ( infcx, predicate) ;
145+ self . register_predicate_obligation ( infcx, predicate) ;
147146 }
148147 Err ( ErrorReported ) => { }
149148 }
@@ -158,10 +157,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
158157 register_region_obligation ( infcx. tcx , t_a, r_b, cause, & mut self . region_obligations ) ;
159158 }
160159
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 > )
164163 {
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+
165168 if !self . duplicate_set . insert ( obligation. predicate . clone ( ) ) {
166169 debug ! ( "register_predicate({}) -- already seen, skip" , obligation. repr( infcx. tcx) ) ;
167170 return ;
@@ -290,7 +293,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
290293 // Now go through all the successful ones,
291294 // registering any nested obligations for the future.
292295 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) ;
294297 }
295298 }
296299
@@ -398,104 +401,18 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
398401 project_obligation. repr( tcx) ,
399402 result. repr( tcx) ) ;
400403 match result {
401- Ok ( ( ) ) => {
404+ Ok ( Some ( obligations) ) => {
405+ new_obligations. extend ( obligations. into_iter ( ) ) ;
402406 true
403407 }
404- Err ( project:: ProjectionError :: TooManyCandidates ) => {
405- // Without more type information, we can't say much.
408+ Ok ( None ) => {
406409 false
407410 }
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) => {
477412 errors. push (
478413 FulfillmentError :: new (
479414 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) ) ) ;
499416 true
500417 }
501418 }
0 commit comments