Repository: rust-lang/rustfmt (rust)

Issue:
Generic associated impl trait type with bounds on self formatted to broken code
### Describe the bug

When specifying an impl trait type alias for a generic associated type with a lifetime bound on `Self`, rustfmt will remove the bound, causing a compiler error, i.e.:

```rust
impl SomeTrait for SomeType {
    type SomeGAT<'a> where Self: 'a = impl SomeOtherTrait;
}
```
will be changed to
```rust
impl SomeTrait for SomeType {
    type SomeGAT<'a> = impl SomeOtherTrait;
}
```

### To Reproduce
The following code compiles, but when running rustfmt on it it will remove the `Self` bound `where Self" 'a` in the implementation  for Foo leading to a compiler error:

```rust
#![allow(incomplete_features)]
#![feature(generic_associated_types)]
#![feature(min_type_alias_impl_trait)]

struct Foo<'b>(&'b ());

trait Iterable {
    type Iter<'a>
    where
        Self: 'a;
    fn iter(&self) -> Self::Iter<'_>;
}

impl<'b> Iterable for Foo<'b> {
    type Iter<'a> where Self: 'a = impl Iterator + 'a;

    fn iter(&self) -> Self::Iter<'_> {
        std::iter::once(self.0)
    }
}
```

### Expected behavior
The above code compiles and should not be formatted so it doesn't compile.

### Meta
- rustfmt 1.4.37-nightly (014026d 2021-07-19)
- From where did you install rustfmt?: rustup
- How do you run rustfmt: rustfmt, sublime RustFmt package

Pull request:
handle GAT types in impls with self bounds
Fixes #4911 

Patch:
diff --git a/src/items.rs b/src/items.rs
index 0542358c..1a56acc7 100644
--- a/src/items.rs
+++ b/src/items.rs
@@ -1497,7 +1497,7 @@ fn format_tuple_struct(
     Some(result)
 }
 
-fn rewrite_type<R: Rewrite>(
+pub(crate) fn rewrite_type<R: Rewrite>(
     context: &RewriteContext<'_>,
     indent: Indent,
     ident: symbol::Ident,
@@ -1841,29 +1841,6 @@ fn rewrite_static(
         Some(format!("{}{};", prefix, ty_str))
     }
 }
-
-pub(crate) fn rewrite_type_alias(
-    ident: symbol::Ident,
-    ty_opt: Option<&ptr::P<ast::Ty>>,
-    generics: &ast::Generics,
-    generic_bounds_opt: Option<&ast::GenericBounds>,
-    context: &RewriteContext<'_>,
-    indent: Indent,
-    vis: &ast::Visibility,
-    span: Span,
-) -> Option<String> {
-    rewrite_type(
-        context,
-        indent,
-        ident,
-        vis,
-        generics,
-        generic_bounds_opt,
-        ty_opt,
-        span,
-    )
-}
-
 struct OpaqueType<'a> {
     bounds: &'a ast::GenericBounds,
 }
@@ -1877,32 +1854,7 @@ impl<'a> Rewrite for OpaqueType<'a> {
     }
 }
 
