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