@@ -10,6 +10,7 @@ use hir::HirVec;
10
10
use lint;
11
11
use middle:: resolve_lifetime as rl;
12
12
use namespace:: Namespace ;
13
+ use rustc:: lint:: builtin:: AMBIGUOUS_ASSOCIATED_ITEMS ;
13
14
use rustc:: traits;
14
15
use rustc:: ty:: { self , Ty , TyCtxt , ToPredicate , TypeFoldable } ;
15
16
use rustc:: ty:: { GenericParamDef , GenericParamDefKind } ;
@@ -1278,29 +1279,50 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
1278
1279
}
1279
1280
1280
1281
// Create a type from a path to an associated type.
1281
- // For a path `A::B::C::D`, `ty ` and `ty_path_def ` are the type and def for `A::B::C`
1282
+ // For a path `A::B::C::D`, `qself_ty ` and `qself_def ` are the type and def for `A::B::C`
1282
1283
// and item_segment is the path segment for `D`. We return a type and a def for
1283
1284
// the whole path.
1284
- // Will fail except for `T::A` and `Self::A`; i.e., if `ty `/`ty_path_def ` are not a type
1285
+ // Will fail except for `T::A` and `Self::A`; i.e., if `qself_ty `/`qself_def ` are not a type
1285
1286
// parameter or `Self`.
1286
- pub fn associated_path_def_to_ty ( & self ,
1287
- ref_id : ast:: NodeId ,
1288
- span : Span ,
1289
- ty : Ty < ' tcx > ,
1290
- ty_path_def : Def ,
1291
- item_segment : & hir:: PathSegment )
1292
- -> ( Ty < ' tcx > , Def )
1293
- {
1287
+ pub fn associated_path_to_ty (
1288
+ & self ,
1289
+ ref_id : ast:: NodeId ,
1290
+ span : Span ,
1291
+ qself_ty : Ty < ' tcx > ,
1292
+ qself_def : Def ,
1293
+ assoc_segment : & hir:: PathSegment ,
1294
+ permit_variants : bool ,
1295
+ ) -> ( Ty < ' tcx > , Def ) {
1294
1296
let tcx = self . tcx ( ) ;
1295
- let assoc_name = item_segment . ident ;
1297
+ let assoc_ident = assoc_segment . ident ;
1296
1298
1297
- debug ! ( "associated_path_def_to_ty : {:?}::{}" , ty , assoc_name ) ;
1299
+ debug ! ( "associated_path_to_ty : {:?}::{}" , qself_ty , assoc_ident ) ;
1298
1300
1299
- self . prohibit_generics ( slice:: from_ref ( item_segment) ) ;
1301
+ self . prohibit_generics ( slice:: from_ref ( assoc_segment) ) ;
1302
+
1303
+ // Check if we have an enum variant.
1304
+ let mut variant_resolution = None ;
1305
+ if let ty:: Adt ( adt_def, _) = qself_ty. sty {
1306
+ if adt_def. is_enum ( ) {
1307
+ let variant_def = adt_def. variants . iter ( ) . find ( |vd| {
1308
+ tcx. hygienic_eq ( assoc_ident, vd. ident , adt_def. did )
1309
+ } ) ;
1310
+ if let Some ( variant_def) = variant_def {
1311
+ let def = Def :: Variant ( variant_def. did ) ;
1312
+ if permit_variants {
1313
+ check_type_alias_enum_variants_enabled ( tcx, span) ;
1314
+ tcx. check_stability ( variant_def. did , Some ( ref_id) , span) ;
1315
+ return ( qself_ty, def) ;
1316
+ } else {
1317
+ variant_resolution = Some ( def) ;
1318
+ }
1319
+ }
1320
+ }
1321
+ }
1300
1322
1301
1323
// Find the type of the associated item, and the trait where the associated
1302
1324
// item is declared.
1303
- let bound = match ( & ty . sty , ty_path_def ) {
1325
+ let bound = match ( & qself_ty . sty , qself_def ) {
1304
1326
( _, Def :: SelfTy ( Some ( _) , Some ( impl_def_id) ) ) => {
1305
1327
// `Self` in an impl of a trait -- we have a concrete self type and a
1306
1328
// trait reference.
@@ -1313,77 +1335,61 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
1313
1335
} ;
1314
1336
1315
1337
let candidates = traits:: supertraits ( tcx, ty:: Binder :: bind ( trait_ref) )
1316
- . filter ( |r| self . trait_defines_associated_type_named ( r. def_id ( ) , assoc_name ) ) ;
1338
+ . filter ( |r| self . trait_defines_associated_type_named ( r. def_id ( ) , assoc_ident ) ) ;
1317
1339
1318
- match self . one_bound_for_assoc_type ( candidates, "Self" , assoc_name , span) {
1340
+ match self . one_bound_for_assoc_type ( candidates, "Self" , assoc_ident , span) {
1319
1341
Ok ( bound) => bound,
1320
1342
Err ( ErrorReported ) => return ( tcx. types . err , Def :: Err ) ,
1321
1343
}
1322
1344
}
1323
1345
( & ty:: Param ( _) , Def :: SelfTy ( Some ( param_did) , None ) ) |
1324
1346
( & ty:: Param ( _) , Def :: TyParam ( param_did) ) => {
1325
- match self . find_bound_for_assoc_item ( param_did, assoc_name , span) {
1347
+ match self . find_bound_for_assoc_item ( param_did, assoc_ident , span) {
1326
1348
Ok ( bound) => bound,
1327
1349
Err ( ErrorReported ) => return ( tcx. types . err , Def :: Err ) ,
1328
1350
}
1329
1351
}
1330
- ( & ty:: Adt ( adt_def, _substs) , Def :: Enum ( _did) ) => {
1331
- let ty_str = ty. to_string ( ) ;
1332
- // Incorrect enum variant.
1333
- let mut err = tcx. sess . struct_span_err (
1334
- span,
1335
- & format ! ( "no variant `{}` on enum `{}`" , & assoc_name. as_str( ) , ty_str) ,
1336
- ) ;
1337
- // Check if it was a typo.
1338
- let input = adt_def. variants . iter ( ) . map ( |variant| & variant. ident . name ) ;
1339
- if let Some ( suggested_name) = find_best_match_for_name (
1340
- input,
1341
- & assoc_name. as_str ( ) ,
1342
- None ,
1343
- ) {
1344
- err. span_suggestion_with_applicability (
1352
+ _ => {
1353
+ if variant_resolution. is_some ( ) {
1354
+ // Variant in type position
1355
+ let msg = format ! ( "expected type, found variant `{}`" , assoc_ident) ;
1356
+ tcx. sess . span_err ( span, & msg) ;
1357
+ } else if qself_ty. is_enum ( ) {
1358
+ // Report as incorrect enum variant rather than ambiguous type.
1359
+ let mut err = tcx. sess . struct_span_err (
1345
1360
span,
1346
- "did you mean" ,
1347
- format ! ( "{}::{}" , ty_str, suggested_name. to_string( ) ) ,
1348
- Applicability :: MaybeIncorrect ,
1361
+ & format ! ( "no variant `{}` on enum `{}`" , & assoc_ident. as_str( ) , qself_ty) ,
1349
1362
) ;
1350
- } else {
1351
- err. span_label ( span, "unknown variant" ) ;
1352
- }
1353
- err. emit ( ) ;
1354
- return ( tcx. types . err , Def :: Err ) ;
1355
- }
1356
- _ => {
1357
- // Check if we have an enum variant.
1358
- match ty. sty {
1359
- ty:: Adt ( adt_def, _) if adt_def. is_enum ( ) => {
1360
- let variant_def = adt_def. variants . iter ( ) . find ( |vd| {
1361
- tcx. hygienic_eq ( assoc_name, vd. ident , adt_def. did )
1362
- } ) ;
1363
- if let Some ( variant_def) = variant_def {
1364
- check_type_alias_enum_variants_enabled ( tcx, span) ;
1365
-
1366
- let def = Def :: Variant ( variant_def. did ) ;
1367
- tcx. check_stability ( def. def_id ( ) , Some ( ref_id) , span) ;
1368
- return ( ty, def) ;
1369
- }
1370
- } ,
1371
- _ => ( ) ,
1372
- }
1373
-
1374
- // Don't print `TyErr` to the user.
1375
- if !ty. references_error ( ) {
1363
+ // Check if it was a typo.
1364
+ let adt_def = qself_ty. ty_adt_def ( ) . expect ( "enum is not an ADT" ) ;
1365
+ if let Some ( suggested_name) = find_best_match_for_name (
1366
+ adt_def. variants . iter ( ) . map ( |variant| & variant. ident . name ) ,
1367
+ & assoc_ident. as_str ( ) ,
1368
+ None ,
1369
+ ) {
1370
+ err. span_suggestion_with_applicability (
1371
+ span,
1372
+ "did you mean" ,
1373
+ format ! ( "{}::{}" , qself_ty, suggested_name) ,
1374
+ Applicability :: MaybeIncorrect ,
1375
+ ) ;
1376
+ } else {
1377
+ err. span_label ( span, "unknown variant" ) ;
1378
+ }
1379
+ err. emit ( ) ;
1380
+ } else if !qself_ty. references_error ( ) {
1381
+ // Don't print `TyErr` to the user.
1376
1382
self . report_ambiguous_associated_type ( span,
1377
- & ty . to_string ( ) ,
1383
+ & qself_ty . to_string ( ) ,
1378
1384
"Trait" ,
1379
- & assoc_name . as_str ( ) ) ;
1385
+ & assoc_ident . as_str ( ) ) ;
1380
1386
}
1381
1387
return ( tcx. types . err , Def :: Err ) ;
1382
1388
}
1383
1389
} ;
1384
1390
1385
1391
let trait_did = bound. def_id ( ) ;
1386
- let ( assoc_ident, def_scope) = tcx. adjust_ident ( assoc_name , trait_did, ref_id) ;
1392
+ let ( assoc_ident, def_scope) = tcx. adjust_ident ( assoc_ident , trait_did, ref_id) ;
1387
1393
let item = tcx. associated_items ( trait_did) . find ( |i| {
1388
1394
Namespace :: from ( i. kind ) == Namespace :: Type &&
1389
1395
i. ident . modern ( ) == assoc_ident
@@ -1394,11 +1400,35 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
1394
1400
1395
1401
let def = Def :: AssociatedTy ( item. def_id ) ;
1396
1402
if !item. vis . is_accessible_from ( def_scope, tcx) {
1397
- let msg = format ! ( "{} `{}` is private" , def. kind_name( ) , assoc_name ) ;
1403
+ let msg = format ! ( "{} `{}` is private" , def. kind_name( ) , assoc_ident ) ;
1398
1404
tcx. sess . span_err ( span, & msg) ;
1399
1405
}
1400
1406
tcx. check_stability ( item. def_id , Some ( ref_id) , span) ;
1401
1407
1408
+ if let Some ( variant_def) = variant_resolution {
1409
+ let mut err = tcx. struct_span_lint_node (
1410
+ AMBIGUOUS_ASSOCIATED_ITEMS ,
1411
+ ref_id,
1412
+ span,
1413
+ "ambiguous associated item" ,
1414
+ ) ;
1415
+
1416
+ let mut could_refer_to = |def : Def , also| {
1417
+ let note_msg = format ! ( "`{}` could{} refer to {} defined here" ,
1418
+ assoc_ident, also, def. kind_name( ) ) ;
1419
+ err. span_note ( tcx. def_span ( def. def_id ( ) ) , & note_msg) ;
1420
+ } ;
1421
+ could_refer_to ( variant_def, "" ) ;
1422
+ could_refer_to ( def, " also" ) ;
1423
+
1424
+ err. span_suggestion_with_applicability (
1425
+ span,
1426
+ "use fully-qualified syntax" ,
1427
+ format ! ( "<{} as {}>::{}" , qself_ty, "Trait" , assoc_ident) ,
1428
+ Applicability :: HasPlaceholders ,
1429
+ ) . emit ( ) ;
1430
+ }
1431
+
1402
1432
( ty, def)
1403
1433
}
1404
1434
@@ -1773,7 +1803,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
1773
1803
} else {
1774
1804
Def :: Err
1775
1805
} ;
1776
- self . associated_path_def_to_ty ( ast_ty. id , ast_ty. span , ty, def, segment) . 0
1806
+ self . associated_path_to_ty ( ast_ty. id , ast_ty. span , ty, def, segment, false ) . 0
1777
1807
}
1778
1808
hir:: TyKind :: Array ( ref ty, ref length) => {
1779
1809
let length_def_id = tcx. hir ( ) . local_def_id ( length. id ) ;
0 commit comments