@@ -23,9 +23,10 @@ use crate::middle::resolve_lifetime as rl;
2323use crate :: middle:: weak_lang_items;
2424use rustc:: mir:: mono:: Linkage ;
2525use rustc:: ty:: query:: Providers ;
26- use rustc:: ty:: subst:: Substs ;
26+ use rustc:: ty:: subst:: { Subst , Substs } ;
2727use rustc:: ty:: util:: Discr ;
2828use rustc:: ty:: util:: IntTypeExt ;
29+ use rustc:: ty:: subst:: UnpackedKind ;
2930use rustc:: ty:: { self , AdtKind , ToPolyTraitRef , Ty , TyCtxt } ;
3031use rustc:: ty:: { ReprOptions , ToPredicate } ;
3132use rustc:: util:: captures:: Captures ;
@@ -1191,7 +1192,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
11911192 tcx. typeck_tables_of ( owner)
11921193 . concrete_existential_types
11931194 . get ( & def_id)
1194- . cloned ( )
1195+ . map ( |opaque| opaque . concrete_type )
11951196 . unwrap_or_else ( || {
11961197 // This can occur if some error in the
11971198 // owner fn prevented us from populating
@@ -1323,7 +1324,13 @@ fn find_existential_constraints<'a, 'tcx>(
13231324 struct ConstraintLocator < ' a , ' tcx : ' a > {
13241325 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
13251326 def_id : DefId ,
1326- found : Option < ( Span , ty:: Ty < ' tcx > ) > ,
1327+ // First found type span, actual type, mapping from the existential type's generic
1328+ // parameters to the concrete type's generic parameters
1329+ //
1330+ // The mapping is an index for each use site of a generic parameter in the concrete type
1331+ //
1332+ // The indices index into the generic parameters on the existential type.
1333+ found : Option < ( Span , ty:: Ty < ' tcx > , Vec < usize > ) > ,
13271334 }
13281335
13291336 impl < ' a , ' tcx > ConstraintLocator < ' a , ' tcx > {
@@ -1338,23 +1345,106 @@ fn find_existential_constraints<'a, 'tcx>(
13381345 . tcx
13391346 . typeck_tables_of ( def_id)
13401347 . concrete_existential_types
1341- . get ( & self . def_id )
1342- . cloned ( ) ;
1343- if let Some ( ty) = ty {
1348+ . get ( & self . def_id ) ;
1349+ if let Some ( ty:: ResolvedOpaqueTy { concrete_type, substs } ) = ty {
13441350 // FIXME(oli-obk): trace the actual span from inference to improve errors
13451351 let span = self . tcx . def_span ( def_id) ;
1346- if let Some ( ( prev_span, prev_ty) ) = self . found {
1347- if ty != prev_ty {
1352+ // used to quickly look up the position of a generic parameter
1353+ let mut index_map: FxHashMap < ty:: ParamTy , usize > = FxHashMap :: default ( ) ;
1354+ // skip binder is ok, since we only use this to find generic parameters and their
1355+ // positions.
1356+ for ( idx, subst) in substs. iter ( ) . enumerate ( ) {
1357+ if let UnpackedKind :: Type ( ty) = subst. unpack ( ) {
1358+ if let ty:: Param ( p) = ty. sty {
1359+ if index_map. insert ( p, idx) . is_some ( ) {
1360+ // there was already an entry for `p`, meaning a generic parameter
1361+ // was used twice
1362+ self . tcx . sess . span_err (
1363+ span,
1364+ & format ! ( "defining existential type use restricts existential \
1365+ type by using the generic parameter `{}` twice", p. name) ,
1366+ ) ;
1367+ return ;
1368+ }
1369+ } else {
1370+ self . tcx . sess . delay_span_bug (
1371+ span,
1372+ & format ! (
1373+ "non-defining exist ty use in defining scope: {:?}, {:?}" ,
1374+ concrete_type, substs,
1375+ ) ,
1376+ ) ;
1377+ }
1378+ }
1379+ }
1380+ // compute the index within the existential type for each generic parameter used in
1381+ // the concrete type
1382+ let indices = concrete_type
1383+ . subst ( self . tcx , substs)
1384+ . walk ( )
1385+ . filter_map ( |t| match & t. sty {
1386+ ty:: Param ( p) => Some ( * index_map. get ( p) . unwrap ( ) ) ,
1387+ _ => None ,
1388+ } ) . collect ( ) ;
1389+ let is_param = |ty : ty:: Ty | match ty. sty {
1390+ ty:: Param ( _) => true ,
1391+ _ => false ,
1392+ } ;
1393+ if !substs. types ( ) . all ( is_param) {
1394+ self . tcx . sess . span_err (
1395+ span,
1396+ "defining existential type use does not fully define existential type" ,
1397+ ) ;
1398+ } else if let Some ( ( prev_span, prev_ty, ref prev_indices) ) = self . found {
1399+ let mut ty = concrete_type. walk ( ) . fuse ( ) ;
1400+ let mut p_ty = prev_ty. walk ( ) . fuse ( ) ;
1401+ let iter_eq = ( & mut ty) . zip ( & mut p_ty) . all ( |( t, p) | match ( & t. sty , & p. sty ) {
1402+ // type parameters are equal to any other type parameter for the purpose of
1403+ // concrete type equality, as it is possible to obtain the same type just
1404+ // by passing matching parameters to a function.
1405+ ( ty:: Param ( _) , ty:: Param ( _) ) => true ,
1406+ _ => t == p,
1407+ } ) ;
1408+ if !iter_eq || ty. next ( ) . is_some ( ) || p_ty. next ( ) . is_some ( ) {
13481409 // found different concrete types for the existential type
13491410 let mut err = self . tcx . sess . struct_span_err (
13501411 span,
1351- "defining existential type use differs from previous" ,
1412+ "concrete type differs from previous defining existential type use" ,
1413+ ) ;
1414+ err. span_label (
1415+ span,
1416+ format ! ( "expected `{}`, got `{}`" , prev_ty, concrete_type) ,
1417+ ) ;
1418+ err. span_note ( prev_span, "previous use here" ) ;
1419+ err. emit ( ) ;
1420+ } else if indices != * prev_indices {
1421+ // found "same" concrete types, but the generic parameter order differs
1422+ let mut err = self . tcx . sess . struct_span_err (
1423+ span,
1424+ "concrete type's generic parameters differ from previous defining use" ,
13521425 ) ;
1426+ use std:: fmt:: Write ;
1427+ let mut s = String :: new ( ) ;
1428+ write ! ( s, "expected [" ) . unwrap ( ) ;
1429+ let list = |s : & mut String , indices : & Vec < usize > | {
1430+ let mut indices = indices. iter ( ) . cloned ( ) ;
1431+ if let Some ( first) = indices. next ( ) {
1432+ write ! ( s, "`{}`" , substs[ first] ) . unwrap ( ) ;
1433+ for i in indices {
1434+ write ! ( s, ", `{}`" , substs[ i] ) . unwrap ( ) ;
1435+ }
1436+ }
1437+ } ;
1438+ list ( & mut s, prev_indices) ;
1439+ write ! ( s, "], got [" ) . unwrap ( ) ;
1440+ list ( & mut s, & indices) ;
1441+ write ! ( s, "]" ) . unwrap ( ) ;
1442+ err. span_label ( span, s) ;
13531443 err. span_note ( prev_span, "previous use here" ) ;
13541444 err. emit ( ) ;
13551445 }
13561446 } else {
1357- self . found = Some ( ( span, ty ) ) ;
1447+ self . found = Some ( ( span, concrete_type , indices ) ) ;
13581448 }
13591449 }
13601450 }
@@ -1413,7 +1503,7 @@ fn find_existential_constraints<'a, 'tcx>(
14131503 }
14141504
14151505 match locator. found {
1416- Some ( ( _, ty) ) => ty,
1506+ Some ( ( _, ty, _ ) ) => ty,
14171507 None => {
14181508 let span = tcx. def_span ( def_id) ;
14191509 tcx. sess . span_err ( span, "could not find defining uses" ) ;
0 commit comments