@@ -441,6 +441,9 @@ declare_features! (
441441
442442 // `foo.rs` as an alternative to `foo/mod.rs`
443443 ( active, non_modrs_mods, "1.24.0" , Some ( 44660 ) ) ,
444+
445+ // Nested `impl Trait`
446+ ( active, nested_impl_trait, "1.24.0" , Some ( 34511 ) ) ,
444447) ;
445448
446449declare_features ! (
@@ -1314,8 +1317,73 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool {
13141317 }
13151318}
13161319
1320+ // Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
1321+ // Nested `impl Trait` _is_ allowed in associated type position,
1322+ // e.g `impl Iterator<Item=impl Debug>`
1323+ struct NestedImplTraitVisitor < ' a > {
1324+ context : & ' a Context < ' a > ,
1325+ is_in_impl_trait : bool ,
1326+ }
1327+
1328+ impl < ' a > NestedImplTraitVisitor < ' a > {
1329+ fn with_impl_trait < F > ( & mut self , is_in_impl_trait : bool , f : F )
1330+ where F : FnOnce ( & mut NestedImplTraitVisitor < ' a > )
1331+ {
1332+ let old_is_in_impl_trait = self . is_in_impl_trait ;
1333+ self . is_in_impl_trait = is_in_impl_trait;
1334+ f ( self ) ;
1335+ self . is_in_impl_trait = old_is_in_impl_trait;
1336+ }
1337+ }
1338+
1339+
1340+ impl < ' a > Visitor < ' a > for NestedImplTraitVisitor < ' a > {
1341+ fn visit_ty ( & mut self , t : & ' a ast:: Ty ) {
1342+ if let ast:: TyKind :: ImplTrait ( _) = t. node {
1343+ if self . is_in_impl_trait {
1344+ gate_feature_post ! ( & self , nested_impl_trait, t. span,
1345+ "nested `impl Trait` is experimental"
1346+ ) ;
1347+ }
1348+ self . with_impl_trait ( true , |this| visit:: walk_ty ( this, t) ) ;
1349+ } else {
1350+ visit:: walk_ty ( self , t) ;
1351+ }
1352+ }
1353+ fn visit_path_parameters ( & mut self , _: Span , path_parameters : & ' a ast:: PathParameters ) {
1354+ match * path_parameters {
1355+ ast:: PathParameters :: AngleBracketed ( ref params) => {
1356+ for type_ in & params. types {
1357+ self . visit_ty ( type_) ;
1358+ }
1359+ for type_binding in & params. bindings {
1360+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
1361+ // are allowed to contain nested `impl Trait`.
1362+ self . with_impl_trait ( false , |this| visit:: walk_ty ( this, & type_binding. ty ) ) ;
1363+ }
1364+ }
1365+ ast:: PathParameters :: Parenthesized ( ref params) => {
1366+ for type_ in & params. inputs {
1367+ self . visit_ty ( type_) ;
1368+ }
1369+ if let Some ( ref type_) = params. output {
1370+ // `-> Foo` syntax is essentially an associated type binding,
1371+ // so it is also allowed to contain nested `impl Trait`.
1372+ self . with_impl_trait ( false , |this| visit:: walk_ty ( this, type_) ) ;
1373+ }
1374+ }
1375+ }
1376+ }
1377+ }
1378+
13171379impl < ' a > PostExpansionVisitor < ' a > {
1318- fn whole_crate_feature_gates ( & mut self ) {
1380+ fn whole_crate_feature_gates ( & mut self , krate : & ast:: Crate ) {
1381+ visit:: walk_crate (
1382+ & mut NestedImplTraitVisitor {
1383+ context : self . context ,
1384+ is_in_impl_trait : false ,
1385+ } , krate) ;
1386+
13191387 for & ( ident, span) in & * self . context . parse_sess . non_modrs_mods . borrow ( ) {
13201388 if !span. allows_unstable ( ) {
13211389 let cx = & self . context ;
@@ -1889,7 +1957,7 @@ pub fn check_crate(krate: &ast::Crate,
18891957 plugin_attributes,
18901958 } ;
18911959 let visitor = & mut PostExpansionVisitor { context : & ctx } ;
1892- visitor. whole_crate_feature_gates ( ) ;
1960+ visitor. whole_crate_feature_gates ( krate ) ;
18931961 visit:: walk_crate ( visitor, krate) ;
18941962}
18951963
0 commit comments