@@ -420,6 +420,141 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
420
420
}
421
421
}
422
422
423
+ // Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
424
+ // Nested `impl Trait` _is_ allowed in associated type position,
425
+ // e.g `impl Iterator<Item=impl Debug>`
426
+ struct NestedImplTraitVisitor < ' a > {
427
+ session : & ' a Session ,
428
+ outer_impl_trait : Option < Span > ,
429
+ }
430
+
431
+ impl < ' a > NestedImplTraitVisitor < ' a > {
432
+ fn with_impl_trait < F > ( & mut self , outer_impl_trait : Option < Span > , f : F )
433
+ where F : FnOnce ( & mut NestedImplTraitVisitor < ' a > )
434
+ {
435
+ let old_outer_impl_trait = self . outer_impl_trait ;
436
+ self . outer_impl_trait = outer_impl_trait;
437
+ f ( self ) ;
438
+ self . outer_impl_trait = old_outer_impl_trait;
439
+ }
440
+ }
441
+
442
+
443
+ impl < ' a > Visitor < ' a > for NestedImplTraitVisitor < ' a > {
444
+ fn visit_ty ( & mut self , t : & ' a Ty ) {
445
+ if let TyKind :: ImplTrait ( _) = t. node {
446
+ if let Some ( outer_impl_trait) = self . outer_impl_trait {
447
+ struct_span_err ! ( self . session, t. span, E0666 ,
448
+ "nested `impl Trait` is not allowed" )
449
+ . span_label ( outer_impl_trait, "outer `impl Trait`" )
450
+ . span_label ( t. span , "nested `impl Trait` here" )
451
+ . emit ( ) ;
452
+
453
+ }
454
+ self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) ) ;
455
+ } else {
456
+ visit:: walk_ty ( self , t) ;
457
+ }
458
+ }
459
+ fn visit_path_parameters ( & mut self , _: Span , path_parameters : & ' a PathParameters ) {
460
+ match * path_parameters {
461
+ PathParameters :: AngleBracketed ( ref params) => {
462
+ for type_ in & params. types {
463
+ self . visit_ty ( type_) ;
464
+ }
465
+ for type_binding in & params. bindings {
466
+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
467
+ // are allowed to contain nested `impl Trait`.
468
+ self . with_impl_trait ( None , |this| visit:: walk_ty ( this, & type_binding. ty ) ) ;
469
+ }
470
+ }
471
+ PathParameters :: Parenthesized ( ref params) => {
472
+ for type_ in & params. inputs {
473
+ self . visit_ty ( type_) ;
474
+ }
475
+ if let Some ( ref type_) = params. output {
476
+ // `-> Foo` syntax is essentially an associated type binding,
477
+ // so it is also allowed to contain nested `impl Trait`.
478
+ self . with_impl_trait ( None , |this| visit:: walk_ty ( this, type_) ) ;
479
+ }
480
+ }
481
+ }
482
+ }
483
+ }
484
+
485
+ // Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
486
+ struct ImplTraitProjectionVisitor < ' a > {
487
+ session : & ' a Session ,
488
+ is_banned : bool ,
489
+ }
490
+
491
+ impl < ' a > ImplTraitProjectionVisitor < ' a > {
492
+ fn with_ban < F > ( & mut self , f : F )
493
+ where F : FnOnce ( & mut ImplTraitProjectionVisitor < ' a > )
494
+ {
495
+ let old_is_banned = self . is_banned ;
496
+ self . is_banned = true ;
497
+ f ( self ) ;
498
+ self . is_banned = old_is_banned;
499
+ }
500
+ }
501
+
502
+ impl < ' a > Visitor < ' a > for ImplTraitProjectionVisitor < ' a > {
503
+ fn visit_ty ( & mut self , t : & ' a Ty ) {
504
+ match t. node {
505
+ TyKind :: ImplTrait ( _) => {
506
+ if self . is_banned {
507
+ struct_span_err ! ( self . session, t. span, E0667 ,
508
+ "`impl Trait` is not allowed in path parameters" )
509
+ . emit ( ) ;
510
+ }
511
+ }
512
+ TyKind :: Path ( ref qself, ref path) => {
513
+ // We allow these:
514
+ // - `Option<impl Trait>`
515
+ // - `option::Option<impl Trait>`
516
+ // - `option::Option<T>::Foo<impl Trait>
517
+ //
518
+ // But not these:
519
+ // - `<impl Trait>::Foo`
520
+ // - `option::Option<impl Trait>::Foo`.
521
+ //
522
+ // To implement this, we disallow `impl Trait` from `qself`
523
+ // (for cases like `<impl Trait>::Foo>`)
524
+ // but we allow `impl Trait` in `PathParameters`
525
+ // iff there are no more PathSegments.
526
+ if let Some ( ref qself) = * qself {
527
+ // `impl Trait` in `qself` is always illegal
528
+ self . with_ban ( |this| this. visit_ty ( & qself. ty ) ) ;
529
+ }
530
+
531
+ for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
532
+ // Allow `impl Trait` iff we're on the final path segment
533
+ if i == ( path. segments . len ( ) - 1 ) {
534
+ visit:: walk_path_segment ( self , path. span , segment) ;
535
+ } else {
536
+ self . with_ban ( |this|
537
+ visit:: walk_path_segment ( this, path. span , segment) ) ;
538
+ }
539
+ }
540
+ }
541
+ _ => visit:: walk_ty ( self , t) ,
542
+ }
543
+ }
544
+ }
545
+
423
546
pub fn check_crate ( session : & Session , krate : & Crate ) {
547
+ visit:: walk_crate (
548
+ & mut NestedImplTraitVisitor {
549
+ session,
550
+ outer_impl_trait : None ,
551
+ } , krate) ;
552
+
553
+ visit:: walk_crate (
554
+ & mut ImplTraitProjectionVisitor {
555
+ session,
556
+ is_banned : false ,
557
+ } , krate) ;
558
+
424
559
visit:: walk_crate ( & mut AstValidator { session : session } , krate)
425
560
}
0 commit comments