@@ -420,6 +420,141 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
420420 }
421421}
422422
423+ // Bans nested `impl Trait`, e.g. `impl Into<impl Debug>`.
424+ // Nested `impl Trait` _is_ allowed in associated type position,
425+ // e.g `impl Iterator<Item=impl Debug>`
426+ struct NestedImplTraitVisitor < ' a > {
427+ session : & ' a Session ,
428+ outer_impl_trait : Option < Span > ,
429+ }
430+
431+ impl < ' a > NestedImplTraitVisitor < ' a > {
432+ fn with_impl_trait < F > ( & mut self , outer_impl_trait : Option < Span > , f : F )
433+ where F : FnOnce ( & mut NestedImplTraitVisitor < ' a > )
434+ {
435+ let old_outer_impl_trait = self . outer_impl_trait ;
436+ self . outer_impl_trait = outer_impl_trait;
437+ f ( self ) ;
438+ self . outer_impl_trait = old_outer_impl_trait;
439+ }
440+ }
441+
442+
443+ impl < ' a > Visitor < ' a > for NestedImplTraitVisitor < ' a > {
444+ fn visit_ty ( & mut self , t : & ' a Ty ) {
445+ if let TyKind :: ImplTrait ( _) = t. node {
446+ if let Some ( outer_impl_trait) = self . outer_impl_trait {
447+ struct_span_err ! ( self . session, t. span, E0666 ,
448+ "nested `impl Trait` is not allowed" )
449+ . span_label ( outer_impl_trait, "outer `impl Trait`" )
450+ . span_label ( t. span , "nested `impl Trait` here" )
451+ . emit ( ) ;
452+
453+ }
454+ self . with_impl_trait ( Some ( t. span ) , |this| visit:: walk_ty ( this, t) ) ;
455+ } else {
456+ visit:: walk_ty ( self , t) ;
457+ }
458+ }
459+ fn visit_path_parameters ( & mut self , _: Span , path_parameters : & ' a PathParameters ) {
460+ match * path_parameters {
461+ PathParameters :: AngleBracketed ( ref params) => {
462+ for type_ in & params. types {
463+ self . visit_ty ( type_) ;
464+ }
465+ for type_binding in & params. bindings {
466+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
467+ // are allowed to contain nested `impl Trait`.
468+ self . with_impl_trait ( None , |this| visit:: walk_ty ( this, & type_binding. ty ) ) ;
469+ }
470+ }
471+ PathParameters :: Parenthesized ( ref params) => {
472+ for type_ in & params. inputs {
473+ self . visit_ty ( type_) ;
474+ }
475+ if let Some ( ref type_) = params. output {
476+ // `-> Foo` syntax is essentially an associated type binding,
477+ // so it is also allowed to contain nested `impl Trait`.
478+ self . with_impl_trait ( None , |this| visit:: walk_ty ( this, type_) ) ;
479+ }
480+ }
481+ }
482+ }
483+ }
484+
485+ // Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
486+ struct ImplTraitProjectionVisitor < ' a > {
487+ session : & ' a Session ,
488+ is_banned : bool ,
489+ }
490+
491+ impl < ' a > ImplTraitProjectionVisitor < ' a > {
492+ fn with_ban < F > ( & mut self , f : F )
493+ where F : FnOnce ( & mut ImplTraitProjectionVisitor < ' a > )
494+ {
495+ let old_is_banned = self . is_banned ;
496+ self . is_banned = true ;
497+ f ( self ) ;
498+ self . is_banned = old_is_banned;
499+ }
500+ }
501+
502+ impl < ' a > Visitor < ' a > for ImplTraitProjectionVisitor < ' a > {
503+ fn visit_ty ( & mut self , t : & ' a Ty ) {
504+ match t. node {
505+ TyKind :: ImplTrait ( _) => {
506+ if self . is_banned {
507+ struct_span_err ! ( self . session, t. span, E0667 ,
508+ "`impl Trait` is not allowed in path parameters" )
509+ . emit ( ) ;
510+ }
511+ }
512+ TyKind :: Path ( ref qself, ref path) => {
513+ // We allow these:
514+ // - `Option<impl Trait>`
515+ // - `option::Option<impl Trait>`
516+ // - `option::Option<T>::Foo<impl Trait>
517+ //
518+ // But not these:
519+ // - `<impl Trait>::Foo`
520+ // - `option::Option<impl Trait>::Foo`.
521+ //
522+ // To implement this, we disallow `impl Trait` from `qself`
523+ // (for cases like `<impl Trait>::Foo>`)
524+ // but we allow `impl Trait` in `PathParameters`
525+ // iff there are no more PathSegments.
526+ if let Some ( ref qself) = * qself {
527+ // `impl Trait` in `qself` is always illegal
528+ self . with_ban ( |this| this. visit_ty ( & qself. ty ) ) ;
529+ }
530+
531+ for ( i, segment) in path. segments . iter ( ) . enumerate ( ) {
532+ // Allow `impl Trait` iff we're on the final path segment
533+ if i == ( path. segments . len ( ) - 1 ) {
534+ visit:: walk_path_segment ( self , path. span , segment) ;
535+ } else {
536+ self . with_ban ( |this|
537+ visit:: walk_path_segment ( this, path. span , segment) ) ;
538+ }
539+ }
540+ }
541+ _ => visit:: walk_ty ( self , t) ,
542+ }
543+ }
544+ }
545+
423546pub fn check_crate ( session : & Session , krate : & Crate ) {
547+ visit:: walk_crate (
548+ & mut NestedImplTraitVisitor {
549+ session,
550+ outer_impl_trait : None ,
551+ } , krate) ;
552+
553+ visit:: walk_crate (
554+ & mut ImplTraitProjectionVisitor {
555+ session,
556+ is_banned : false ,
557+ } , krate) ;
558+
424559 visit:: walk_crate ( & mut AstValidator { session : session } , krate)
425560}
0 commit comments