@@ -24,6 +24,31 @@ use syntax_pos::Span;
2424use errors:: Applicability ;
2525use log:: debug;
2626
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+
2752struct AstValidator < ' a > {
2853 session : & ' a Session ,
2954 has_proc_macro_decls : bool ,
@@ -32,7 +57,7 @@ struct AstValidator<'a> {
3257 // Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
3358 // Nested `impl Trait` _is_ allowed in associated type position,
3459 // e.g `impl Iterator<Item=impl Debug>`
35- outer_impl_trait : Option < Span > ,
60+ outer_impl_trait : Option < OuterImplTrait > ,
3661
3762 // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
3863 // or `Foo::Bar<impl Trait>`
@@ -44,18 +69,11 @@ struct AstValidator<'a> {
4469 // impl trait in projections), and thus miss some cases. We track
4570 // whether we should downgrade to a warning for short-term via
4671 // these booleans.
47- warning_period_57979_nested_impl_trait : bool ,
72+ warning_period_57979_didnt_record_next_impl_trait : bool ,
4873 warning_period_57979_impl_trait_in_proj : bool ,
4974}
5075
5176impl < ' 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-
5977 fn with_impl_trait_in_proj_warning < T > ( & mut self , v : bool , f : impl FnOnce ( & mut Self ) -> T ) -> T {
6078 let old = mem:: replace ( & mut self . warning_period_57979_impl_trait_in_proj , v) ;
6179 let ret = f ( self ) ;
@@ -69,17 +87,53 @@ impl<'a> AstValidator<'a> {
6987 self . is_impl_trait_banned = old;
7088 }
7189
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 ) ;
7492 f ( self ) ;
7593 self . outer_impl_trait = old;
7694 }
7795
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+
78131 // Mirrors visit::walk_ty, but tracks relevant state
79132 fn walk_ty ( & mut self , t : & ' a Ty ) {
80133 match t. node {
81134 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) )
83137 }
84138 TyKind :: Path ( ref qself, ref path) => {
85139 // We allow these:
@@ -441,18 +495,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
441495 }
442496
443497 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 ( ) {
445499 self . session . buffer_lint_with_diagnostic (
446500 NESTED_IMPL_TRAIT , ty. id , ty. span ,
447501 "nested `impl Trait` is not allowed" ,
448502 BuiltinLintDiagnostics :: NestedImplTrait {
449- outer_impl_trait_span : outer_impl_trait,
503+ outer_impl_trait_span : outer_impl_trait. span ,
450504 inner_impl_trait_span : ty. span ,
451505 } ) ;
452506 } else {
453507 struct_span_err ! ( self . session, ty. span, E0666 ,
454508 "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`" )
456510 . span_label ( ty. span , "nested `impl Trait` here" )
457511 . emit ( ) ;
458512 }
@@ -650,22 +704,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
650704 } , arg. span ( ) , None )
651705 } ) , GenericPosition :: Arg , generic_args. span ( ) ) ;
652706
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) ;
659711 } ) ;
660712 }
661713 GenericArgs :: Parenthesized ( ref data) => {
662714 walk_list ! ( self , visit_ty, & data. inputs) ;
663715 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_) ) ;
669719 }
670720 }
671721 }
@@ -767,7 +817,7 @@ pub fn check_crate(session: &Session, krate: &Crate) -> (bool, bool) {
767817 has_global_allocator : false ,
768818 outer_impl_trait : None ,
769819 is_impl_trait_banned : false ,
770- warning_period_57979_nested_impl_trait : false ,
820+ warning_period_57979_didnt_record_next_impl_trait : false ,
771821 warning_period_57979_impl_trait_in_proj : false ,
772822 } ;
773823 visit:: walk_crate ( & mut validator, krate) ;
0 commit comments