Repository: rust-analyzer/rust-analyzer (rust)

Issue:
"index out of bounds" in chalk when computing completions
```rust
struct S;

impl S {
    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
    }

    fn f(&mut self, v: &[u8]) {
        self.indented(|this| v.$0)
    }
}
```

Requesting completions at `$0` results in:

```
thread '<unnamed>' panicked at 'index out of bounds: the len is 0 but the index is 0', /home/jonas/.cargo/registry/src/github.com-1ecc6299db9ec823/chalk-ir-0.64.0/src/lib.rs:2752:10
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic_bounds_check
   3: <&chalk_ir::SubstFolder<I,A> as chalk_ir::fold::Folder<I>>::fold_free_var_ty
   4: <chalk_ir::Ty<I> as chalk_ir::fold::SuperFold<I>>::super_fold_with
   5: hir_ty::infer::unify::unify
   6: hir_ty::infer::unify::could_unify
   7: hir::Type::could_unify_with
   8: ide_completion::render::compute_type_match
   9: ide_completion::render::render_field
  10: ide_completion::completions::dot::complete_dot
  11: ide_completion::completions
  12: std::panicking::try
  13: ide::Analysis::completions
  14: rust_analyzer::handlers::handle_completion
```

Pull request:
internal: Fix #8931
  - and add some better checking for similar bugs

Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 52d72c3c52..800101c919 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2053,7 +2053,7 @@ impl Type {
         name: Option<&Name>,
         mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
     ) -> Option<T> {
-        let canonical = hir_ty::replace_errors_with_variables(self.ty.clone());
+        let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
         let env = self.env.clone();
         let krate = krate.id;
@@ -2222,7 +2222,7 @@ impl Type {
     }
 
     pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
-        let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone()));
+        let tys = hir_ty::replace_errors_with_variables(&(self.ty.clone(), other.ty.clone()));
         could_unify(db, self.env.clone(), &tys)
     }
 }
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 38bd376bc0..1b5064b5a2 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -505,9 +505,10 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
-        // FIXME: this erases Substs
+        // FIXME: this erases Substs, we should instead record the correct
+        // substitution during inference and use that
         let func = self.resolve_method_call(call)?;
-        let (ty, _) = self.db.value_ty(func.into()).into_value_and_skipped_binders();
+        let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
         let resolver = self.analyze(call.syntax()).resolver;
         let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
         let mut res = ty.as_callable(self.db)?;
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 4bc87a0e20..5ec02d1be7 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -2,12 +2,7 @@
 
 use std::fmt::{self, Write};
 
-use crate::{
-    attr::RawAttrs,
-    generics::{WherePredicate, WherePredicateTypeTarget},
-    path::GenericArg,
-    visibility::RawVisibility,
-};
+use crate::{attr::RawAttrs, visibility::RawVisibility};
 
 use super::*;
 
@@ -75,13 +70,6 @@ impl<'a> Printer<'a> {
         }
     }
 
