6
6
// This pass is supposed to perform only simple checks not requiring name resolution
7
7
// or type checking or some other kind of complex analysis.
8
8
9
+ use std:: mem;
9
10
use rustc:: lint;
10
11
use rustc:: session:: Session ;
11
12
use syntax:: ast:: * ;
@@ -20,9 +21,73 @@ use errors::Applicability;
20
21
21
22
struct AstValidator < ' a > {
22
23
session : & ' a Session ,
24
+
25
+ // Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
26
+ // Nested `impl Trait` _is_ allowed in associated type position,
27
+ // e.g `impl Iterator<Item=impl Debug>`
28
+ outer_impl_trait : Option < Span > ,
29
+
30
+ // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
31
+ // or `Foo::Bar<impl Trait>`
32
+ is_impl_trait_banned : bool ,
23
33
}
24
34
25
35
impl < ' a > AstValidator < ' a > {
36
+ fn with_banned_impl_trait ( & mut self , f : impl FnOnce ( & mut Self ) ) {
37
+ let old = mem:: replace ( & mut self . is_impl_trait_banned , true ) ;
38
+ f ( self ) ;
39
+ self . is_impl_trait_banned = old;
40
+ }
41
+
42
+ fn with_impl_trait ( & mut self , outer_impl_trait : Option < Span > , f : impl FnOnce ( & mut Self ) ) {
43
+ let old = mem:: replace ( & mut self . outer_impl_trait , outer_impl_trait) ;
44
+ f ( self ) ;
45
+ self . outer_impl_trait = old;
46
+ }
47
+
48
+ // Mirrors visit::walk_ty, but tracks relevant state
49
+ fn walk_ty ( & mut self , t : & ' a Ty ) {
50
+ match t. node {
51
+ TyKind :: ImplTrait ( ..) => {
52
+ self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) )
53
+ }
54
+ TyKind :: Path ( ref qself, ref path) => {
55
+ // We allow these:
56
+ // - `Option<impl Trait>`
57
+ // - `option::Option<impl Trait>`
58
+ // - `option::Option<T>::Foo<impl Trait>
59
+ //
60
+ // But not these:
61
+ // - `<impl Trait>::Foo`
62
+ // - `option::Option<impl Trait>::Foo`.
63
+ //
64
+ // To implement this, we disallow `impl Trait` from `qself`
65
+ // (for cases like `<impl Trait>::Foo>`)
66
+ // but we allow `impl Trait` in `GenericArgs`
67
+ // iff there are no more PathSegments.
68
+ if let Some ( ref qself) = * qself {
69
+ // `impl Trait` in `qself` is always illegal
70
+ self . with_banned_impl_trait ( |this| this. visit_ty ( & qself. ty ) ) ;
71
+ }
72
+
73
+ // Note that there should be a call to visit_path here,
74
+ // so if any logic is added to process `Path`s a call to it should be
75
+ // added both in visit_path and here. This code mirrors visit::walk_path.
76
+ for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
77
+ // Allow `impl Trait` iff we're on the final path segment
78
+ if i == path. segments . len ( ) - 1 {
79
+ self . visit_path_segment ( path. span , segment) ;
80
+ } else {
81
+ self . with_banned_impl_trait ( |this| {
82
+ this. visit_path_segment ( path. span , segment)
83
+ } ) ;
84
+ }
85
+ }
86
+ }
87
+ _ => visit:: walk_ty ( self , t) ,
88
+ }
89
+ }
90
+
26
91
fn err_handler ( & self ) -> & errors:: Handler {
27
92
& self . session . diagnostic ( )
28
93
}
@@ -267,6 +332,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
267
332
self . no_questions_in_bounds ( bounds, "trait object types" , false ) ;
268
333
}
269
334
TyKind :: ImplTrait ( _, ref bounds) => {
335
+ if self . is_impl_trait_banned {
336
+ struct_span_err ! ( self . session, ty. span, E0667 ,
337
+ "`impl Trait` is not allowed in path parameters" ) . emit ( ) ;
338
+ }
339
+
340
+ if let Some ( outer_impl_trait) = self . outer_impl_trait {
341
+ struct_span_err ! ( self . session, ty. span, E0666 ,
342
+ "nested `impl Trait` is not allowed" )
343
+ . span_label ( outer_impl_trait, "outer `impl Trait`" )
344
+ . span_label ( ty. span , "nested `impl Trait` here" )
345
+ . emit ( ) ;
346
+
347
+ }
270
348
if !bounds. iter ( )
271
349
. any ( |b| if let GenericBound :: Trait ( ..) = * b { true } else { false } ) {
272
350
self . err_handler ( ) . span_err ( ty. span , "at least one trait must be specified" ) ;
@@ -275,7 +353,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
275
353
_ => { }
276
354
}
277
355
278
- visit :: walk_ty ( self , ty)
356
+ self . walk_ty ( ty)
279
357
}
280
358
281
359
fn visit_label ( & mut self , label : & ' a Label ) {
@@ -414,6 +492,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
414
492
visit:: walk_foreign_item ( self , fi)
415
493
}
416
494
495
+ // Mirrors visit::walk_generic_args, but tracks relevant state
496
+ fn visit_generic_args ( & mut self , _: Span , generic_args : & ' a GenericArgs ) {
497
+ match * generic_args {
498
+ GenericArgs :: AngleBracketed ( ref data) => {
499
+ walk_list ! ( self , visit_generic_arg, & data. args) ;
500
+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
501
+ // are allowed to contain nested `impl Trait`.
502
+ self . with_impl_trait ( None , |this| {
503
+ walk_list ! ( this, visit_assoc_type_binding, & data. bindings) ;
504
+ } ) ;
505
+ }
506
+ GenericArgs :: Parenthesized ( ref data) => {
507
+ walk_list ! ( self , visit_ty, & data. inputs) ;
508
+ if let Some ( ref type_) = data. output {
509
+ // `-> Foo` syntax is essentially an associated type binding,
510
+ // so it is also allowed to contain nested `impl Trait`.
511
+ self . with_impl_trait ( None , |this| visit:: walk_ty ( this, type_) ) ;
512
+ }
513
+ }
514
+ }
515
+ }
516
+
417
517
fn visit_generics ( & mut self , generics : & ' a Generics ) {
418
518
let mut seen_non_lifetime_param = false ;
419
519
let mut seen_default = None ;
@@ -490,148 +590,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
490
590
}
491
591
}
492
592
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
593
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)
594
+ visit:: walk_crate ( & mut AstValidator {
595
+ session,
596
+ outer_impl_trait : None ,
597
+ is_impl_trait_banned : false ,
598
+ } , krate)
637
599
}
0 commit comments