@@ -24,6 +24,31 @@ use syntax_pos::Span;
24
24
use errors:: Applicability ;
25
25
use log:: debug;
26
26
27
+ #[ derive( Copy , Clone , Debug ) ]
28
+ struct OuterImplTrait {
29
+ span : Span ,
30
+
31
+ /// rust-lang/rust#57979: a bug in original implementation caused
32
+ /// us to fail sometimes to record an outer `impl Trait`.
33
+ /// Therefore, in order to reliably issue a warning (rather than
34
+ /// an error) in the *precise* places where we are newly injecting
35
+ /// the diagnostic, we have to distinguish between the places
36
+ /// where the outer `impl Trait` has always been recorded, versus
37
+ /// the places where it has only recently started being recorded.
38
+ only_recorded_since_pull_request_57730 : bool ,
39
+ }
40
+
41
+ impl OuterImplTrait {
42
+ /// This controls whether we should downgrade the nested impl
43
+ /// trait diagnostic to a warning rather than an error, based on
44
+ /// whether the outer impl trait had been improperly skipped in
45
+ /// earlier implementations of the analysis on the stable
46
+ /// compiler.
47
+ fn should_warn_instead_of_error ( & self ) -> bool {
48
+ self . only_recorded_since_pull_request_57730
49
+ }
50
+ }
51
+
27
52
struct AstValidator < ' a > {
28
53
session : & ' a Session ,
29
54
has_proc_macro_decls : bool ,
@@ -32,7 +57,7 @@ struct AstValidator<'a> {
32
57
// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
33
58
// Nested `impl Trait` _is_ allowed in associated type position,
34
59
// e.g `impl Iterator<Item=impl Debug>`
35
- outer_impl_trait : Option < Span > ,
60
+ outer_impl_trait : Option < OuterImplTrait > ,
36
61
37
62
// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
38
63
// or `Foo::Bar<impl Trait>`
@@ -44,18 +69,11 @@ struct AstValidator<'a> {
44
69
// impl trait in projections), and thus miss some cases. We track
45
70
// whether we should downgrade to a warning for short-term via
46
71
// these booleans.
47
- warning_period_57979_nested_impl_trait : bool ,
72
+ warning_period_57979_didnt_record_next_impl_trait : bool ,
48
73
warning_period_57979_impl_trait_in_proj : bool ,
49
74
}
50
75
51
76
impl < ' a > AstValidator < ' a > {
52
- fn with_nested_impl_trait_warning < T > ( & mut self , v : bool , f : impl FnOnce ( & mut Self ) -> T ) -> T {
53
- let old = mem:: replace ( & mut self . warning_period_57979_nested_impl_trait , v) ;
54
- let ret = f ( self ) ;
55
- self . warning_period_57979_nested_impl_trait = old;
56
- ret
57
- }
58
-
59
77
fn with_impl_trait_in_proj_warning < T > ( & mut self , v : bool , f : impl FnOnce ( & mut Self ) -> T ) -> T {
60
78
let old = mem:: replace ( & mut self . warning_period_57979_impl_trait_in_proj , v) ;
61
79
let ret = f ( self ) ;
@@ -69,17 +87,53 @@ impl<'a> AstValidator<'a> {
69
87
self . is_impl_trait_banned = old;
70
88
}
71
89
72
- fn with_impl_trait ( & mut self , outer_impl_trait : Option < Span > , f : impl FnOnce ( & mut Self ) ) {
73
- let old = mem:: replace ( & mut self . outer_impl_trait , outer_impl_trait ) ;
90
+ fn with_impl_trait ( & mut self , outer : Option < OuterImplTrait > , f : impl FnOnce ( & mut Self ) ) {
91
+ let old = mem:: replace ( & mut self . outer_impl_trait , outer ) ;
74
92
f ( self ) ;
75
93
self . outer_impl_trait = old;
76
94
}
77
95
96
+ fn visit_assoc_type_binding_from_generic_args ( & mut self , type_binding : & ' a TypeBinding ) {
97
+ // rust-lang/rust#57979: bug in old visit_generic_args called
98
+ // walk_ty rather than visit_ty, skipping outer `impl Trait`
99
+ // if it happened to occur at `type_binding.ty`
100
+ if let TyKind :: ImplTrait ( ..) = type_binding. ty . node {
101
+ self . warning_period_57979_didnt_record_next_impl_trait = true ;
102
+ }
103
+ self . visit_assoc_type_binding ( type_binding) ;
104
+ }
105
+
106
+ fn visit_ty_from_generic_args ( & mut self , ty : & ' a Ty ) {
107
+ // rust-lang/rust#57979: bug in old visit_generic_args called
108
+ // walk_ty rather than visit_ty, skippping outer `impl Trait`
109
+ // if it happened to occur at `ty`
110
+ if let TyKind :: ImplTrait ( ..) = ty. node {
111
+ self . warning_period_57979_didnt_record_next_impl_trait = true ;
112
+ }
113
+ self . visit_ty ( ty) ;
114
+ }
115
+
116
+ fn outer_impl_trait ( & mut self , span : Span ) -> OuterImplTrait {
117
+ let only_recorded_since_pull_request_57730 =
118
+ self . warning_period_57979_didnt_record_next_impl_trait ;
119
+
120
+ // (this flag is designed to be set to true and then only
121
+ // reach the construction point for the outer impl trait once,
122
+ // so its safe and easiest to unconditionally reset it to
123
+ // false)
124
+ self . warning_period_57979_didnt_record_next_impl_trait = false ;
125
+
126
+ OuterImplTrait {
127
+ span, only_recorded_since_pull_request_57730,
128
+ }
129
+ }
130
+
78
131
// Mirrors visit::walk_ty, but tracks relevant state
79
132
fn walk_ty ( & mut self , t : & ' a Ty ) {
80
133
match t. node {
81
134
TyKind :: ImplTrait ( ..) => {
82
- self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) )
135
+ let outer_impl_trait = self . outer_impl_trait ( t. span ) ;
136
+ self . with_impl_trait ( Some ( outer_impl_trait) , |this| visit:: walk_ty ( this, t) )
83
137
}
84
138
TyKind :: Path ( ref qself, ref path) => {
85
139
// We allow these:
@@ -441,18 +495,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
441
495
}
442
496
443
497
if let Some ( outer_impl_trait) = self . outer_impl_trait {
444
- if self . warning_period_57979_nested_impl_trait {
498
+ if outer_impl_trait . should_warn_instead_of_error ( ) {
445
499
self . session . buffer_lint_with_diagnostic (
446
500
NESTED_IMPL_TRAIT , ty. id , ty. span ,
447
501
"nested `impl Trait` is not allowed" ,
448
502
BuiltinLintDiagnostics :: NestedImplTrait {
449
- outer_impl_trait_span : outer_impl_trait,
503
+ outer_impl_trait_span : outer_impl_trait. span ,
450
504
inner_impl_trait_span : ty. span ,
451
505
} ) ;
452
506
} else {
453
507
struct_span_err ! ( self . session, ty. span, E0666 ,
454
508
"nested `impl Trait` is not allowed" )
455
- . span_label ( outer_impl_trait, "outer `impl Trait`" )
509
+ . span_label ( outer_impl_trait. span , "outer `impl Trait`" )
456
510
. span_label ( ty. span , "nested `impl Trait` here" )
457
511
. emit ( ) ;
458
512
}
@@ -650,22 +704,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
650
704
} , arg. span ( ) , None )
651
705
} ) , GenericPosition :: Arg , generic_args. span ( ) ) ;
652
706
653
- self . with_nested_impl_trait_warning ( true , |this| {
654
- // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
655
- // are allowed to contain nested `impl Trait`.
656
- this. with_impl_trait ( None , |this| {
657
- walk_list ! ( this, visit_assoc_type_binding, & data. bindings) ;
658
- } ) ;
707
+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
708
+ // are allowed to contain nested `impl Trait`.
709
+ self . with_impl_trait ( None , |this| {
710
+ walk_list ! ( this, visit_assoc_type_binding_from_generic_args, & data. bindings) ;
659
711
} ) ;
660
712
}
661
713
GenericArgs :: Parenthesized ( ref data) => {
662
714
walk_list ! ( self , visit_ty, & data. inputs) ;
663
715
if let Some ( ref type_) = data. output {
664
- self . with_nested_impl_trait_warning ( true , |this| {
665
- // `-> Foo` syntax is essentially an associated type binding,
666
- // so it is also allowed to contain nested `impl Trait`.
667
- this. with_impl_trait ( None , |this| this. visit_ty ( type_) ) ;
668
- } ) ;
716
+ // `-> Foo` syntax is essentially an associated type binding,
717
+ // so it is also allowed to contain nested `impl Trait`.
718
+ self . with_impl_trait ( None , |this| this. visit_ty_from_generic_args ( type_) ) ;
669
719
}
670
720
}
671
721
}
@@ -767,7 +817,7 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
767
817
has_global_allocator : false ,
768
818
outer_impl_trait : None ,
769
819
is_impl_trait_banned : false ,
770
- warning_period_57979_nested_impl_trait : false ,
820
+ warning_period_57979_didnt_record_next_impl_trait : false ,
771
821
warning_period_57979_impl_trait_in_proj : false ,
772
822
} ;
773
823
visit:: walk_crate ( & mut validator, krate) ;
0 commit comments