@@ -20,9 +20,79 @@ use errors::Applicability;
20
20
21
21
struct AstValidator < ' a > {
22
22
session : & ' a Session ,
23
+
24
+ // Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
25
+ // Nested `impl Trait` _is_ allowed in associated type position,
26
+ // e.g `impl Iterator<Item=impl Debug>`
27
+ outer_impl_trait : Option < Span > ,
28
+
29
+ // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
30
+ // or `Foo::Bar<impl Trait>`
31
+ is_impl_trait_banned : bool ,
23
32
}
24
33
25
34
impl < ' a > AstValidator < ' a > {
35
+ fn with_banned_impl_trait < F > ( & mut self , f : F )
36
+ where F : FnOnce ( & mut Self )
37
+ {
38
+ let old_is_impl_trait_banned = self . is_impl_trait_banned ;
39
+ self . is_impl_trait_banned = true ;
40
+ f ( self ) ;
41
+ self . is_impl_trait_banned = old_is_impl_trait_banned;
42
+ }
43
+
44
+ fn with_impl_trait < F > ( & mut self , outer_impl_trait : Option < Span > , f : F )
45
+ where F : FnOnce ( & mut Self )
46
+ {
47
+ let old_outer_impl_trait = self . outer_impl_trait ;
48
+ self . outer_impl_trait = outer_impl_trait;
49
+ f ( self ) ;
50
+ self . outer_impl_trait = old_outer_impl_trait;
51
+ }
52
+
53
+ // Mirrors visit::walk_ty, but tracks relevant state
54
+ fn walk_ty ( & mut self , t : & ' a Ty ) {
55
+ match t. node {
56
+ TyKind :: ImplTrait ( ..) => {
57
+ self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) )
58
+ }
59
+ TyKind :: Path ( ref qself, ref path) => {
60
+ // We allow these:
61
+ // - `Option<impl Trait>`
62
+ // - `option::Option<impl Trait>`
63
+ // - `option::Option<T>::Foo<impl Trait>
64
+ //
65
+ // But not these:
66
+ // - `<impl Trait>::Foo`
67
+ // - `option::Option<impl Trait>::Foo`.
68
+ //
69
+ // To implement this, we disallow `impl Trait` from `qself`
70
+ // (for cases like `<impl Trait>::Foo>`)
71
+ // but we allow `impl Trait` in `GenericArgs`
72
+ // iff there are no more PathSegments.
73
+ if let Some ( ref qself) = * qself {
74
+ // `impl Trait` in `qself` is always illegal
75
+ self . with_banned_impl_trait ( |this| this. visit_ty ( & qself. ty ) ) ;
76
+ }
77
+
78
+ // Note that there should be a call to visit_path here,
79
+ // so if any logic is added to process `Path`s a call to it should be
80
+ // added both in visit_path and here. This code mirrors visit::walk_path.
81
+ for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
82
+ // Allow `impl Trait` iff we're on the final path segment
83
+ if i == path. segments . len ( ) - 1 {
84
+ self . visit_path_segment ( path. span , segment) ;
85
+ } else {
86
+ self . with_banned_impl_trait ( |this| {
87
+ this. visit_path_segment ( path. span , segment)
88
+ } ) ;
89
+ }
90
+ }
91
+ }
92
+ _ => visit:: walk_ty ( self , t) ,
93
+ }
94
+ }
95
+
26
96
fn err_handler ( & self ) -> & errors:: Handler {
27
97
& self . session . diagnostic ( )
28
98
}
@@ -267,6 +337,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
267
337
self . no_questions_in_bounds ( bounds, "trait object types" , false ) ;
268
338
}
269
339
TyKind :: ImplTrait ( _, ref bounds) => {
340
+ if self . is_impl_trait_banned {
341
+ struct_span_err ! ( self . session, ty. span, E0667 ,
342
+ "`impl Trait` is not allowed in path parameters" ) . emit ( ) ;
343
+ }
344
+
345
+ if let Some ( outer_impl_trait) = self . outer_impl_trait {
346
+ struct_span_err ! ( self . session, ty. span, E0666 ,
347
+ "nested `impl Trait` is not allowed" )
348
+ . span_label ( outer_impl_trait, "outer `impl Trait`" )
349
+ . span_label ( ty. span , "nested `impl Trait` here" )
350
+ . emit ( ) ;
351
+
352
+ }
270
353
if !bounds. iter ( )
271
354
. any ( |b| if let GenericBound :: Trait ( ..) = * b { true } else { false } ) {
272
355
self . err_handler ( ) . span_err ( ty. span , "at least one trait must be specified" ) ;
@@ -275,7 +358,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
275
358
_ => { }
276
359
}
277
360
278
- visit :: walk_ty ( self , ty)
361
+ self . walk_ty ( ty)
279
362
}
280
363
281
364
fn visit_label ( & mut self , label : & ' a Label ) {
@@ -414,6 +497,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
414
497
visit:: walk_foreign_item ( self , fi)
415
498
}
416
499
500
+ // Mirrors visit::walk_generic_args, but tracks relevant state
501
+ fn visit_generic_args ( & mut self , _: Span , generic_args : & ' a GenericArgs ) {
502
+ match * generic_args {
503
+ GenericArgs :: AngleBracketed ( ref data) => {
504
+ walk_list ! ( self , visit_generic_arg, & data. args) ;
505
+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
506
+ // are allowed to contain nested `impl Trait`.
507
+ self . with_impl_trait ( None , |this| {
508
+ walk_list ! ( this, visit_assoc_type_binding, & data. bindings) ;
509
+ } ) ;
510
+ }
511
+ GenericArgs :: Parenthesized ( ref data) => {
512
+ walk_list ! ( self , visit_ty, & data. inputs) ;
513
+ if let Some ( ref type_) = data. output {
514
+ // `-> Foo` syntax is essentially an associated type binding,
515
+ // so it is also allowed to contain nested `impl Trait`.
516
+ self . with_impl_trait ( None , |this| visit:: walk_ty ( this, type_) ) ;
517
+ }
518
+ }
519
+ }
520
+ }
521
+
417
522
fn visit_generics ( & mut self , generics : & ' a Generics ) {
418
523
let mut seen_non_lifetime_param = false ;
419
524
let mut seen_default = None ;
@@ -490,148 +595,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
490
595
}
491
596
}
492
597
493
- // Bans nested `impl Trait`, e.g., `impl Into<impl Debug>`.
494
- // Nested `impl Trait` _is_ allowed in associated type position,
495
- // e.g `impl Iterator<Item=impl Debug>`
496
- struct NestedImplTraitVisitor < ' a > {
497
- session : & ' a Session ,
498
- outer_impl_trait : Option < Span > ,
499
- }
500
-
501
- impl < ' a > NestedImplTraitVisitor < ' a > {
502
- fn with_impl_trait < F > ( & mut self , outer_impl_trait : Option < Span > , f : F )
503
- where F : FnOnce ( & mut NestedImplTraitVisitor < ' a > )
504
- {
505
- let old_outer_impl_trait = self . outer_impl_trait ;
506
- self . outer_impl_trait = outer_impl_trait;
507
- f ( self ) ;
508
- self . outer_impl_trait = old_outer_impl_trait;
509
- }
510
- }
511
-
512
-
513
- impl < ' a > Visitor < ' a > for NestedImplTraitVisitor < ' a > {
514
- fn visit_ty ( & mut self , t : & ' a Ty ) {
515
- if let TyKind :: ImplTrait ( ..) = t. node {
516
- if let Some ( outer_impl_trait) = self . outer_impl_trait {
517
- struct_span_err ! ( self . session, t. span, E0666 ,
518
- "nested `impl Trait` is not allowed" )
519
- . span_label ( outer_impl_trait, "outer `impl Trait`" )
520
- . span_label ( t. span , "nested `impl Trait` here" )
521
- . emit ( ) ;
522
-
523
- }
524
- self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) ) ;
525
- } else {
526
- visit:: walk_ty ( self , t) ;
527
- }
528
- }
529
- fn visit_generic_args ( & mut self , _: Span , generic_args : & ' a GenericArgs ) {
530
- match * generic_args {
531
- GenericArgs :: AngleBracketed ( ref data) => {
532
- for arg in & data. args {
533
- self . visit_generic_arg ( arg)
534
- }
535
- for type_binding in & data. bindings {
536
- // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
537
- // are allowed to contain nested `impl Trait`.
538
- self . with_impl_trait ( None , |this| visit:: walk_ty ( this, & type_binding. ty ) ) ;
539
- }
540
- }
541
- GenericArgs :: Parenthesized ( ref data) => {
542
- for type_ in & data. inputs {
543
- self . visit_ty ( type_) ;
544
- }
545
- if let Some ( ref type_) = data. output {
546
- // `-> Foo` syntax is essentially an associated type binding,
547
- // so it is also allowed to contain nested `impl Trait`.
548
- self . with_impl_trait ( None , |this| visit:: walk_ty ( this, type_) ) ;
549
- }
550
- }
551
- }
552
- }
553
-
554
- fn visit_mac ( & mut self , _mac : & Spanned < Mac_ > ) {
555
- // covered in AstValidator
556
- }
557
- }
558
-
559
- // Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
560
- struct ImplTraitProjectionVisitor < ' a > {
561
- session : & ' a Session ,
562
- is_banned : bool ,
563
- }
564
-
565
- impl < ' a > ImplTraitProjectionVisitor < ' a > {
566
- fn with_ban < F > ( & mut self , f : F )
567
- where F : FnOnce ( & mut ImplTraitProjectionVisitor < ' a > )
568
- {
569
- let old_is_banned = self . is_banned ;
570
- self . is_banned = true ;
571
- f ( self ) ;
572
- self . is_banned = old_is_banned;
573
- }
574
- }
575
-
576
- impl < ' a > Visitor < ' a > for ImplTraitProjectionVisitor < ' a > {
577
- fn visit_ty ( & mut self , t : & ' a Ty ) {
578
- match t. node {
579
- TyKind :: ImplTrait ( ..) => {
580
- if self . is_banned {
581
- struct_span_err ! ( self . session, t. span, E0667 ,
582
- "`impl Trait` is not allowed in path parameters" ) . emit ( ) ;
583
- }
584
- }
585
- TyKind :: Path ( ref qself, ref path) => {
586
- // We allow these:
587
- // - `Option<impl Trait>`
588
- // - `option::Option<impl Trait>`
589
- // - `option::Option<T>::Foo<impl Trait>
590
- //
591
- // But not these:
592
- // - `<impl Trait>::Foo`
593
- // - `option::Option<impl Trait>::Foo`.
594
- //
595
- // To implement this, we disallow `impl Trait` from `qself`
596
- // (for cases like `<impl Trait>::Foo>`)
597
- // but we allow `impl Trait` in `GenericArgs`
598
- // iff there are no more PathSegments.
599
- if let Some ( ref qself) = * qself {
600
- // `impl Trait` in `qself` is always illegal
601
- self . with_ban ( |this| this. visit_ty ( & qself. ty ) ) ;
602
- }
603
-
604
- for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
605
- // Allow `impl Trait` iff we're on the final path segment
606
- if i == path. segments . len ( ) - 1 {
607
- visit:: walk_path_segment ( self , path. span , segment) ;
608
- } else {
609
- self . with_ban ( |this|
610
- visit:: walk_path_segment ( this, path. span , segment) ) ;
611
- }
612
- }
613
- }
614
- _ => visit:: walk_ty ( self , t) ,
615
- }
616
- }
617
-
618
- fn visit_mac ( & mut self , _mac : & Spanned < Mac_ > ) {
619
- // covered in AstValidator
620
- }
621
- }
622
-
623
598
pub fn check_crate ( session : & Session , krate : & Crate ) {
624
- visit:: walk_crate (
625
- & mut NestedImplTraitVisitor {
626
- session,
627
- outer_impl_trait : None ,
628
- } , krate) ;
629
-
630
- visit:: walk_crate (
631
- & mut ImplTraitProjectionVisitor {
632
- session,
633
- is_banned : false ,
634
- } , krate) ;
635
-
636
- visit:: walk_crate ( & mut AstValidator { session } , krate)
599
+ visit:: walk_crate ( & mut AstValidator {
600
+ session,
601
+ outer_impl_trait : None ,
602
+ is_impl_trait_banned : false ,
603
+ } , krate)
637
604
}
0 commit comments