@@ -23,9 +23,10 @@ use crate::middle::resolve_lifetime as rl;
23
23
use crate :: middle:: weak_lang_items;
24
24
use rustc:: mir:: mono:: Linkage ;
25
25
use rustc:: ty:: query:: Providers ;
26
- use rustc:: ty:: subst:: Substs ;
26
+ use rustc:: ty:: subst:: { Subst , Substs } ;
27
27
use rustc:: ty:: util:: Discr ;
28
28
use rustc:: ty:: util:: IntTypeExt ;
29
+ use rustc:: ty:: subst:: UnpackedKind ;
29
30
use rustc:: ty:: { self , AdtKind , ToPolyTraitRef , Ty , TyCtxt } ;
30
31
use rustc:: ty:: { ReprOptions , ToPredicate } ;
31
32
use rustc:: util:: captures:: Captures ;
@@ -1211,7 +1212,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> {
1211
1212
tcx. typeck_tables_of ( owner)
1212
1213
. concrete_existential_types
1213
1214
. get ( & def_id)
1214
- . cloned ( )
1215
+ . map ( |opaque| opaque . concrete_type )
1215
1216
. unwrap_or_else ( || {
1216
1217
// This can occur if some error in the
1217
1218
// owner fn prevented us from populating
@@ -1343,7 +1344,13 @@ fn find_existential_constraints<'a, 'tcx>(
1343
1344
struct ConstraintLocator < ' a , ' tcx : ' a > {
1344
1345
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
1345
1346
def_id : DefId ,
1346
- found : Option < ( Span , ty:: Ty < ' tcx > ) > ,
1347
+ // First found type span, actual type, mapping from the existential type's generic
1348
+ // parameters to the concrete type's generic parameters
1349
+ //
1350
+ // The mapping is an index for each use site of a generic parameter in the concrete type
1351
+ //
1352
+ // The indices index into the generic parameters on the existential type.
1353
+ found : Option < ( Span , ty:: Ty < ' tcx > , Vec < usize > ) > ,
1347
1354
}
1348
1355
1349
1356
impl < ' a , ' tcx > ConstraintLocator < ' a , ' tcx > {
@@ -1358,23 +1365,106 @@ fn find_existential_constraints<'a, 'tcx>(
1358
1365
. tcx
1359
1366
. typeck_tables_of ( def_id)
1360
1367
. concrete_existential_types
1361
- . get ( & self . def_id )
1362
- . cloned ( ) ;
1363
- if let Some ( ty) = ty {
1368
+ . get ( & self . def_id ) ;
1369
+ if let Some ( ty:: ResolvedOpaqueTy { concrete_type, substs } ) = ty {
1364
1370
// FIXME(oli-obk): trace the actual span from inference to improve errors
1365
1371
let span = self . tcx . def_span ( def_id) ;
1366
- if let Some ( ( prev_span, prev_ty) ) = self . found {
1367
- if ty != prev_ty {
1372
+ // used to quickly look up the position of a generic parameter
1373
+ let mut index_map: FxHashMap < ty:: ParamTy , usize > = FxHashMap :: default ( ) ;
1374
+ // skip binder is ok, since we only use this to find generic parameters and their
1375
+ // positions.
1376
+ for ( idx, subst) in substs. iter ( ) . enumerate ( ) {
1377
+ if let UnpackedKind :: Type ( ty) = subst. unpack ( ) {
1378
+ if let ty:: Param ( p) = ty. sty {
1379
+ if index_map. insert ( p, idx) . is_some ( ) {
1380
+ // there was already an entry for `p`, meaning a generic parameter
1381
+ // was used twice
1382
+ self . tcx . sess . span_err (
1383
+ span,
1384
+ & format ! ( "defining existential type use restricts existential \
1385
+ type by using the generic parameter `{}` twice", p. name) ,
1386
+ ) ;
1387
+ return ;
1388
+ }
1389
+ } else {
1390
+ self . tcx . sess . delay_span_bug (
1391
+ span,
1392
+ & format ! (
1393
+ "non-defining exist ty use in defining scope: {:?}, {:?}" ,
1394
+ concrete_type, substs,
1395
+ ) ,
1396
+ ) ;
1397
+ }
1398
+ }
1399
+ }
1400
+ // compute the index within the existential type for each generic parameter used in
1401
+ // the concrete type
1402
+ let indices = concrete_type
1403
+ . subst ( self . tcx , substs)
1404
+ . walk ( )
1405
+ . filter_map ( |t| match & t. sty {
1406
+ ty:: Param ( p) => Some ( * index_map. get ( p) . unwrap ( ) ) ,
1407
+ _ => None ,
1408
+ } ) . collect ( ) ;
1409
+ let is_param = |ty : ty:: Ty | match ty. sty {
1410
+ ty:: Param ( _) => true ,
1411
+ _ => false ,
1412
+ } ;
1413
+ if !substs. types ( ) . all ( is_param) {
1414
+ self . tcx . sess . span_err (
1415
+ span,
1416
+ "defining existential type use does not fully define existential type" ,
1417
+ ) ;
1418
+ } else if let Some ( ( prev_span, prev_ty, ref prev_indices) ) = self . found {
1419
+ let mut ty = concrete_type. walk ( ) . fuse ( ) ;
1420
+ let mut p_ty = prev_ty. walk ( ) . fuse ( ) ;
1421
+ let iter_eq = ( & mut ty) . zip ( & mut p_ty) . all ( |( t, p) | match ( & t. sty , & p. sty ) {
1422
+ // type parameters are equal to any other type parameter for the purpose of
1423
+ // concrete type equality, as it is possible to obtain the same type just
1424
+ // by passing matching parameters to a function.
1425
+ ( ty:: Param ( _) , ty:: Param ( _) ) => true ,
1426
+ _ => t == p,
1427
+ } ) ;
1428
+ if !iter_eq || ty. next ( ) . is_some ( ) || p_ty. next ( ) . is_some ( ) {
1368
1429
// found different concrete types for the existential type
1369
1430
let mut err = self . tcx . sess . struct_span_err (
1370
1431
span,
1371
- "defining existential type use differs from previous" ,
1432
+ "concrete type differs from previous defining existential type use" ,
1433
+ ) ;
1434
+ err. span_label (
1435
+ span,
1436
+ format ! ( "expected `{}`, got `{}`" , prev_ty, concrete_type) ,
1437
+ ) ;
1438
+ err. span_note ( prev_span, "previous use here" ) ;
1439
+ err. emit ( ) ;
1440
+ } else if indices != * prev_indices {
1441
+ // found "same" concrete types, but the generic parameter order differs
1442
+ let mut err = self . tcx . sess . struct_span_err (
1443
+ span,
1444
+ "concrete type's generic parameters differ from previous defining use" ,
1372
1445
) ;
1446
+ use std:: fmt:: Write ;
1447
+ let mut s = String :: new ( ) ;
1448
+ write ! ( s, "expected [" ) . unwrap ( ) ;
1449
+ let list = |s : & mut String , indices : & Vec < usize > | {
1450
+ let mut indices = indices. iter ( ) . cloned ( ) ;
1451
+ if let Some ( first) = indices. next ( ) {
1452
+ write ! ( s, "`{}`" , substs[ first] ) . unwrap ( ) ;
1453
+ for i in indices {
1454
+ write ! ( s, ", `{}`" , substs[ i] ) . unwrap ( ) ;
1455
+ }
1456
+ }
1457
+ } ;
1458
+ list ( & mut s, prev_indices) ;
1459
+ write ! ( s, "], got [" ) . unwrap ( ) ;
1460
+ list ( & mut s, & indices) ;
1461
+ write ! ( s, "]" ) . unwrap ( ) ;
1462
+ err. span_label ( span, s) ;
1373
1463
err. span_note ( prev_span, "previous use here" ) ;
1374
1464
err. emit ( ) ;
1375
1465
}
1376
1466
} else {
1377
- self . found = Some ( ( span, ty ) ) ;
1467
+ self . found = Some ( ( span, concrete_type , indices ) ) ;
1378
1468
}
1379
1469
}
1380
1470
}
@@ -1433,7 +1523,7 @@ fn find_existential_constraints<'a, 'tcx>(
1433
1523
}
1434
1524
1435
1525
match locator. found {
1436
- Some ( ( _, ty) ) => ty,
1526
+ Some ( ( _, ty, _ ) ) => ty,
1437
1527
None => {
1438
1528
let span = tcx. def_span ( def_id) ;
1439
1529
tcx. sess . span_err ( span, "could not find defining uses" ) ;
0 commit comments