@@ -10,6 +10,7 @@ use hir::HirVec;
1010use lint;
1111use middle:: resolve_lifetime as rl;
1212use namespace:: Namespace ;
13+ use rustc:: lint:: builtin:: AMBIGUOUS_ASSOCIATED_ITEMS ;
1314use rustc:: traits;
1415use rustc:: ty:: { self , Ty , TyCtxt , ToPredicate , TypeFoldable } ;
1516use rustc:: ty:: { GenericParamDef , GenericParamDefKind } ;
@@ -1278,29 +1279,50 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
12781279 }
12791280
12801281 // 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`
12821283 // and item_segment is the path segment for `D`. We return a type and a def for
12831284 // 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
12851286 // 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 ) {
12941296 let tcx = self . tcx ( ) ;
1295- let assoc_name = item_segment . ident ;
1297+ let assoc_ident = assoc_segment . ident ;
12961298
1297- debug ! ( "associated_path_def_to_ty : {:?}::{}" , ty , assoc_name ) ;
1299+ debug ! ( "associated_path_to_ty : {:?}::{}" , qself_ty , assoc_ident ) ;
12981300
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+ }
13001322
13011323 // Find the type of the associated item, and the trait where the associated
13021324 // item is declared.
1303- let bound = match ( & ty . sty , ty_path_def ) {
1325+ let bound = match ( & qself_ty . sty , qself_def ) {
13041326 ( _, Def :: SelfTy ( Some ( _) , Some ( impl_def_id) ) ) => {
13051327 // `Self` in an impl of a trait -- we have a concrete self type and a
13061328 // trait reference.
@@ -1313,77 +1335,61 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
13131335 } ;
13141336
13151337 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 ) ) ;
13171339
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) {
13191341 Ok ( bound) => bound,
13201342 Err ( ErrorReported ) => return ( tcx. types . err , Def :: Err ) ,
13211343 }
13221344 }
13231345 ( & ty:: Param ( _) , Def :: SelfTy ( Some ( param_did) , None ) ) |
13241346 ( & 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) {
13261348 Ok ( bound) => bound,
13271349 Err ( ErrorReported ) => return ( tcx. types . err , Def :: Err ) ,
13281350 }
13291351 }
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 (
13451360 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) ,
13491362 ) ;
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.
13761382 self . report_ambiguous_associated_type ( span,
1377- & ty . to_string ( ) ,
1383+ & qself_ty . to_string ( ) ,
13781384 "Trait" ,
1379- & assoc_name . as_str ( ) ) ;
1385+ & assoc_ident . as_str ( ) ) ;
13801386 }
13811387 return ( tcx. types . err , Def :: Err ) ;
13821388 }
13831389 } ;
13841390
13851391 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) ;
13871393 let item = tcx. associated_items ( trait_did) . find ( |i| {
13881394 Namespace :: from ( i. kind ) == Namespace :: Type &&
13891395 i. ident . modern ( ) == assoc_ident
@@ -1394,11 +1400,35 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
13941400
13951401 let def = Def :: AssociatedTy ( item. def_id ) ;
13961402 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 ) ;
13981404 tcx. sess . span_err ( span, & msg) ;
13991405 }
14001406 tcx. check_stability ( item. def_id , Some ( ref_id) , span) ;
14011407
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+
14021432 ( ty, def)
14031433 }
14041434
@@ -1773,7 +1803,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o {
17731803 } else {
17741804 Def :: Err
17751805 } ;
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
17771807 }
17781808 hir:: TyKind :: Array ( ref ty, ref length) => {
17791809 let length_def_id = tcx. hir ( ) . local_def_id ( length. id ) ;
0 commit comments