@@ -419,6 +419,141 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
419419 }
420420}
421421
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+
422545pub 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+
423558 visit:: walk_crate ( & mut AstValidator { session : session } , krate)
424559}
0 commit comments