@@ -1362,12 +1362,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
13621362 debug ! ( "assemble_candidates_from_object_ty: poly_trait_ref={:?}" ,
13631363 poly_trait_ref) ;
13641364
1365- // see whether the object trait can be upcast to the trait we are looking for
1366- let upcast_trait_refs = self . upcast ( poly_trait_ref, obligation) ;
1367- if upcast_trait_refs. len ( ) > 1 {
1365+ // Count only those upcast versions that match the trait-ref
1366+ // we are looking for. Specifically, do not only check for the
1367+ // correct trait, but also the correct type parameters.
1368+ // For example, we may be trying to upcast `Foo` to `Bar<i32>`,
1369+ // but `Foo` is declared as `trait Foo : Bar<u32>`.
1370+ let upcast_trait_refs = util:: supertraits ( self . tcx ( ) , poly_trait_ref)
1371+ . filter ( |upcast_trait_ref| self . infcx . probe ( |_| {
1372+ let upcast_trait_ref = upcast_trait_ref. clone ( ) ;
1373+ self . match_poly_trait_ref ( obligation, upcast_trait_ref) . is_ok ( )
1374+ } ) ) . count ( ) ;
1375+
1376+ if upcast_trait_refs > 1 {
13681377 // can be upcast in many ways; need more type information
13691378 candidates. ambiguous = true ;
1370- } else if upcast_trait_refs. len ( ) == 1 {
1379+ } else if upcast_trait_refs == 1 {
13711380 candidates. vec . push ( ObjectCandidate ) ;
13721381 }
13731382
@@ -2305,20 +2314,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
23052314 // be exactly one applicable trait-reference; if this were not
23062315 // the case, we would have reported an ambiguity error rather
23072316 // than successfully selecting one of the candidates.
2308- let upcast_trait_refs = self . upcast ( poly_trait_ref. clone ( ) , obligation) ;
2309- assert_eq ! ( upcast_trait_refs. len( ) , 1 ) ;
2310- let upcast_trait_ref = upcast_trait_refs. into_iter ( ) . next ( ) . unwrap ( ) ;
2317+ let mut upcast_trait_refs = util:: supertraits ( self . tcx ( ) , poly_trait_ref)
2318+ . map ( |upcast_trait_ref| {
2319+ ( upcast_trait_ref. clone ( ) , self . infcx . probe ( |_| {
2320+ self . match_poly_trait_ref ( obligation, upcast_trait_ref)
2321+ } ) . is_ok ( ) )
2322+ } ) ;
2323+ let mut upcast_trait_ref = None ;
2324+ let mut vtable_base = 0 ;
23112325
2312- match self . match_poly_trait_ref ( obligation, upcast_trait_ref. clone ( ) ) {
2313- Ok ( ( ) ) => { }
2314- Err ( ( ) ) => {
2315- self . tcx ( ) . sess . span_bug ( obligation. cause . span ,
2316- "failed to match trait refs" ) ;
2326+ while let Some ( ( supertrait, matches) ) = upcast_trait_refs. next ( ) {
2327+ if matches {
2328+ upcast_trait_ref = Some ( supertrait) ;
2329+ break ;
23172330 }
2331+ vtable_base += util:: count_own_vtable_entries ( self . tcx ( ) , supertrait) ;
23182332 }
2333+ assert ! ( upcast_trait_refs. all( |( _, matches) | !matches) ) ;
23192334
2320- VtableObjectData { object_ty : self_ty,
2321- upcast_trait_ref : upcast_trait_ref }
2335+ VtableObjectData {
2336+ upcast_trait_ref : upcast_trait_ref. unwrap ( ) ,
2337+ vtable_base : vtable_base
2338+ }
23222339 }
23232340
23242341 fn confirm_fn_pointer_candidate ( & mut self ,
@@ -2719,7 +2736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
27192736
27202737 /// Returns `Ok` if `poly_trait_ref` being true implies that the
27212738 /// obligation is satisfied.
2722- fn match_poly_trait_ref ( & mut self ,
2739+ fn match_poly_trait_ref ( & self ,
27232740 obligation : & TraitObligation < ' tcx > ,
27242741 poly_trait_ref : ty:: PolyTraitRef < ' tcx > )
27252742 -> Result < ( ) , ( ) >
@@ -2930,32 +2947,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
29302947 obligation. cause . clone ( )
29312948 }
29322949 }
2933-
2934- /// Upcasts an object trait-reference into those that match the obligation.
2935- fn upcast ( & mut self , obj_trait_ref : ty:: PolyTraitRef < ' tcx > , obligation : & TraitObligation < ' tcx > )
2936- -> Vec < ty:: PolyTraitRef < ' tcx > >
2937- {
2938- debug ! ( "upcast(obj_trait_ref={:?}, obligation={:?})" ,
2939- obj_trait_ref,
2940- obligation) ;
2941-
2942- let obligation_def_id = obligation. predicate . def_id ( ) ;
2943- let mut upcast_trait_refs = util:: upcast ( self . tcx ( ) , obj_trait_ref, obligation_def_id) ;
2944-
2945- // Retain only those upcast versions that match the trait-ref
2946- // we are looking for. In particular, we know that all of
2947- // `upcast_trait_refs` apply to the correct trait, but
2948- // possibly with incorrect type parameters. For example, we
2949- // may be trying to upcast `Foo` to `Bar<i32>`, but `Foo` is
2950- // declared as `trait Foo : Bar<u32>`.
2951- upcast_trait_refs. retain ( |upcast_trait_ref| {
2952- let upcast_trait_ref = upcast_trait_ref. clone ( ) ;
2953- self . infcx . probe ( |_| self . match_poly_trait_ref ( obligation, upcast_trait_ref) ) . is_ok ( )
2954- } ) ;
2955-
2956- debug ! ( "upcast: upcast_trait_refs={:?}" , upcast_trait_refs) ;
2957- upcast_trait_refs
2958- }
29592950}
29602951
29612952impl < ' tcx > SelectionCache < ' tcx > {
0 commit comments