-pub(crate) fn rewrite_opaque_impl_type(
-    context: &RewriteContext<'_>,
-    ident: symbol::Ident,
-    generics: &ast::Generics,
-    generic_bounds: &ast::GenericBounds,
-    indent: Indent,
-) -> Option<String> {
-    let ident_str = rewrite_ident(context, ident);
-    // 5 = "type "
-    let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
-    let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
-    let prefix = format!("type {} =", generics_str);
-    let rhs = OpaqueType {
-        bounds: generic_bounds,
-    };
-
-    rewrite_assign_rhs(
-        context,
-        &prefix,
-        &rhs,
-        Shape::indented(indent, context.config).sub_width(1)?,
-    )
-    .map(|s| s + ";")
-}
-
-pub(crate) fn rewrite_associated_impl_type(
+pub(crate) fn rewrite_impl_type(
     ident: symbol::Ident,
     vis: &ast::Visibility,
     defaultness: ast::Defaultness,
@@ -1912,7 +1864,25 @@ pub(crate) fn rewrite_associated_impl_type(
     indent: Indent,
     span: Span,
 ) -> Option<String> {
-    let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis, span)?;
+    // Opaque type
+    let result = if let Some(rustc_ast::ast::Ty {
+        kind: ast::TyKind::ImplTrait(_, ref bounds),
+        ..
+    }) = ty_opt.map(|t| &**t)
+    {
+        rewrite_type(
+            context,
+            indent,
+            ident,
+            &DEFAULT_VISIBILITY,
+            generics,
+            None,
+            Some(&OpaqueType { bounds }),
+            span,
+        )
+    } else {
+        rewrite_type(context, indent, ident, vis, generics, None, ty_opt, span)
+    }?;
 
     match defaultness {
         ast::Defaultness::Default(..) => Some(format!("default {}", result)),
@@ -3164,14 +3134,14 @@ impl Rewrite for ast::ForeignItem {
             ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
                 let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
                     **ty_alias_kind;
-                rewrite_type_alias(
-                    self.ident,
-                    type_default.as_ref(),
-                    generics,
-                    Some(generic_bounds),
+                rewrite_type(
                     &context,
                     shape.indent,
+                    self.ident,
                     &self.vis,
+                    generics,
+                    Some(generic_bounds),
+                    type_default.as_ref(),
                     self.span,
                 )
             }
diff --git a/src/visitor.rs b/src/visitor.rs
index 3f251bf7..12a3281e 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -11,9 +11,9 @@ use crate::config::Version;
 use crate::config::{BraceStyle, Config};
 use crate::coverage::transform_missing_snippet;
 use crate::items::{
-    format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
-    rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type,
-    rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts,
+    format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
+    rewrite_impl_type, rewrite_opaque_type, rewrite_type, FnBraceStyle, FnSig, StaticParts,
+    StructParts,
 };
 use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
 use crate::modules::Module;
@@ -579,14 +579,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                         **alias_kind;
                     match ty {
                         Some(ty) => {
-                            let rewrite = rewrite_type_alias(
-                                item.ident,
-                                Some(&*ty),
-                                generics,
-                                Some(generic_bounds),
+                            let rewrite = rewrite_type(
                                 &self.get_context(),
                                 self.block_indent,
+                                item.ident,
                                 &item.vis,
+                                generics,
+                                Some(generic_bounds),
+                                Some(&*ty),
                                 item.span,
                             );
                             self.push_rewrite(item.span, rewrite);
@@ -665,14 +665,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
             ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
                 let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
                     **ty_alias_kind;
-                let rewrite = rewrite_type_alias(
-                    ti.ident,
-                    type_default.as_ref(),
-                    generics,
-                    Some(generic_bounds),
+                let rewrite = rewrite_type(
                     &self.get_context(),
                     self.block_indent,
+                    ti.ident,
                     &ti.vis,
+                    generics,
+                    Some(generic_bounds),
+                    type_default.as_ref(),
                     ti.span,
                 );
                 self.push_rewrite(ti.span, rewrite);
@@ -715,8 +715,9 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
             ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
             ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
                 let ast::TyAliasKind(defaultness, ref generics, _, ref ty) = **ty_alias_kind;
-                let rewrite_associated = || {
-                    rewrite_associated_impl_type(
+                self.push_rewrite(
+                    ii.span,
+                    rewrite_impl_type(
                         ii.ident,
                         &ii.vis,
                         defaultness,
@@ -725,22 +726,8 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                         &self.get_context(),
                         self.block_indent,
                         ii.span,
-                    )
-                };
-                let rewrite = match ty {
-                    None => rewrite_associated(),
-                    Some(ty) => match ty.kind {
-                        ast::TyKind::ImplTrait(_, ref bounds) => rewrite_opaque_impl_type(
-                            &self.get_context(),
-                            ii.ident,
-                            generics,
-                            bounds,
-                            self.block_indent,
-                        ),
-                        _ => rewrite_associated(),
-                    },
-                };
-                self.push_rewrite(ii.span, rewrite);
+                    ),
+                );
             }
             ast::AssocItemKind::MacCall(ref mac) => {
                 self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);


Test patch:
diff --git a/tests/source/issue_4911.rs b/tests/source/issue_4911.rs
new file mode 100644
index 00000000..21ef6c6c
--- /dev/null
+++ b/tests/source/issue_4911.rs
@@ -0,0 +1,6 @@
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+    type SomeGAT<'a> where Self: 'a = impl SomeOtherTrait;
+}
\ No newline at end of file
diff --git a/tests/target/issue_4911.rs b/tests/target/issue_4911.rs
new file mode 100644
index 00000000..890a6226
--- /dev/null
+++ b/tests/target/issue_4911.rs
@@ -0,0 +1,9 @@
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+    type SomeGAT<'a>
+    where
+        Self: 'a,
+    = impl SomeOtherTrait;
+}