@@ -441,6 +441,9 @@ declare_features! (
441
441
442
442
// `foo.rs` as an alternative to `foo/mod.rs`
443
443
( active, non_modrs_mods, "1.24.0" , Some ( 44660 ) ) ,
444
+
445
+ // Nested `impl Trait`
446
+ ( active, nested_impl_trait, "1.24.0" , Some ( 34511 ) ) ,
444
447
) ;
445
448
446
449
declare_features ! (
@@ -1314,8 +1317,73 @@ fn contains_novel_literal(item: &ast::MetaItem) -> bool {
1314
1317
}
1315
1318
}
1316
1319
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
+
1317
1379
impl < ' 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
+
1319
1387
for & ( ident, span) in & * self . context . parse_sess . non_modrs_mods . borrow ( ) {
1320
1388
if !span. allows_unstable ( ) {
1321
1389
let cx = & self . context ;
@@ -1889,7 +1957,7 @@ pub fn check_crate(krate: &ast::Crate,
1889
1957
plugin_attributes,
1890
1958
} ;
1891
1959
let visitor = & mut PostExpansionVisitor { context : & ctx } ;
1892
- visitor. whole_crate_feature_gates ( ) ;
1960
+ visitor. whole_crate_feature_gates ( krate ) ;
1893
1961
visit:: walk_crate ( visitor, krate) ;
1894
1962
}
1895
1963
0 commit comments