-    fn whitespace(&mut self) {
-        match self.buf.chars().next_back() {
-            None | Some('\n') | Some(' ') => {}
-            _ => self.buf.push(' '),
-        }
-    }
-
     fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
         let inner = if inner { "!" } else { "" };
         for attr in &**attrs {
@@ -112,8 +100,7 @@ impl<'a> Printer<'a> {
     fn print_fields(&mut self, fields: &Fields) {
         match fields {
             Fields::Record(fields) => {
-                self.whitespace();
-                w!(self, "{{");
+                w!(self, " {{");
                 self.indented(|this| {
                     for field in fields.clone() {
                         let Field { visibility, name, type_ref } = &this.tree[field];
@@ -144,25 +131,6 @@ impl<'a> Printer<'a> {
         }
     }
 
-    fn print_fields_and_where_clause(&mut self, fields: &Fields, params: &GenericParams) {
-        match fields {
-            Fields::Record(_) => {
-                if self.print_where_clause(params) {
-                    wln!(self);
-                }
-                self.print_fields(fields);
-            }
-            Fields::Unit => {
-                self.print_where_clause(params);
-                self.print_fields(fields);
-            }
-            Fields::Tuple(_) => {
-                self.print_fields(fields);
-                self.print_where_clause(params);
-            }
-        }
-    }
-
     fn print_mod_item(&mut self, item: ModItem) {
         self.print_attrs_of(item);
 
@@ -206,7 +174,7 @@ impl<'a> Printer<'a> {
                 let Function {
                     name,
                     visibility,
-                    generic_params,
+                    generic_params: _, // FIXME print these somehow
                     abi,
                     params,
                     ret_type,
@@ -220,9 +188,7 @@ impl<'a> Printer<'a> {
                 if let Some(abi) = abi {
                     w!(self, "extern \"{}\" ", abi);
                 }
-                w!(self, "fn {}", name);
-                self.print_generic_params(generic_params);
-                w!(self, "(");
+                w!(self, "fn {}(", name);
                 if !params.is_empty() {
                     self.indented(|this| {
                         for param in params.clone() {
@@ -242,15 +208,14 @@ impl<'a> Printer<'a> {
                 }
                 w!(self, ") -> ");
                 self.print_type_ref(ret_type);
-                self.print_where_clause(generic_params);
                 wln!(self, ";");
             }
             ModItem::Struct(it) => {
-                let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
+                let Struct { visibility, name, fields, generic_params: _, ast_id: _ } =
+                    &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name);
-                self.print_generic_params(generic_params);
-                self.print_fields_and_where_clause(fields, generic_params);
+                self.print_fields(fields);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
                 } else {
@@ -258,11 +223,11 @@ impl<'a> Printer<'a> {
                 }
             }
             ModItem::Union(it) => {
-                let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
+                let Union { name, visibility, fields, generic_params: _, ast_id: _ } =
+                    &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name);
-                self.print_generic_params(generic_params);
-                self.print_fields_and_where_clause(fields, generic_params);
+                self.print_fields(fields);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
                 } else {
@@ -270,11 +235,10 @@ impl<'a> Printer<'a> {
                 }
             }
             ModItem::Enum(it) => {
-                let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
+                let Enum { name, visibility, variants, generic_params: _, ast_id: _ } =
+                    &self.tree[it];
                 self.print_visibility(*visibility);
-                w!(self, "enum {}", name);
-                self.print_generic_params(generic_params);
-                self.print_where_clause_and_opening_brace(generic_params);
+                w!(self, "enum {} {{", name);
                 self.indented(|this| {
                     for variant in variants.clone() {
                         let Variant { name, fields } = &this.tree[variant];
@@ -322,7 +286,7 @@ impl<'a> Printer<'a> {
                     is_unsafe,
                     bounds,
                     items,
-                    generic_params,
+                    generic_params: _,
                     ast_id: _,
                 } = &self.tree[it];
                 self.print_visibility(*visibility);
@@ -333,12 +297,11 @@ impl<'a> Printer<'a> {
                     w!(self, "auto ");
                 }
                 w!(self, "trait {}", name);
-                self.print_generic_params(generic_params);
                 if !bounds.is_empty() {
                     w!(self, ": ");
                     self.print_type_bounds(bounds);
                 }
-                self.print_where_clause_and_opening_brace(generic_params);
+                w!(self, " {{");
                 self.indented(|this| {
                     for item in &**items {
                         this.print_mod_item((*item).into());
@@ -347,11 +310,15 @@ impl<'a> Printer<'a> {
                 wln!(self, "}}");
             }
             ModItem::Impl(it) => {
-                let Impl { target_trait, self_ty, is_negative, items, generic_params, ast_id: _ } =
-                    &self.tree[it];
-                w!(self, "impl");
-                self.print_generic_params(generic_params);
-                w!(self, " ");
+                let Impl {
+                    target_trait,
+                    self_ty,
+                    is_negative,
+                    items,
+                    generic_params: _,
+                    ast_id: _,
+                } = &self.tree[it];
+                w!(self, "impl ");
                 if *is_negative {
                     w!(self, "!");
                 }
@@ -360,7 +327,7 @@ impl<'a> Printer<'a> {
                     w!(self, " for ");
                 }
                 self.print_type_ref(self_ty);
-                self.print_where_clause_and_opening_brace(generic_params);
+                w!(self, " {{");
                 self.indented(|this| {
                     for item in &**items {
                         this.print_mod_item((*item).into());
@@ -375,12 +342,11 @@ impl<'a> Printer<'a> {
                     bounds,
                     type_ref,
                     is_extern,
-                    generic_params,
+                    generic_params: _,
                     ast_id: _,
                 } = &self.tree[it];
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name);
-                self.print_generic_params(generic_params);
                 if !bounds.is_empty() {
                     w!(self, ": ");
                     self.print_type_bounds(bounds);
@@ -389,7 +355,6 @@ impl<'a> Printer<'a> {
                     w!(self, " = ");
                     self.print_type_ref(ty);
                 }
-                self.print_where_clause(generic_params);
                 w!(self, ";");
                 if *is_extern {
                     w!(self, "  // extern");
@@ -501,7 +466,7 @@ impl<'a> Printer<'a> {
             TypeRef::Macro(_ast_id) => {
                 w!(self, "<macro>");
             }
-            TypeRef::Error => w!(self, "{{unknown}}"),
+            TypeRef::Error => drop(write!(self, "{{unknown}}")),
             TypeRef::ImplTrait(bounds) => {
                 w!(self, "impl ");
                 self.print_type_bounds(bounds);
@@ -528,168 +493,15 @@ impl<'a> Printer<'a> {
     }
 
     fn print_path(&mut self, path: &Path) {
-        match path.type_anchor() {
-            Some(anchor) => {
-                w!(self, "<");
-                self.print_type_ref(anchor);
-                w!(self, ">::");
-            }
-            None => match path.kind() {
-                PathKind::Plain => {}
-                PathKind::Super(0) => w!(self, "self::"),
-                PathKind::Super(n) => {
-                    for _ in 0..*n {
-                        w!(self, "super::");
-                    }
-                }
-                PathKind::Crate => w!(self, "crate::"),
-                PathKind::Abs => w!(self, "::"),
-                PathKind::DollarCrate(_) => w!(self, "$crate::"),
-            },
-        }
-
-        for (i, segment) in path.segments().iter().enumerate() {
-            if i != 0 {
-                w!(self, "::");
-            }
-
-            w!(self, "{}", segment.name);
-            if let Some(generics) = segment.args_and_bindings {
-                // NB: these are all in type position, so `::<` turbofish syntax is not necessary
-                w!(self, "<");
-                let mut first = true;
-                let args = if generics.has_self_type {
-                    let (self_ty, args) = generics.args.split_first().unwrap();
-                    w!(self, "Self=");
-                    self.print_generic_arg(self_ty);
-                    first = false;
-                    args
-                } else {
-                    &generics.args
-                };
-                for arg in args {
-                    if !first {
-                        w!(self, ", ");
-                    }
-                    first = false;
-                    self.print_generic_arg(arg);
-                }
-                for binding in &generics.bindings {
-                    if !first {
-                        w!(self, ", ");
-                    }
-                    first = false;
-                    w!(self, "{}", binding.name);
-                    if !binding.bounds.is_empty() {
-                        w!(self, ": ");
-                        self.print_type_bounds(&binding.bounds);
-                    }
-                    if let Some(ty) = &binding.type_ref {
-                        w!(self, " = ");
-                        self.print_type_ref(ty);
-                    }
-                }
-
-                w!(self, ">");
-            }
-        }
-    }
-
-    fn print_generic_arg(&mut self, arg: &GenericArg) {
-        match arg {
-            GenericArg::Type(ty) => self.print_type_ref(ty),
-            GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
-        }
-    }
-
-    fn print_generic_params(&mut self, params: &GenericParams) {
-        if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() {
-            return;
-        }
-
-        w!(self, "<");
-        let mut first = true;
-        for (_, lt) in params.lifetimes.iter() {
-            if !first {
-                w!(self, ", ");
-            }
-            first = false;
-            w!(self, "{}", lt.name);
-        }
-        for (idx, ty) in params.types.iter() {
-            if !first {
-                w!(self, ", ");
-            }
-            first = false;
-            match &ty.name {
-                Some(name) => w!(self, "{}", name),
-                None => w!(self, "_anon_{}", idx.into_raw()),
-            }
-        }
-        for (_, konst) in params.consts.iter() {
-            if !first {
-                w!(self, ", ");
-            }
-            first = false;
-            w!(self, "const {}: ", konst.name);
-            self.print_type_ref(&konst.ty);
-        }
-        w!(self, ">");
-    }
-
-    fn print_where_clause_and_opening_brace(&mut self, params: &GenericParams) {
-        if self.print_where_clause(params) {
-            w!(self, "\n{{");
+        if path.type_anchor().is_none()
+            && path.segments().iter().all(|seg| seg.args_and_bindings.is_none())
+        {
+            w!(self, "{}", path.mod_path());
         } else {
-            self.whitespace();
-            w!(self, "{{");
+            // too complicated, just use `Debug`
+            w!(self, "{:?}", path);
         }
     }
-
-    fn print_where_clause(&mut self, params: &GenericParams) -> bool {
-        if params.where_predicates.is_empty() {
-            return false;
-        }
-
-        w!(self, "\nwhere");
-        self.indented(|this| {
-            for (i, pred) in params.where_predicates.iter().enumerate() {
-                if i != 0 {
-                    wln!(this, ",");
-                }
-
-                let (target, bound) = match pred {
-                    WherePredicate::TypeBound { target, bound } => (target, bound),
-                    WherePredicate::Lifetime { target, bound } => {
-                        wln!(this, "{}: {},", target.name, bound.name);
-                        continue;
-                    }
-                    WherePredicate::ForLifetime { lifetimes, target, bound } => {
-                        w!(this, "for<");
-                        for (i, lt) in lifetimes.iter().enumerate() {
-                            if i != 0 {
-                                w!(this, ", ");
-                            }
-                            w!(this, "{}", lt);
-                        }
-                        w!(this, "> ");
-                        (target, bound)
-                    }
-                };
-
-                match target {
-                    WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
-                    WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
-                        Some(name) => w!(this, "{}", name),
-                        None => w!(this, "_anon_{}", id.into_raw()),
-                    },
-                }
-                w!(this, ": ");
-                this.print_type_bounds(std::slice::from_ref(bound));
-            }
-        });
-        true
-    }
 }
 
 impl<'a> Write for Printer<'a> {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 72093d75a2..ef021978ad 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -43,7 +43,6 @@ use hir_def::{
     type_ref::{ConstScalar, Rawness},
     TypeParamId,
 };
-use stdx::always;
 
 use crate::{db::HirDatabase, utils::generics};
 
@@ -329,14 +328,17 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
     t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
 }
 
-pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result>
+/// 'Canonicalizes' the `t` by replacing any errors with new variables. Also
+/// ensures there are no unbound variables or inference variables anywhere in
+/// the `t`.
+pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T::Result>
 where
-    T: HasInterner<Interner = Interner> + Fold<Interner>,
+    T: HasInterner<Interner = Interner> + Fold<Interner> + Clone,
     T::Result: HasInterner<Interner = Interner>,
 {
     use chalk_ir::{
         fold::{Folder, SuperFold},
-        Fallible,
+        Fallible, NoSolution,
     };
     struct ErrorReplacer {
         vars: usize,
@@ -363,18 +365,88 @@ where
 
         fn fold_inference_ty(
             &mut self,
-            var: InferenceVar,
-            kind: TyVariableKind,
+            _var: InferenceVar,
+            _kind: TyVariableKind,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Ty> {
+            if cfg!(debug_assertions) {
+                // we don't want to just panic here, because then the error message
+                // won't contain the whole thing, which would not be very helpful
+                Err(NoSolution)
+            } else {
+                Ok(TyKind::Error.intern(&Interner))
+            }
+        }
+
+        fn fold_free_var_ty(
+            &mut self,
+            _bound_var: BoundVar,
             _outer_binder: DebruijnIndex,
         ) -> Fallible<Ty> {
-            always!(false);
-            Ok(TyKind::InferenceVar(var, kind).intern(&Interner))
+            if cfg!(debug_assertions) {
+                // we don't want to just panic here, because then the error message
+                // won't contain the whole thing, which would not be very helpful
+                Err(NoSolution)
+            } else {
+                Ok(TyKind::Error.intern(&Interner))
+            }
+        }
+
+        fn fold_inference_const(
+            &mut self,
+            _ty: Ty,
+            _var: InferenceVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Const> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(dummy_usize_const())
+            }
+        }
+
+        fn fold_free_var_const(
+            &mut self,
+            _ty: Ty,
+            _bound_var: BoundVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Const> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(dummy_usize_const())
+            }
+        }
+
+        fn fold_inference_lifetime(
+            &mut self,
+            _var: InferenceVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Lifetime> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(static_lifetime())
+            }
+        }
+
+        fn fold_free_var_lifetime(
+            &mut self,
+            _bound_var: BoundVar,
+            _outer_binder: DebruijnIndex,
+        ) -> Fallible<Lifetime> {
+            if cfg!(debug_assertions) {
+                Err(NoSolution)
+            } else {
+                Ok(static_lifetime())
+            }
         }
     }
     let mut error_replacer = ErrorReplacer { vars: 0 };
-    let value = t
-        .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST)
-        .expect("fold failed unexpectedly");
+    let value = match t.clone().fold_with(&mut error_replacer, DebruijnIndex::INNERMOST) {
+        Ok(t) => t,
+        Err(_) => panic!("Encountered unbound or inference vars in {:?}", t),
+    };
     let kinds = (0..error_replacer.vars).map(|_| {
         chalk_ir::CanonicalVarKind::new(
             chalk_ir::VariableKind::Ty(TyVariableKind::General),
diff --git a/crates/ide_completion/src/completions/dot.rs b/crates/ide_completion/src/completions/dot.rs
index 7e4efe5898..fd97387437 100644
--- a/crates/ide_completion/src/completions/dot.rs
+++ b/crates/ide_completion/src/completions/dot.rs
@@ -454,4 +454,34 @@ mod foo {
             "#]],
         );
     }
+
+    #[test]
+    fn issue_8931() {
+        check(
+            r#"
+#[lang = "fn_once"]
+trait FnOnce<Args> {
+    type Output;
+}
+struct S;
+
+struct Foo;
+impl Foo {
+    fn foo(&self) -> &[u8] { loop {} }
+}
+
+impl S {
+    fn indented(&mut self, f: impl FnOnce(&mut Self)) {
+    }
+
+    fn f(&mut self, v: Foo) {
+        self.indented(|this| v.$0)
+    }
+}
+        "#,
+            expect![[r#"
+                me foo() fn(&self) -> &[u8]
+            "#]],
+        );
+    }
 }
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index ad367511b4..1d8a1930a9 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -293,8 +293,6 @@ EOF
 
 See https://sharksforarms.dev/posts/neovim-rust/ for more tips on getting started.
 
-Check out https://github.com/simrat39/rust-tools.nvim for a batteries included rust-analyzer setup for neovim.
-
 ==== vim-lsp
 
 vim-lsp is installed by following https://github.com/prabirshrestha/vim-lsp[the plugin instructions].


Test patch:
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 6407871b50..100ae9b97a 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -183,11 +183,7 @@ trait Tr: SuperTrait + 'lifetime {
                 _: (),
             ) -> ();
 
-            pub(self) trait Tr<Self>: SuperTrait + 'lifetime
-            where
-                Self: SuperTrait,
-                Self: 'lifetime
-            {
+            pub(self) trait Tr: SuperTrait + 'lifetime {
                 pub(self) type Assoc: AssocBound = Default;
 
                 // flags = 0x1
@@ -211,8 +207,6 @@ mod inline {
 
     fn fn_in_module() {}
 }
-
-mod outline;
         "#,
         expect![[r##"
             #[doc = " outer"]  // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -223,8 +217,6 @@ mod outline;
                 // flags = 0x2
                 pub(self) fn fn_in_module() -> ();
             }
-
-            pub(self) mod outline;
         "##]],
     );
 }
@@ -250,115 +242,3 @@ m!();
         "#]],
     );
 }
-
-#[test]
-fn mod_paths() {
-    check(
-        r#"
-struct S {
-    a: self::Ty,
-    b: super::SuperTy,
-    c: super::super::SuperSuperTy,
-    d: ::abs::Path,
-    e: crate::Crate,
-    f: plain::path::Ty,
-}
-        "#,
-        expect![[r#"
-            pub(self) struct S {
-                pub(self) a: self::Ty,
-                pub(self) b: super::SuperTy,
-                pub(self) c: super::super::SuperSuperTy,
-                pub(self) d: ::abs::Path,
-                pub(self) e: crate::Crate,
-                pub(self) f: plain::path::Ty,
-            }
-        "#]],
-    )
-}
-
-#[test]
-fn types() {
-    check(
-        r#"
-struct S {
-    a: Mixed<'a, T, Item=(), OtherItem=u8>,
-    b: <Fully as Qualified>::Syntax,
-    c: <TypeAnchored>::Path::<'a>,
-}
-        "#,
-        expect![[r#"
-            pub(self) struct S {
-                pub(self) a: Mixed<'a, T, Item = (), OtherItem = u8>,
-                pub(self) b: Qualified<Self=Fully>::Syntax,
-                pub(self) c: <TypeAnchored>::Path<'a>,
-            }
-        "#]],
-    )
-}
-
-#[test]
-fn generics() {
-    check(
-        r#"
-struct S<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> {
-    field: &'a &'b T,
-}
-
-struct Tuple<T: Copy>(T);
-
-impl<'a, 'b: 'a, T: Copy + 'a + 'b, const K: u8 = 0> S<'a, 'b, T, K> {
-    fn f<G: 'a>(arg: impl Copy) -> impl Copy {}
-}
-
-enum Enum<'a, T, const U: u8> {}
-union Union<'a, T, const U: u8> {}
-
-trait Tr<'a, T: 'a>: Super {}
-        "#,
-        expect![[r#"
-            pub(self) struct S<'a, 'b, T, const K: u8>
-            where
-                T: Copy,
-                T: 'a,
-                T: 'b
-            {
-                pub(self) field: &'a &'b T,
-            }
-
-            pub(self) struct Tuple<T>(
-                pub(self) 0: T,
-            )
-            where
-                T: Copy;
-
-            impl<'a, 'b, T, const K: u8> S<'a, 'b, T, K>
-            where
-                T: Copy,
-                T: 'a,
-                T: 'b
-            {
-                // flags = 0x2
-                pub(self) fn f<G, _anon_1>(
-                    _: impl Copy,
-                ) -> impl Copy
-                where
-                    G: 'a,
-                    _anon_1: Copy;
-            }
-
-            pub(self) enum Enum<'a, T, const U: u8> {
-            }
-
-            pub(self) union Union<'a, T, const U: u8> {
-            }
-
-            pub(self) trait Tr<'a, Self, T>: Super
-            where
-                Self: Super,
-                T: 'a
-            {
-            }
-        "#]],
-    )
-}