@@ -46,6 +46,7 @@ use syntax::attr;
4646use syntax:: feature_gate:: { AttributeGate , AttributeType , Stability , deprecated_attributes} ;
4747use syntax_pos:: { BytePos , Span , SyntaxContext } ;
4848use syntax:: symbol:: keywords;
49+ use syntax:: errors:: DiagnosticBuilder ;
4950
5051use rustc:: hir:: { self , PatKind } ;
5152use rustc:: hir:: intravisit:: FnKind ;
@@ -1334,31 +1335,97 @@ impl LintPass for TypeAliasBounds {
13341335 }
13351336}
13361337
1337- impl EarlyLintPass for TypeAliasBounds {
1338- fn check_item ( & mut self , cx : & EarlyContext , item : & ast:: Item ) {
1339- let type_alias_generics = match item. node {
1340- ast:: ItemKind :: Ty ( _, ref generics) => generics,
1338+ impl TypeAliasBounds {
1339+ fn is_type_variable_assoc ( qpath : & hir:: QPath ) -> bool {
1340+ match * qpath {
1341+ hir:: QPath :: TypeRelative ( ref ty, _) => {
1342+ // If this is a type variable, we found a `T::Assoc`.
1343+ match ty. node {
1344+ hir:: TyPath ( hir:: QPath :: Resolved ( None , ref path) ) => {
1345+ match path. def {
1346+ Def :: TyParam ( _) => true ,
1347+ _ => false
1348+ }
1349+ }
1350+ _ => false
1351+ }
1352+ }
1353+ hir:: QPath :: Resolved ( ..) => false ,
1354+ }
1355+ }
1356+
1357+ fn suggest_changing_assoc_types ( ty : & hir:: Ty , err : & mut DiagnosticBuilder ) {
1358+ // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
1359+ // bound. Let's see of this type does that.
1360+
1361+ // We use an AST visitor to walk the type.
1362+ use rustc:: hir:: intravisit:: { self , Visitor } ;
1363+ use syntax:: ast:: NodeId ;
1364+ struct WalkAssocTypes < ' a , ' db > where ' db : ' a {
1365+ err : & ' a mut DiagnosticBuilder < ' db >
1366+ }
1367+ impl < ' a , ' db , ' v > Visitor < ' v > for WalkAssocTypes < ' a , ' db > {
1368+ fn nested_visit_map < ' this > ( & ' this mut self ) -> intravisit:: NestedVisitorMap < ' this , ' v >
1369+ {
1370+ intravisit:: NestedVisitorMap :: None
1371+ }
1372+
1373+ fn visit_qpath ( & mut self , qpath : & ' v hir:: QPath , id : NodeId , span : Span ) {
1374+ if TypeAliasBounds :: is_type_variable_assoc ( qpath) {
1375+ self . err . span_help ( span,
1376+ "use absolute paths (i.e., <T as Trait>::Assoc) to refer to associated \
1377+ types in type aliases") ;
1378+ }
1379+ intravisit:: walk_qpath ( self , qpath, id, span)
1380+ }
1381+ }
1382+
1383+ // Let's go for a walk!
1384+ let mut visitor = WalkAssocTypes { err } ;
1385+ visitor. visit_ty ( ty) ;
1386+ }
1387+ }
1388+
1389+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for TypeAliasBounds {
1390+ fn check_item ( & mut self , cx : & LateContext , item : & hir:: Item ) {
1391+ let ( ty, type_alias_generics) = match item. node {
1392+ hir:: ItemTy ( ref ty, ref generics) => ( & * ty, generics) ,
13411393 _ => return ,
13421394 } ;
1395+ let mut suggested_changing_assoc_types = false ;
13431396 // There must not be a where clause
13441397 if !type_alias_generics. where_clause . predicates . is_empty ( ) {
13451398 let spans : Vec < _ > = type_alias_generics. where_clause . predicates . iter ( )
13461399 . map ( |pred| pred. span ( ) ) . collect ( ) ;
1347- cx. span_lint ( TYPE_ALIAS_BOUNDS , spans,
1400+ let mut err = cx. struct_span_lint ( TYPE_ALIAS_BOUNDS , spans,
13481401 "where clauses are not enforced in type aliases" ) ;
1402+ err. help ( "the clause will not be checked when the type alias is used, \
1403+ and should be removed") ;
1404+ if !suggested_changing_assoc_types {
1405+ TypeAliasBounds :: suggest_changing_assoc_types ( ty, & mut err) ;
1406+ suggested_changing_assoc_types = true ;
1407+ }
1408+ err. emit ( ) ;
13491409 }
13501410 // The parameters must not have bounds
13511411 for param in type_alias_generics. params . iter ( ) {
13521412 let spans : Vec < _ > = match param {
1353- & ast :: GenericParam :: Lifetime ( ref l) => l. bounds . iter ( ) . map ( |b| b. span ) . collect ( ) ,
1354- & ast :: GenericParam :: Type ( ref ty) => ty. bounds . iter ( ) . map ( |b| b. span ( ) ) . collect ( ) ,
1413+ & hir :: GenericParam :: Lifetime ( ref l) => l. bounds . iter ( ) . map ( |b| b. span ) . collect ( ) ,
1414+ & hir :: GenericParam :: Type ( ref ty) => ty. bounds . iter ( ) . map ( |b| b. span ( ) ) . collect ( ) ,
13551415 } ;
13561416 if !spans. is_empty ( ) {
1357- cx. span_lint (
1417+ let mut err = cx. struct_span_lint (
13581418 TYPE_ALIAS_BOUNDS ,
13591419 spans,
13601420 "bounds on generic parameters are not enforced in type aliases" ,
13611421 ) ;
1422+ err. help ( "the bound will not be checked when the type alias is used, \
1423+ and should be removed") ;
1424+ if !suggested_changing_assoc_types {
1425+ TypeAliasBounds :: suggest_changing_assoc_types ( ty, & mut err) ;
1426+ suggested_changing_assoc_types = true ;
1427+ }
1428+ err. emit ( ) ;
13621429 }
13631430 }
13641431 }
0 commit comments