@@ -23,6 +23,7 @@ use rustc_session::Session;
2323use rustc_span:: symbol:: { kw, sym} ;
2424use rustc_span:: Span ;
2525use std:: mem;
26+ use std:: ops:: DerefMut ;
2627
2728const MORE_EXTERN : & str =
2829 "for more information, visit https://doc.rust-lang.org/std/keyword.extern.html" ;
@@ -1113,17 +1114,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11131114
11141115 for predicate in & generics. where_clause . predicates {
11151116 if let WherePredicate :: EqPredicate ( ref predicate) = * predicate {
1116- self . err_handler ( )
1117- . struct_span_err (
1118- predicate. span ,
1119- "equality constraints are not yet supported in `where` clauses" ,
1120- )
1121- . span_label ( predicate. span , "not supported" )
1122- . note (
1123- "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> \
1124- for more information",
1125- )
1126- . emit ( ) ;
1117+ deny_equality_constraints ( self , predicate, generics) ;
11271118 }
11281119 }
11291120
@@ -1300,6 +1291,87 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
13001291 }
13011292}
13021293
1294+ fn deny_equality_constraints (
1295+ this : & mut AstValidator < ' _ > ,
1296+ predicate : & WhereEqPredicate ,
1297+ generics : & Generics ,
1298+ ) {
1299+ let mut err = this. err_handler ( ) . struct_span_err (
1300+ predicate. span ,
1301+ "equality constraints are not yet supported in `where` clauses" ,
1302+ ) ;
1303+ err. span_label ( predicate. span , "not supported" ) ;
1304+
1305+ // Given `<A as Foo>::Bar = RhsTy`, suggest `A: Foo<Bar = RhsTy>`.
1306+ if let TyKind :: Path ( Some ( qself) , full_path) = & predicate. lhs_ty . kind {
1307+ if let TyKind :: Path ( None , path) = & qself. ty . kind {
1308+ match & path. segments [ ..] {
1309+ [ PathSegment { ident, args : None , .. } ] => {
1310+ for param in & generics. params {
1311+ if param. ident == * ident {
1312+ let param = ident;
1313+ match & full_path. segments [ qself. position ..] {
1314+ [ PathSegment { ident, .. } ] => {
1315+ // Make a new `Path` from `foo::Bar` to `Foo<Bar = RhsTy>`.
1316+ let mut assoc_path = full_path. clone ( ) ;
1317+ // Remove `Bar` from `Foo::Bar`.
1318+ assoc_path. segments . pop ( ) ;
1319+ let len = assoc_path. segments . len ( ) - 1 ;
1320+ // Build `<Bar = RhsTy>`.
1321+ let arg = AngleBracketedArg :: Constraint ( AssocTyConstraint {
1322+ id : rustc_ast:: node_id:: DUMMY_NODE_ID ,
1323+ ident : * ident,
1324+ kind : AssocTyConstraintKind :: Equality {
1325+ ty : predicate. rhs_ty . clone ( ) ,
1326+ } ,
1327+ span : ident. span ,
1328+ } ) ;
1329+ // Add `<Bar = RhsTy>` to `Foo`.
1330+ match & mut assoc_path. segments [ len] . args {
1331+ Some ( args) => match args. deref_mut ( ) {
1332+ GenericArgs :: Parenthesized ( _) => continue ,
1333+ GenericArgs :: AngleBracketed ( args) => {
1334+ args. args . push ( arg) ;
1335+ }
1336+ } ,
1337+ empty_args => {
1338+ * empty_args = AngleBracketedArgs {
1339+ span : ident. span ,
1340+ args : vec ! [ arg] ,
1341+ }
1342+ . into ( ) ;
1343+ }
1344+ }
1345+ err. span_suggestion_verbose (
1346+ predicate. span ,
1347+ & format ! (
1348+ "if `{}` is an associated type you're trying to set, \
1349+ use the associated type binding syntax",
1350+ ident
1351+ ) ,
1352+ format ! (
1353+ "{}: {}" ,
1354+ param,
1355+ pprust:: path_to_string( & assoc_path)
1356+ ) ,
1357+ Applicability :: MaybeIncorrect ,
1358+ ) ;
1359+ }
1360+ _ => { }
1361+ } ;
1362+ }
1363+ }
1364+ }
1365+ _ => { }
1366+ }
1367+ }
1368+ }
1369+ err. note (
1370+ "see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information" ,
1371+ ) ;
1372+ err. emit ( ) ;
1373+ }
1374+
13031375pub fn check_crate ( session : & Session , krate : & Crate , lints : & mut LintBuffer ) -> bool {
13041376 let mut validator = AstValidator {
13051377 session,
0 commit comments