Repository: rust-lang/rust-analyzer
Pull request #13329 (2022-10-01 20:52:43)

minor: Use `$crate` instead of std for panic `builtin_fn_macro`
This should be closer to the expected output and gets rid of a few type mismatches in rustc/library

Veykril: @bors r+
bors: :pushpin: Commit 83d48bccf41e34b97df971b38a21ca440b6a7291 has been approved by `Veykril`

It is now in the [queue](https://bors.rust-lang.org/homu/queue/rust-analyzer) for this repository.

<!-- @bors r=Veykril 83d48bccf41e34b97df971b38a21ca440b6a7291 -->
<!-- homu: {"type":"Approved","sha":"83d48bccf41e34b97df971b38a21ca440b6a7291","approver":"Veykril","queue":"https://bors.rust-lang.org/homu/queue/rust-analyzer"} -->
bors: :hourglass: Testing commit 83d48bccf41e34b97df971b38a21ca440b6a7291 with merge 6544968ab07a01620a5cd030add6be5d4da28f7d...
<!-- homu: {"type":"BuildStarted","head_sha":"83d48bccf41e34b97df971b38a21ca440b6a7291","merge_sha":"6544968ab07a01620a5cd030add6be5d4da28f7d"} -->
bors: :broken_heart: Test failed - [checks-actions](https://github.com/rust-lang/rust-analyzer/actions/runs/3166121744/jobs/5155663332)
<!-- homu: {"type":"BuildFailed","builder_url":"https://github.com/rust-lang/rust-analyzer/actions/runs/3166121744/jobs/5155663332","builder_name":"checks-actions"} -->

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index e45cde6838..93b7f746e0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2082,18 +2082,18 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
 
 [[package]]
 name = "xflags"
-version = "0.3.0"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbf19f5031a1a812e96fede16f8161218883079946cea87619d3613db1efd268"
+checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
 dependencies = [
  "xflags-macros",
 ]
 
 [[package]]
 name = "xflags-macros"
-version = "0.3.0"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2afbd7f2039bb6cad2dd45f0c5dff49c0d4e26118398768b7a605524d4251809"
+checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
 
 [[package]]
 name = "xshell"
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index e8c63d410a..fdc03f4053 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -169,17 +169,13 @@ impl FlycheckActor {
     }
     fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
         let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
-        if let Ok(msg) = inbox.try_recv() {
-            // give restarts a preference so check outputs don't block a restart or stop
-            return Some(Event::Restart(msg));
-        }
         select! {
             recv(inbox) -> msg => msg.ok().map(Event::Restart),
             recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
         }
     }
     fn run(mut self, inbox: Receiver<Restart>) {
-        'event: while let Some(event) = self.next_event(&inbox) {
+        while let Some(event) = self.next_event(&inbox) {
             match event {
                 Event::Restart(Restart::No) => {
                     self.cancel_check_process();
@@ -187,12 +183,7 @@ impl FlycheckActor {
                 Event::Restart(Restart::Yes) => {
                     // Cancel the previously spawned process
                     self.cancel_check_process();
-                    while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
-                        // restart chained with a stop, so just cancel
-                        if let Restart::No = restart {
-                            continue 'event;
-                        }
-                    }
+                    while let Ok(_) = inbox.recv_timeout(Duration::from_millis(50)) {}
 
                     let command = self.check_command();
                     tracing::debug!(?command, "will restart flycheck");
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 8befa7f7da..7b19518e25 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -238,9 +238,9 @@ fn format_args_expand(
 ) -> ExpandResult<tt::Subtree> {
     // We expand `format_args!("", a1, a2)` to
     // ```
-    // std::fmt::Arguments::new_v1(&[], &[
-    //   std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
-    //   std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
+    // $crate::fmt::Arguments::new_v1(&[], &[
+    //   $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt),
+    //   $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt),
     // ])
     // ```,
     // which is still not really correct, but close enough for now
@@ -262,10 +262,10 @@ fn format_args_expand(
     }
     let _format_string = args.remove(0);
     let arg_tts = args.into_iter().flat_map(|arg| {
-        quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
+        quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), }
     }.token_trees);
     let expanded = quote! {
-        std::fmt::Arguments::new_v1(&[], &[##arg_tts])
+        #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts])
     };
     ExpandResult::ok(expanded)
 }
@@ -675,8 +675,8 @@ fn option_env_expand(
     };
 
     let expanded = match get_env_inner(db, arg_id, &key) {
-        None => quote! { std::option::Option::None::<&str> },
-        Some(s) => quote! { std::option::Some(#s) },
+        None => quote! { #DOLLAR_CRATE::option::Option::None::<&str> },
+        Some(s) => quote! { #DOLLAR_CRATE::option::Some(#s) },
     };
 
     ExpandResult::ok(ExpandedEager::new(expanded))
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 02332ea80d..344036dd81 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -123,14 +123,13 @@ fn deref_by_trait(table: &mut InferenceTable<'_>, ty: Ty) -> Option<Ty> {
     let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
 
     let projection = {
-        let b = TyBuilder::subst_for_def(db, deref_trait, None);
+        let b = TyBuilder::assoc_type_projection(db, target);
         if b.remaining() != 1 {
             // the Target type + Deref trait should only have one generic parameter,
             // namely Deref's Self type
             return None;
         }
-        let deref_subst = b.push(ty).build();
-        TyBuilder::assoc_type_projection(db, target, Some(deref_subst)).build()
+        b.push(ty).build()
     };
 
     // Check that the type implements Deref at all
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index 9ae752556d..3ae7fb2a61 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -6,7 +6,7 @@ use chalk_ir::{
     cast::{Cast, CastTo, Caster},
     fold::TypeFoldable,
     interner::HasInterner,
-    AdtId, DebruijnIndex, Scalar,
+    AdtId, BoundVar, DebruijnIndex, Scalar,
 };
 use hir_def::{
     builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
@@ -16,9 +16,9 @@ use smallvec::SmallVec;
 
 use crate::{
     consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
-    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, BoundVar, CallableSig,
-    GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
-    ValueTyDefId,
+    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
+    ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
+    TyDefId, TyExt, TyKind, ValueTyDefId,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -34,32 +34,17 @@ pub struct TyBuilder<D> {
     data: D,
     vec: SmallVec<[GenericArg; 2]>,
     param_kinds: SmallVec<[ParamKind; 2]>,
-    parent_subst: Substitution,
 }
 
 impl<A> TyBuilder<A> {
     fn with_data<B>(self, data: B) -> TyBuilder<B> {
-        TyBuilder {
-            data,
-            vec: self.vec,
-            param_kinds: self.param_kinds,
-            parent_subst: self.parent_subst,
-        }
+        TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
     }
 }
 
 impl<D> TyBuilder<D> {
-    fn new(
-        data: D,
-        param_kinds: SmallVec<[ParamKind; 2]>,
-        parent_subst: Option<Substitution>,
-    ) -> Self {
-        let parent_subst = parent_subst.unwrap_or_else(|| Substitution::empty(Interner));
-        Self { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds, parent_subst }
-    }
-
-    fn new_empty(data: D) -> Self {
-        TyBuilder::new(data, SmallVec::new(), None)
+    fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
+        TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
     }
 
     fn build_internal(self) -> (D, Substitution) {
@@ -67,18 +52,13 @@ impl<D> TyBuilder<D> {
         for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
             self.assert_match_kind(a, e);
         }
-        let subst = Substitution::from_iter(
-            Interner,
-            self.vec.into_iter().chain(self.parent_subst.iter(Interner).cloned()),
-        );
+        let subst = Substitution::from_iter(Interner, self.vec);
         (self.data, subst)
     }
 
     pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
-        assert!(self.remaining() > 0);
         let arg = arg.cast(Interner);
         let expected_kind = &self.param_kinds[self.vec.len()];
-
         let arg_kind = match arg.data(Interner) {
             chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
             chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
@@ -88,9 +68,7 @@ impl<D> TyBuilder<D> {
             }
         };
         assert_eq!(*expected_kind, arg_kind);
-
         self.vec.push(arg);
-
         self
     }
 
@@ -101,12 +79,20 @@ impl<D> TyBuilder<D> {
     pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
         // self.fill is inlined to make borrow checker happy
         let mut this = self;
-        let other = &this.param_kinds[this.vec.len()..];
+        let other = this.param_kinds.iter().skip(this.vec.len());
         let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
-            ParamKind::Type => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
-            ParamKind::Const(ty) => {
-                BoundVar::new(debruijn, idx).to_const(Interner, ty.clone()).cast(Interner)
+            ParamKind::Type => {
+                GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
+                    .intern(Interner)
             }
+            ParamKind::Const(ty) => GenericArgData::Const(
+                ConstData {
+                    value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
+                    ty: ty.clone(),
+                }
+                .intern(Interner),
+            )
+            .intern(Interner),
         });
         this.vec.extend(filler.take(this.remaining()).casted(Interner));
         assert_eq!(this.remaining(), 0);
@@ -116,8 +102,8 @@ impl<D> TyBuilder<D> {
     pub fn fill_with_unknown(self) -> Self {
         // self.fill is inlined to make borrow checker happy
         let mut this = self;
-        let filler = this.param_kinds[this.vec.len()..].iter().map(|x| match x {
-            ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
+        let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
+            ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
             ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
         });
         this.vec.extend(filler.casted(Interner));
@@ -127,17 +113,33 @@ impl<D> TyBuilder<D> {
 
     pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
         self.fill(|x| match x {
-            ParamKind::Type => table.new_type_var().cast(Interner),
-            ParamKind::Const(ty) => table.new_const_var(ty.clone()).cast(Interner),
+            ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
+            ParamKind::Const(ty) => {
+                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
+            }
         })
     }
 
     pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
-        self.vec.extend(self.param_kinds[self.vec.len()..].iter().map(filler));
+        self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
         assert_eq!(self.remaining(), 0);
         self
     }
 
+    pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
+        assert!(self.vec.is_empty());
+        assert!(parent_substs.len(Interner) <= self.param_kinds.len());
+        self.extend(parent_substs.iter(Interner).cloned());
+        self
+    }
+
+    fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
+        for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
+            self.assert_match_kind(&x.0, &x.1);
+        }
+        self.vec.extend(it);
+    }
+
     fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
         match (a.data(Interner), e) {
             (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
@@ -186,42 +188,53 @@ impl TyBuilder<()> {
         params.placeholder_subst(db)
     }
 
-    pub fn subst_for_def(
-        db: &dyn HirDatabase,
-        def: impl Into<GenericDefId>,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<()> {
-        let generics = generics(db.upcast(), def.into());
-        assert!(generics.parent_generics().is_some() == parent_subst.is_some());
-        let params = generics
-            .iter_self()
-            .map(|(id, data)| match data {
-                TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
-                TypeOrConstParamData::ConstParamData(_) => {
-                    ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
-                }
-            })
-            .collect();
-        TyBuilder::new((), params, parent_subst)
+    pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
+        let def = def.into();
+        let params = generics(db.upcast(), def);
+        TyBuilder::new(
+            (),
+            params
+                .iter()
+                .map(|(id, data)| match data {
+                    TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
+                    TypeOrConstParamData::ConstParamData(_) => {
+                        ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
+                    }
+                })
+                .collect(),
+        )
     }
 
     /// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
     ///
     /// A generator's substitution consists of:
+    /// - generic parameters in scope on `parent`
     /// - resume type of generator
     /// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
     /// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
-    /// - generic parameters in scope on `parent`
     /// in this order.
     ///
     /// This method prepopulates the builder with placeholder substitution of `parent`, so you
     /// should only push exactly 3 `GenericArg`s before building.
     pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
-        let parent_subst =
-            parent.as_generic_def_id().map(|p| generics(db.upcast(), p).placeholder_subst(db));
-        // These represent resume type, yield type, and return type of generator.
-        let params = std::iter::repeat(ParamKind::Type).take(3).collect();
-        TyBuilder::new((), params, parent_subst)
+        let parent_subst = match parent.as_generic_def_id() {
+            Some(parent) => generics(db.upcast(), parent).placeholder_subst(db),
+            // Static initializers *may* contain generators.
+            None => Substitution::empty(Interner),
+        };
+        let builder = TyBuilder::new(
+            (),
+            parent_subst
+                .iter(Interner)
+                .map(|arg| match arg.constant(Interner) {
+                    Some(c) => ParamKind::Const(c.data(Interner).ty.clone()),
+                    None => ParamKind::Type,
+                })
+                // These represent resume type, yield type, and return type of generator.
+                .chain(std::iter::repeat(ParamKind::Type).take(3))
+                .collect(),
+        );
+        builder.use_parent_substs(&parent_subst)
     }
 
     pub fn build(self) -> Substitution {
@@ -232,7 +245,7 @@ impl TyBuilder<()> {
 
 impl TyBuilder<hir_def::AdtId> {
     pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
-        TyBuilder::subst_for_def(db, def, None).with_data(def)
+        TyBuilder::subst_for_def(db, def).with_data(def)
     }
 
     pub fn fill_with_defaults(
@@ -240,27 +253,16 @@ impl TyBuilder<hir_def::AdtId> {
         db: &dyn HirDatabase,
         mut fallback: impl FnMut() -> Ty,
     ) -> Self {
-        // Note that we're building ADT, so we never have parent generic parameters.
         let defaults = db.generic_defaults(self.data.into());
-        let dummy_ty = TyKind::Error.intern(Interner).cast(Interner);
         for default_ty in defaults.iter().skip(self.vec.len()) {
-            // NOTE(skip_binders): we only check if the arg type is error type.
-            if let Some(x) = default_ty.skip_binders().ty(Interner) {
+            if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
                 if x.is_unknown() {
                     self.vec.push(fallback().cast(Interner));
                     continue;
                 }
-            }
-            // Each default can only depend on the previous parameters.
-            // FIXME: we don't handle const generics here.
-            let subst_so_far = Substitution::from_iter(
-                Interner,
-                self.vec
-                    .iter()
-                    .cloned()
-                    .chain(iter::repeat(dummy_ty.clone()))
-                    .take(self.param_kinds.len()),
-            );
+            };
+            // each default can depend on the previous parameters
+            let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
             self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
         }
         self
@@ -275,7 +277,7 @@ impl TyBuilder<hir_def::AdtId> {
 pub struct Tuple(usize);
 impl TyBuilder<Tuple> {
     pub fn tuple(size: usize) -> TyBuilder<Tuple> {
-        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect(), None)
+        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
     }
 
     pub fn build(self) -> Ty {
@@ -286,7 +288,7 @@ impl TyBuilder<Tuple> {
 
 impl TyBuilder<TraitId> {
     pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
-        TyBuilder::subst_for_def(db, def, None).with_data(def)
+        TyBuilder::subst_for_def(db, def).with_data(def)
     }
 
     pub fn build(self) -> TraitRef {
@@ -296,12 +298,8 @@ impl TyBuilder<TraitId> {
 }
 
 impl TyBuilder<TypeAliasId> {
-    pub fn assoc_type_projection(
-        db: &dyn HirDatabase,
-        def: TypeAliasId,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<TypeAliasId> {
-        TyBuilder::subst_for_def(db, def, parent_subst).with_data(def)
+    pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
+        TyBuilder::subst_for_def(db, def).with_data(def)
     }
 
     pub fn build(self) -> ProjectionTy {
@@ -311,6 +309,19 @@ impl TyBuilder<TypeAliasId> {
 }
 
 impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Binders<T>> {
+    fn subst_binders(b: Binders<T>) -> Self {
+        let param_kinds = b
+            .binders
+            .iter(Interner)
+            .map(|x| match x {
+                chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
+                chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
+                chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
+            })
+            .collect();
+        TyBuilder::new(b, param_kinds)
+    }
+
     pub fn build(self) -> T {
         let (b, subst) = self.build_internal();
         b.substitute(Interner, &subst)
@@ -318,41 +329,15 @@ impl<T: HasInterner<Interner = Interner> + TypeFoldable<Interner>> TyBuilder<Bin
 }
 
 impl TyBuilder<Binders<Ty>> {
-    pub fn def_ty(
-        db: &dyn HirDatabase,
-        def: TyDefId,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<Binders<Ty>> {
-        let poly_ty = db.ty(def);
-        let id: GenericDefId = match def {
-            TyDefId::BuiltinType(_) => {
-                assert!(parent_subst.is_none());
-                return TyBuilder::new_empty(poly_ty);
-            }
-            TyDefId::AdtId(id) => id.into(),
-            TyDefId::TypeAliasId(id) => id.into(),
-        };
-        TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_ty)
+    pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
+        TyBuilder::subst_binders(db.ty(def))
     }
 
     pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
-        TyBuilder::subst_for_def(db, def, None).with_data(db.impl_self_ty(def))
+        TyBuilder::subst_binders(db.impl_self_ty(def))
     }
 
-    pub fn value_ty(
-        db: &dyn HirDatabase,
-        def: ValueTyDefId,
-        parent_subst: Option<Substitution>,
-    ) -> TyBuilder<Binders<Ty>> {
-        let poly_value_ty = db.value_ty(def);
-        let id = match def.to_generic_def_id() {
-            Some(id) => id,
-            None => {
-                // static items
-                assert!(parent_subst.is_none());
-                return TyBuilder::new_empty(poly_value_ty);
-            }
-        };
-        TyBuilder::subst_for_def(db, id, parent_subst).with_data(poly_value_ty)
+    pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
+        TyBuilder::subst_binders(db.value_ty(def))
     }
 }
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 3f3f8f7d0f..c5cf6729d1 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -382,12 +382,13 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         // `resume_type`, `yield_type`, and `return_type` of the generator in question.
         let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
 
+        let len = subst.len(Interner);
         let input_output = rust_ir::GeneratorInputOutputDatum {
-            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
+            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3))
                 .intern(Interner),
-            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 1))
+            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2))
                 .intern(Interner),
-            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 2))
+            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1))
                 .intern(Interner),
             // FIXME: calculate upvars
             upvars: vec![],
@@ -475,15 +476,10 @@ pub(crate) fn associated_ty_data_query(
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver)
         .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
-
-    let trait_subst = TyBuilder::subst_for_def(db, trait_, None)
-        .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self())
-        .build();
-    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst))
+    let pro_ty = TyBuilder::assoc_type_projection(db, type_alias)
         .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0)
         .build();
     let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner);
-
     let mut bounds: Vec<_> = type_alias_data
         .bounds
         .iter()
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index 4f0e9dbf1e..ed97bd2da4 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -152,7 +152,7 @@ impl TyExt for Ty {
             TyKind::FnDef(def, parameters) => {
                 let callable_def = db.lookup_intern_callable_def((*def).into());
                 let sig = db.callable_item_signature(callable_def);
-                Some(sig.substitute(Interner, parameters))
+                Some(sig.substitute(Interner, &parameters))
             }
             TyKind::Closure(.., substs) => {
                 let sig_param = substs.at(Interner, 0).assert_ty_ref(Interner);
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 7f0baf49da..a5058f71a4 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -27,7 +27,7 @@ use crate::{
     db::HirDatabase,
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
     mapping::from_chalk,
-    primitive, to_assoc_type_id,
+    primitive, subst_prefix, to_assoc_type_id,
     utils::{self, generics},
     AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
     GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
@@ -506,15 +506,8 @@ impl HirDisplay for Ty {
                     let total_len = parent_params + self_param + type_params + const_params;
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if total_len > 0 {
-                        // `parameters` are in the order of fn's params (including impl traits),
-                        // parent's params (those from enclosing impl or trait, if any).
-                        let parameters = parameters.as_slice(Interner);
-                        let fn_params_len = self_param + type_params + const_params;
-                        let fn_params = parameters.get(..fn_params_len);
-                        let parent_params = parameters.get(parameters.len() - parent_params..);
-                        let params = parent_params.into_iter().chain(fn_params).flatten();
                         write!(f, "<")?;
-                        f.write_joined(params, ", ")?;
+                        f.write_joined(&parameters.as_slice(Interner)[..total_len], ", ")?;
                         write!(f, ">")?;
                     }
                 }
@@ -586,8 +579,9 @@ impl HirDisplay for Ty {
                                         Some(x) => x,
                                         None => return true,
                                     };
-                                    let actual_default =
-                                        default_parameter.clone().substitute(Interner, &parameters);
+                                    let actual_default = default_parameter
+                                        .clone()
+                                        .substitute(Interner, &subst_prefix(parameters, i));
                                     parameter != &actual_default
                                 }
                                 let mut default_from = 0;
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 31e56dec62..25179afaca 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -26,8 +26,8 @@ use hir_def::{
     path::{path, Path},
     resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs},
     type_ref::TypeRef,
-    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule,
-    ItemContainerId, Lookup, TraitId, TypeAliasId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
+    TraitId, TypeAliasId, VariantId,
 };
 use hir_expand::name::{name, Name};
 use itertools::Either;
@@ -713,8 +713,6 @@ impl<'a> InferenceContext<'a> {
         &mut self,
         inner_ty: Ty,
         assoc_ty: Option<TypeAliasId>,
-        // FIXME(GATs): these are args for the trait ref, args for assoc type itself should be
-        // handled when we support them.
         params: &[GenericArg],
     ) -> Ty {
         match assoc_ty {
@@ -806,18 +804,7 @@ impl<'a> InferenceContext<'a> {
                 self.resolve_variant_on_alias(ty, unresolved, path)
             }
             TypeNs::TypeAliasId(it) => {
-                let container = it.lookup(self.db.upcast()).container;
-                let parent_subst = match container {
-                    ItemContainerId::TraitId(id) => {
-                        let subst = TyBuilder::subst_for_def(self.db, id, None)
-                            .fill_with_inference_vars(&mut self.table)
-                            .build();
-                        Some(subst)
-                    }
-                    // Type aliases do not exist in impls.
-                    _ => None,
-                };
-                let ty = TyBuilder::def_ty(self.db, it.into(), parent_subst)
+                let ty = TyBuilder::def_ty(self.db, it.into())
                     .fill_with_inference_vars(&mut self.table)
                     .build();
                 self.resolve_variant_on_alias(ty, unresolved, path)
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index f56108b26c..2643baf8a3 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -987,13 +987,11 @@ impl<'a> InferenceContext<'a> {
         let lhs_ty = self.infer_expr(lhs, &lhs_expectation);
         let rhs_ty = self.table.new_type_var();
 
-        let trait_func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
-            let trait_id = self.resolve_lang_item(lang_item)?.as_trait()?;
-            let func = self.db.trait_data(trait_id).method_by_name(&name)?;
-            Some((trait_id, func))
+        let func = lang_names_for_bin_op(op).and_then(|(name, lang_item)| {
+            self.db.trait_data(self.resolve_lang_item(lang_item)?.as_trait()?).method_by_name(&name)
         });
-        let (trait_, func) = match trait_func {
-            Some(it) => it,
+        let func = match func {
+            Some(func) => func,
             None => {
                 let rhs_ty = self.builtin_binary_op_rhs_expectation(op, lhs_ty.clone());
                 let rhs_ty = self.infer_expr_coerce(rhs, &Expectation::from_option(rhs_ty));
@@ -1003,9 +1001,7 @@ impl<'a> InferenceContext<'a> {
             }
         };
 
-        // HACK: We can use this substitution for the function because the function itself doesn't
-        // have its own generic parameters.
-        let subst = TyBuilder::subst_for_def(self.db, trait_, None)
+        let subst = TyBuilder::subst_for_def(self.db, func)
             .push(lhs_ty.clone())
             .push(rhs_ty.clone())
             .build();
@@ -1284,7 +1280,19 @@ impl<'a> InferenceContext<'a> {
         assert_eq!(self_params, 0); // method shouldn't have another Self param
         let total_len = parent_params + type_params + const_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
-
+        // Parent arguments are unknown
+        for (id, param) in def_generics.iter_parent() {
+            match param {
+                TypeOrConstParamData::TypeParamData(_) => {
+                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
+                }
+                TypeOrConstParamData::ConstParamData(_) => {
+                    let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
+                    substs
+                        .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
+                }
+            }
+        }
         // handle provided arguments
         if let Some(generic_args) = generic_args {
             // if args are provided, it should be all of them, but we can't rely on that
@@ -1293,7 +1301,7 @@ impl<'a> InferenceContext<'a> {
                 .iter()
                 .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
                 .take(type_params + const_params)
-                .zip(def_generics.iter_id())
+                .zip(def_generics.iter_id().skip(parent_params))
             {
                 if let Some(g) = generic_arg_to_chalk(
                     self.db,
@@ -1317,9 +1325,6 @@ impl<'a> InferenceContext<'a> {
                 }
             }
         };
-
-        // Handle everything else as unknown. This also handles generic arguments for the method's
-        // parent (impl or trait), which should come after those for the method.
         for (id, data) in def_generics.iter().skip(substs.len()) {
             match data {
                 TypeOrConstParamData::TypeParamData(_) => {
@@ -1357,13 +1362,9 @@ impl<'a> InferenceContext<'a> {
                 CallableDefId::FunctionId(f) => {
                     if let ItemContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container {
                         // construct a TraitRef
-                        let params_len = parameters.len(Interner);
-                        let trait_params_len = generics(self.db.upcast(), trait_.into()).len();
-                        let substs = Substitution::from_iter(
-                            Interner,
-                            // The generic parameters for the trait come after those for the
-                            // function.
-                            &parameters.as_slice(Interner)[params_len - trait_params_len..],
+                        let substs = crate::subst_prefix(
+                            &*parameters,
+                            generics(self.db.upcast(), trait_.into()).len(),
                         );
                         self.push_obligation(
                             TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 7a4754cdc7..f580e09e91 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -12,8 +12,8 @@ use crate::{
     builder::ParamKind,
     consteval,
     method_resolution::{self, VisibleFromModule},
-    utils::generics,
-    Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
+    GenericArgData, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+    ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -96,21 +96,17 @@ impl<'a> InferenceContext<'a> {
             ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
         };
 
+        let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
         let substs = ctx.substs_from_path(path, typable, true);
-        let substs = substs.as_slice(Interner);
-        let parent_substs = self_subst.or_else(|| {
-            let generics = generics(self.db.upcast(), typable.to_generic_def_id()?);
-            let parent_params_len = generics.parent_generics()?.len();
-            let parent_args = &substs[substs.len() - parent_params_len..];
-            Some(Substitution::from_iter(Interner, parent_args))
-        });
-        let parent_substs_len = parent_substs.as_ref().map_or(0, |s| s.len(Interner));
-        let mut it = substs.iter().take(substs.len() - parent_substs_len).cloned();
-        let ty = TyBuilder::value_ty(self.db, typable, parent_substs)
+        let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
+        let ty = TyBuilder::value_ty(self.db, typable)
+            .use_parent_substs(&parent_substs)
             .fill(|x| {
                 it.next().unwrap_or_else(|| match x {
-                    ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
+                    ParamKind::Type => {
+                        GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
+                    }
                     ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
                 })
             })
@@ -253,7 +249,7 @@ impl<'a> InferenceContext<'a> {
                 };
                 let substs = match container {
                     ItemContainerId::ImplId(impl_id) => {
-                        let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
+                        let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
                             .fill_with_inference_vars(&mut self.table)
                             .build();
                         let impl_self_ty =
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 6ccd0b215c..e77b55670b 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -598,14 +598,11 @@ impl<'a> InferenceTable<'a> {
             .build();
 
         let projection = {
-            let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
+            let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
             if b.remaining() != 2 {
                 return None;
             }
-            let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
-
-            TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
-                .build()
+            b.push(ty.clone()).push(arg_ty).build()
         };
 
         let trait_env = self.trait_env.env.clone();
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 223d705b15..e28c87dfa4 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -306,7 +306,7 @@ impl<'a> TyLoweringContext<'a> {
                         // FIXME we're probably doing something wrong here
                         self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
-                            _parent_params,
+                            parent_params,
                             self_params,
                             list_params,
                             const_params,
@@ -319,7 +319,7 @@ impl<'a> TyLoweringContext<'a> {
                         };
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + self_params + list_params + const_params,
+                            idx as usize + parent_params + self_params + list_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -499,31 +499,14 @@ impl<'a> TyLoweringContext<'a> {
                 .intern(Interner)
             }
             TypeNs::SelfType(impl_id) => {
-                let def =
-                    self.resolver.generic_def().expect("impl should have generic param scope");
-                let generics = generics(self.db.upcast(), def);
-
-                match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        // `def` can be either impl itself or item within, and we need impl itself
-                        // now.
-                        let generics = generics.parent_generics().unwrap_or(&generics);
-                        let subst = generics.placeholder_subst(self.db);
-                        self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
-                    }
+                let generics = generics(self.db.upcast(), impl_id.into());
+                let substs = match self.type_param_mode {
+                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
                     ParamLoweringMode::Variable => {
-                        let starting_from = match def {
-                            GenericDefId::ImplId(_) => 0,
-                            // `def` is an item within impl. We need to substitute `BoundVar`s but
-                            // remember that they are for parent (i.e. impl) generic params so they
-                            // come after our own params.
-                            _ => generics.len_self(),
-                        };
-                        TyBuilder::impl_self_ty(self.db, impl_id)
-                            .fill_with_bound_vars(self.in_binders, starting_from)
-                            .build()
+                        generics.bound_vars_subst(self.db, self.in_binders)
                     }
-                }
+                };
+                self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
             }
             TypeNs::AdtSelfType(adt) => {
                 let generics = generics(self.db.upcast(), adt.into());
@@ -680,31 +663,40 @@ impl<'a> TyLoweringContext<'a> {
     fn substs_from_path_segment(
         &self,
         segment: PathSegment<'_>,
-        def: Option<GenericDefId>,
+        def_generic: Option<GenericDefId>,
         infer_args: bool,
         explicit_self_ty: Option<Ty>,
     ) -> Substitution {
-        // Remember that the item's own generic args come before its parent's.
         let mut substs = Vec::new();
-        let def = if let Some(d) = def {
-            d
+        let def_generics = if let Some(def) = def_generic {
+            generics(self.db.upcast(), def)
         } else {
             return Substitution::empty(Interner);
         };
-        let def_generics = generics(self.db.upcast(), def);
         let (parent_params, self_params, type_params, const_params, impl_trait_params) =
             def_generics.provenance_split();
-        let item_len = self_params + type_params + const_params + impl_trait_params;
-        let total_len = parent_params + item_len;
+        let total_len =
+            parent_params + self_params + type_params + const_params + impl_trait_params;
 
-        let ty_error = TyKind::Error.intern(Interner).cast(Interner);
+        let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
 
         let mut def_generic_iter = def_generics.iter_id();
 
+        for _ in 0..parent_params {
+            if let Some(eid) = def_generic_iter.next() {
+                match eid {
+                    Either::Left(_) => substs.push(ty_error.clone()),
+                    Either::Right(x) => {
+                        substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
+                    }
+                }
+            }
+        }
+
         let fill_self_params = || {
             for x in explicit_self_ty
                 .into_iter()
-                .map(|x| x.cast(Interner))
+                .map(|x| GenericArgData::Ty(x).intern(Interner))
                 .chain(iter::repeat(ty_error.clone()))
                 .take(self_params)
             {
@@ -765,40 +757,37 @@ impl<'a> TyLoweringContext<'a> {
             fill_self_params();
         }
 
-        // These params include those of parent.
-        let remaining_params: SmallVec<[_; 2]> = def_generic_iter
-            .map(|eid| match eid {
-                Either::Left(_) => ty_error.clone(),
-                Either::Right(x) => unknown_const_as_generic(self.db.const_param_ty(x)),
-            })
-            .collect();
-        assert_eq!(remaining_params.len() + substs.len(), total_len);
-
         // handle defaults. In expression or pattern path segments without
         // explicitly specified type arguments, missing type arguments are inferred
         // (i.e. defaults aren't used).
         if !infer_args || had_explicit_args {
-            let defaults = self.db.generic_defaults(def);
-            assert_eq!(total_len, defaults.len());
-            let parent_from = item_len - substs.len();
-
-            for (idx, default_ty) in defaults[substs.len()..item_len].iter().enumerate() {
-                // each default can depend on the previous parameters
-                let substs_so_far = Substitution::from_iter(
-                    Interner,
-                    substs.iter().cloned().chain(remaining_params[idx..].iter().cloned()),
-                );
-                substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
+            if let Some(def_generic) = def_generic {
+                let defaults = self.db.generic_defaults(def_generic);
+                assert_eq!(total_len, defaults.len());
+
+                for default_ty in defaults.iter().skip(substs.len()) {
+                    // each default can depend on the previous parameters
+                    let substs_so_far = Substitution::from_iter(Interner, substs.clone());
+                    if let Some(_id) = def_generic_iter.next() {
+                        substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
+                    }
+                }
             }
-
-            // Keep parent's params as unknown.
-            let mut remaining_params = remaining_params;
-            substs.extend(remaining_params.drain(parent_from..));
-        } else {
-            substs.extend(remaining_params);
         }
 
+        // add placeholders for args that were not provided
+        // FIXME: emit diagnostics in contexts where this is not allowed
+        for eid in def_generic_iter {
+            match eid {
+                Either::Left(_) => substs.push(ty_error.clone()),
+                Either::Right(x) => {
+                    substs.push(unknown_const_as_generic(self.db.const_param_ty(x)))
+                }
+            }
+        }
+        // If this assert fails, it means you pushed into subst but didn't call .next() of def_generic_iter
         assert_eq!(substs.len(), total_len);
+
         Substitution::from_iter(Interner, substs)
     }
 
@@ -1158,28 +1147,11 @@ fn named_associated_type_shorthand_candidates<R>(
     };
 
     match res {
-        TypeNs::SelfType(impl_id) => {
+        TypeNs::SelfType(impl_id) => search(
             // we're _in_ the impl -- the binders get added back later. Correct,
             // but it would be nice to make this more explicit
-            let trait_ref = db.impl_trait(impl_id)?.into_value_and_skipped_binders().0;
-
-            let impl_id_as_generic_def: GenericDefId = impl_id.into();
-            if impl_id_as_generic_def != def {
-                // `trait_ref` contains `BoundVar`s bound by impl's `Binders`, but here we need
-                // `BoundVar`s from `def`'s point of view.
-                // FIXME: A `HirDatabase` query may be handy if this process is needed in more
-                // places. It'd be almost identical as `impl_trait_query` where `resolver` would be
-                // of `def` instead of `impl_id`.
-                let starting_idx = generics(db.upcast(), def).len_self();
-                let subst = TyBuilder::subst_for_def(db, impl_id, None)
-                    .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
-                    .build();
-                let trait_ref = subst.apply(trait_ref, Interner);
-                search(trait_ref)
-            } else {
-                search(trait_ref)
-            }
-        }
+            db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
+        ),
         TypeNs::GenericParam(param_id) => {
             let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
             let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
@@ -1196,18 +1168,10 @@ fn named_associated_type_shorthand_candidates<R>(
             }
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
-                let trait_generics = generics(db.upcast(), trait_id.into());
-                if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
-                    let def_generics = generics(db.upcast(), def);
-                    let starting_idx = match def {
-                        GenericDefId::TraitId(_) => 0,
-                        // `def` is an item within trait. We need to substitute `BoundVar`s but
-                        // remember that they are for parent (i.e. trait) generic params so they
-                        // come after our own params.
-                        _ => def_generics.len_self(),
-                    };
+                let generics = generics(db.upcast(), trait_id.into());
+                if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
                     let trait_ref = TyBuilder::trait_ref(db, trait_id)
-                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, starting_idx)
+                        .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
                         .build();
                     return search(trait_ref);
                 }
@@ -1449,7 +1413,6 @@ pub(crate) fn generic_defaults_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     let generic_params = generics(db.upcast(), def);
-    let parent_start_idx = generic_params.len_self();
 
     let defaults = generic_params
         .iter()
@@ -1462,17 +1425,19 @@ pub(crate) fn generic_defaults_query(
                     let val = unknown_const_as_generic(
                         db.const_param_ty(ConstParamId::from_unchecked(id)),
                     );
-                    return make_binders(db, &generic_params, val);
+                    return crate::make_binders_with_count(db, idx, &generic_params, val);
                 }
             };
             let mut ty =
                 p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 
             // Each default can only refer to previous parameters.
-            // Type variable default referring to parameter coming
-            // after it is forbidden (FIXME: report diagnostic)
-            ty = fallback_bound_vars(ty, idx, parent_start_idx);
-            crate::make_binders(db, &generic_params, ty.cast(Interner))
+            // type variable default referring to parameter coming
+            // after it. This is forbidden (FIXME: report
+            // diagnostic)
+            ty = fallback_bound_vars(ty, idx);
+            let val = GenericArgData::Ty(ty).intern(Interner);
+            crate::make_binders_with_count(db, idx, &generic_params, val)
         })
         .collect();
 
@@ -1489,14 +1454,15 @@ pub(crate) fn generic_defaults_recover(
     // we still need one default per parameter
     let defaults = generic_params
         .iter_id()
-        .map(|id| {
+        .enumerate()
+        .map(|(count, id)| {
             let val = match id {
                 itertools::Either::Left(_) => {
                     GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
                 }
                 itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
             };
-            crate::make_binders(db, &generic_params, val)
+            crate::make_binders_with_count(db, count, &generic_params, val)
         })
         .collect();
 
@@ -1675,19 +1641,6 @@ pub enum ValueTyDefId {
 }
 impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
 
-impl ValueTyDefId {
-    pub(crate) fn to_generic_def_id(self) -> Option<GenericDefId> {
-        match self {
-            Self::FunctionId(id) => Some(id.into()),
-            Self::StructId(id) => Some(id.into()),
-            Self::UnionId(id) => Some(id.into()),
-            Self::EnumVariantId(var) => Some(var.into()),
-            Self::ConstId(id) => Some(id.into()),
-            Self::StaticId(_) => None,
-        }
-    }
-}
-
 /// Build the declared type of an item. This depends on the namespace; e.g. for
 /// `struct Foo(usize)`, we have two types: The type of the struct itself, and
 /// the constructor function `(usize) -> Foo` which lives in the values
@@ -1871,48 +1824,26 @@ pub(crate) fn const_or_path_to_chalk(
     }
 }
 
-/// Replaces any 'free' `BoundVar`s in `s` by `TyKind::Error` from the perspective of generic
-/// parameter whose index is `param_index`. A `BoundVar` is free when it is or (syntactically)
-/// appears after the generic parameter of `param_index`.
+/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
+/// num_vars_to_keep) by `TyKind::Unknown`.
 fn fallback_bound_vars<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
     s: T,
-    param_index: usize,
-    parent_start: usize,
+    num_vars_to_keep: usize,
 ) -> T {
-    // Keep in mind that parent generic parameters, if any, come *after* those of the item in
-    // question. In the diagrams below, `c*` and `p*` represent generic parameters of the item and
-    // its parent respectively.
-    let is_allowed = |index| {
-        if param_index < parent_start {
-            // The parameter of `param_index` is one from the item in question. Any parent generic
-            // parameters or the item's generic parameters that come before `param_index` is
-            // allowed.
-            // [c1, .., cj, .., ck, p1, .., pl] where cj is `param_index`
-            //  ^^^^^^              ^^^^^^^^^^ these are allowed
-            !(param_index..parent_start).contains(&index)
-        } else {
-            // The parameter of `param_index` is one from the parent generics. Only parent generic
-            // parameters that come before `param_index` are allowed.
-            // [c1, .., ck, p1, .., pj, .., pl] where pj is `param_index`
-            //              ^^^^^^ these are allowed
-            (parent_start..param_index).contains(&index)
-        }
-    };
-
     crate::fold_free_vars(
         s,
         |bound, binders| {
-            if bound.index_if_innermost().map_or(true, is_allowed) {
-                bound.shifted_in_from(binders).to_ty(Interner)
-            } else {
+            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
                 TyKind::Error.intern(Interner)
+            } else {
+                bound.shifted_in_from(binders).to_ty(Interner)
             }
         },
         |ty, bound, binders| {
-            if bound.index_if_innermost().map_or(true, is_allowed) {
-                bound.shifted_in_from(binders).to_const(Interner, ty)
-            } else {
+            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
                 unknown_const(ty.clone())
+            } else {
+                bound.shifted_in_from(binders).to_const(Interner, ty)
             }
         },
     )
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 5998680dcd..41fcef73d9 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -654,7 +654,7 @@ fn find_matching_impl(
         let r = table.run_in_snapshot(|table| {
             let impl_data = db.impl_data(impl_);
             let substs =
-                TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
+                TyBuilder::subst_for_def(db, impl_).fill_with_inference_vars(table).build();
             let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
 
             table
@@ -1147,9 +1147,10 @@ fn is_valid_candidate(
             }));
             if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
                 let self_ty_matches = table.run_in_snapshot(|table| {
-                    let expected_self_ty = TyBuilder::impl_self_ty(db, impl_id)
-                        .fill_with_inference_vars(table)
-                        .build();
+                    let subst =
+                        TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
+                    let expected_self_ty =
+                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
                     table.unify(&expected_self_ty, &self_ty)
                 });
                 if !self_ty_matches {
@@ -1185,26 +1186,31 @@ fn is_valid_fn_candidate(
 
     table.run_in_snapshot(|table| {
         let container = fn_id.lookup(db.upcast()).container;
-        let (impl_subst, expect_self_ty) = match container {
+        let impl_subst = match container {
             ItemContainerId::ImplId(it) => {
-                let subst =
-                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
-                let self_ty = db.impl_self_ty(it).substitute(Interner, &subst);
-                (subst, self_ty)
+                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
             }
             ItemContainerId::TraitId(it) => {
-                let subst =
-                    TyBuilder::subst_for_def(db, it, None).fill_with_inference_vars(table).build();
-                let self_ty = subst.at(Interner, 0).assert_ty_ref(Interner).clone();
-                (subst, self_ty)
+                TyBuilder::subst_for_def(db, it).fill_with_inference_vars(table).build()
             }
             _ => unreachable!(),
         };
 
-        let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
+        let fn_subst = TyBuilder::subst_for_def(db, fn_id)
+            .use_parent_substs(&impl_subst)
             .fill_with_inference_vars(table)
             .build();
 
+        let expect_self_ty = match container {
+            ItemContainerId::TraitId(_) => fn_subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
+            ItemContainerId::ImplId(impl_id) => {
+                fn_subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
+            }
+            // We should only get called for associated items (impl/trait)
+            ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
+                unreachable!()
+            }
+        };
         check_that!(table.unify(&expect_self_ty, self_ty));
 
         if let Some(receiver_ty) = receiver_ty {
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index e54bcb421a..d6638db028 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -4,7 +4,7 @@
 use std::iter;
 
 use base_db::CrateId;
-use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex};
+use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
 use hir_def::{
     db::DefDatabase,
     generics::{
@@ -24,7 +24,8 @@ use smallvec::{smallvec, SmallVec};
 use syntax::SmolStr;
 
 use crate::{
-    db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, WhereClause,
+    db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
+    TraitRef, TraitRefExt, TyKind, WhereClause,
 };
 
 pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
@@ -173,6 +174,31 @@ pub(super) fn associated_type_by_name_including_super_traits(
 
 pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
     let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
+    if parent_generics.is_some() && matches!(def, GenericDefId::TypeAliasId(_)) {
+        let params = db.generic_params(def);
+        let parent_params = &parent_generics.as_ref().unwrap().params;
+        let has_consts =
+            params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
+        let parent_has_consts =
+            parent_params.iter().any(|(_, x)| matches!(x, TypeOrConstParamData::ConstParamData(_)));
+        return if has_consts || parent_has_consts {
+            // XXX: treat const generic associated types as not existing to avoid crashes
+            // (#11769)
+            //
+            // Note: Also crashes when the parent has const generics (also even if the GAT
+            // doesn't use them), see `tests::regression::gat_crash_3` for an example.
+            // Avoids that by disabling GATs when the parent (i.e. `impl` block) has
+            // const generics (#12193).
+            //
+            // Chalk expects the inner associated type's parameters to come
+            // *before*, not after the trait's generics as we've always done it.
+            // Adapting to this requires a larger refactoring
+            cov_mark::hit!(ignore_gats);
+            Generics { def, params: Interned::new(Default::default()), parent_generics }
+        } else {
+            Generics { def, params, parent_generics }
+        };
+    }
     Generics { def, params: db.generic_params(def), parent_generics }
 }
 
@@ -195,30 +221,23 @@ impl Generics {
         })
     }
 
-    /// Iterator over types and const params of self, then parent.
+    /// Iterator over types and const params of parent, then self.
     pub(crate) fn iter<'a>(
         &'a self,
     ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
         let to_toc_id = |it: &'a Generics| {
             move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
         };
-        self.params.iter().map(to_toc_id(self)).chain(self.iter_parent())
-    }
-
-    /// Iterate over types and const params without parent params.
-    pub(crate) fn iter_self<'a>(
-        &'a self,
-    ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
-        let to_toc_id = |it: &'a Generics| {
-            move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p)
-        };
-        self.params.iter().map(to_toc_id(self))
+        self.parent_generics()
+            .into_iter()
+            .flat_map(move |it| it.params.iter().map(to_toc_id(it)))
+            .chain(self.params.iter().map(to_toc_id(self)))
     }
 
     /// Iterator over types and const params of parent.
     pub(crate) fn iter_parent<'a>(
         &'a self,
-    ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
+    ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
         self.parent_generics().into_iter().flat_map(|it| {
             let to_toc_id =
                 move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p);
@@ -226,18 +245,12 @@ impl Generics {
         })
     }
 
-    /// Returns total number of generic parameters in scope, including those from parent.
     pub(crate) fn len(&self) -> usize {
         let parent = self.parent_generics().map_or(0, Generics::len);
         let child = self.params.type_or_consts.len();
         parent + child
     }
 
-    /// Returns numbers of generic parameters excluding those from parent.
-    pub(crate) fn len_self(&self) -> usize {
-        self.params.type_or_consts.len()
-    }
-
     /// (parent total, self param, type param list, const param list, impl trait)
     pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
         let ty_iter = || self.params.iter().filter_map(|x| x.1.type_param());
@@ -262,17 +275,15 @@ impl Generics {
         if param.parent == self.def {
             let (idx, (_local_id, data)) =
                 self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
-            Some((idx, data))
+            let parent_len = self.parent_generics().map_or(0, Generics::len);
+            Some((parent_len + idx, data))
         } else {
-            self.parent_generics()
-                .and_then(|g| g.find_param(param))
-                // Remember that parent parameters come after parameters for self.
-                .map(|(idx, data)| (self.len_self() + idx, data))
+            self.parent_generics().and_then(|g| g.find_param(param))
         }
     }
 
-    pub(crate) fn parent_generics(&self) -> Option<&Generics> {
-        self.parent_generics.as_deref()
+    fn parent_generics(&self) -> Option<&Generics> {
+        self.parent_generics.as_ref().map(|it| &**it)
     }
 
     /// Returns a Substitution that replaces each parameter by a bound variable.
@@ -284,10 +295,18 @@ impl Generics {
         Substitution::from_iter(
             Interner,
             self.iter_id().enumerate().map(|(idx, id)| match id {
-                Either::Left(_) => BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner),
-                Either::Right(id) => BoundVar::new(debruijn, idx)
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
+                Either::Left(_) => GenericArgData::Ty(
+                    TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
+                )
+                .intern(Interner),
+                Either::Right(id) => GenericArgData::Const(
+                    ConstData {
+                        value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
+                        ty: db.const_param_ty(id),
+                    }
+                    .intern(Interner),
+                )
+                .intern(Interner),
             }),
         )
     }
@@ -297,12 +316,18 @@ impl Generics {
         Substitution::from_iter(
             Interner,
             self.iter_id().map(|id| match id {
-                Either::Left(id) => {
-                    crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner)
-                }
-                Either::Right(id) => crate::to_placeholder_idx(db, id.into())
-                    .to_const(Interner, db.const_param_ty(id))
-                    .cast(Interner),
+                Either::Left(id) => GenericArgData::Ty(
+                    TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
+                )
+                .intern(Interner),
+                Either::Right(id) => GenericArgData::Const(
+                    ConstData {
+                        value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
+                        ty: db.const_param_ty(id),
+                    }
+                    .intern(Interner),
+                )
+                .intern(Interner),
             }),
         )
     }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index f5324208c9..d1c8fa59ae 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -61,6 +61,7 @@ use hir_ty::{
     diagnostics::BodyValidationDiagnostic,
     method_resolution::{self, TyFingerprint},
     primitive::UintTy,
+    subst_prefix,
     traits::FnTrait,
     AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
     GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
@@ -1089,7 +1090,7 @@ impl Adt {
     pub fn ty_with_args(self, db: &dyn HirDatabase, args: &[Type]) -> Type {
         let id = AdtId::from(self);
         let mut it = args.iter().map(|t| t.ty.clone());
-        let ty = TyBuilder::def_ty(db, id.into(), None)
+        let ty = TyBuilder::def_ty(db, id.into())
             .fill(|x| {
                 let r = it.next().unwrap_or_else(|| TyKind::Error.intern(Interner));
                 match x {
@@ -2546,7 +2547,7 @@ impl TypeParam {
         let resolver = self.id.parent().resolver(db.upcast());
         let ty = params.get(local_idx)?.clone();
         let subst = TyBuilder::placeholder_subst(db, self.id.parent());
-        let ty = ty.substitute(Interner, &subst);
+        let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
         match ty.data(Interner) {
             GenericArgData::Ty(x) => Some(Type::new_with_resolver_inner(db, &resolver, x.clone())),
             _ => None,
@@ -2800,22 +2801,7 @@ impl Type {
     }
 
     fn from_def(db: &dyn HirDatabase, def: impl HasResolver + Into<TyDefId>) -> Type {
-        let ty_def = def.into();
-        let parent_subst = match ty_def {
-            TyDefId::TypeAliasId(id) => match id.lookup(db.upcast()).container {
-                ItemContainerId::TraitId(id) => {
-                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
-                    Some(subst)
-                }
-                ItemContainerId::ImplId(id) => {
-                    let subst = TyBuilder::subst_for_def(db, id, None).fill_with_unknown().build();
-                    Some(subst)
-                }
-                _ => None,
-            },
-            _ => None,
-        };
-        let ty = TyBuilder::def_ty(db, ty_def, parent_subst).fill_with_unknown().build();
+        let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
         Type::new(db, def, ty)
     }
 
@@ -2955,11 +2941,7 @@ impl Type {
         alias: TypeAlias,
     ) -> Option<Type> {
         let mut args = args.iter();
-        let trait_id = match alias.id.lookup(db.upcast()).container {
-            ItemContainerId::TraitId(id) => id,
-            _ => unreachable!("non assoc type alias reached in normalize_trait_assoc_type()"),
-        };
-        let parent_subst = TyBuilder::subst_for_def(db, trait_id, None)
+        let projection = TyBuilder::assoc_type_projection(db, alias.id)
             .push(self.ty.clone())
             .fill(|x| {
                 // FIXME: this code is not covered in tests.
@@ -2971,8 +2953,6 @@ impl Type {
                 }
             })
             .build();
-        // FIXME: We don't handle GATs yet.
-        let projection = TyBuilder::assoc_type_projection(db, alias.id, Some(parent_subst)).build();
 
         let ty = db.normalize_projection(projection, self.env.clone());
         if ty.is_unknown() {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 07bae2b38c..342912b678 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -22,7 +22,7 @@ use hir_def::{
     resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
     type_ref::Mutability,
     AsMacroCall, AssocItemId, DefWithBodyId, FieldId, FunctionId, ItemContainerId, LocalFieldId,
-    Lookup, ModuleDefId, TraitId, VariantId,
+    Lookup, ModuleDefId, VariantId,
 };
 use hir_expand::{
     builtin_fn_macro::BuiltinFnLikeExpander,
@@ -302,15 +302,10 @@ impl SourceAnalyzer {
             }
         }
 
-        let future_trait = db
-            .lang_item(self.resolver.krate(), hir_expand::name![future_trait].to_smol_str())?
-            .as_trait()?;
         let poll_fn = db
             .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
             .as_function()?;
-        // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
-        // doesn't have any generic parameters, so we skip building another subst for `poll()`.
-        let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
+        let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
         Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
     }
 
@@ -326,10 +321,8 @@ impl SourceAnalyzer {
         };
         let ty = self.ty_of_expr(db, &prefix_expr.expr()?.into())?;
 
-        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
-        // HACK: subst for all methods coincides with that for their trait because the methods
-        // don't have any generic parameters, so we skip building another subst for the methods.
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
+        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -344,10 +337,8 @@ impl SourceAnalyzer {
 
         let lang_item_name = name![index];
 
-        let (op_trait, op_fn) = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
-        // HACK: subst for all methods coincides with that for their trait because the methods
-        // don't have any generic parameters, so we skip building another subst for the methods.
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
+        let op_fn = self.lang_trait_fn(db, &lang_item_name, &lang_item_name)?;
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn)
             .push(base_ty.clone())
             .push(index_ty.clone())
             .build();
@@ -363,14 +354,10 @@ impl SourceAnalyzer {
         let lhs = self.ty_of_expr(db, &binop_expr.lhs()?.into())?;
         let rhs = self.ty_of_expr(db, &binop_expr.rhs()?.into())?;
 
-        let (op_trait, op_fn) = lang_names_for_bin_op(op)
+        let op_fn = lang_names_for_bin_op(op)
             .and_then(|(name, lang_item)| self.lang_trait_fn(db, &lang_item, &name))?;
-        // HACK: subst for `index()` coincides with that for `Index` because `index()` itself
-        // doesn't have any generic parameters, so we skip building another subst for `index()`.
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None)
-            .push(lhs.clone())
-            .push(rhs.clone())
-            .build();
+        let substs =
+            hir_ty::TyBuilder::subst_for_def(db, op_fn).push(lhs.clone()).push(rhs.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -384,13 +371,7 @@ impl SourceAnalyzer {
 
         let op_fn =
             db.lang_item(self.resolver.krate(), name![branch].to_smol_str())?.as_function()?;
-        let op_trait = match op_fn.lookup(db.upcast()).container {
-            ItemContainerId::TraitId(id) => id,
-            _ => return None,
-        };
-        // HACK: subst for `branch()` coincides with that for `Try` because `branch()` itself
-        // doesn't have any generic parameters, so we skip building another subst for `branch()`.
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
+        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
 
         Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
     }
@@ -818,10 +799,9 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         lang_trait: &Name,
         method_name: &Name,
-    ) -> Option<(TraitId, FunctionId)> {
-        let trait_id = db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?;
-        let fn_id = db.trait_data(trait_id).method_by_name(method_name)?;
-        Some((trait_id, fn_id))
+    ) -> Option<FunctionId> {
+        db.trait_data(db.lang_item(self.resolver.krate(), lang_trait.to_smol_str())?.as_trait()?)
+            .method_by_name(method_name)
     }
 
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
diff --git a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
deleted file mode 100644
index 8d11e0bac9..0000000000
--- a/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ /dev/null
@@ -1,822 +0,0 @@
-use either::Either;
-use ide_db::defs::Definition;
-use itertools::Itertools;
-use syntax::{
-    ast::{self, AstNode, HasGenericParams, HasVisibility},
-    match_ast, SyntaxKind, SyntaxNode,
-};
-
-use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
-
-// Assist: convert_named_struct_to_tuple_struct
-//
-// Converts struct with named fields to tuple struct, and analogously for enum variants with named
-// fields.
-//
-// ```
-// struct Point$0 { x: f32, y: f32 }
-//
-// impl Point {
-//     pub fn new(x: f32, y: f32) -> Self {
-//         Point { x, y }
-//     }
-//
-//     pub fn x(&self) -> f32 {
-//         self.x
-//     }
-//
-//     pub fn y(&self) -> f32 {
-//         self.y
-//     }
-// }
-// ```
-// ->
-// ```
-// struct Point(f32, f32);
-//
-// impl Point {
-//     pub fn new(x: f32, y: f32) -> Self {
-//         Point(x, y)
-//     }
-//
-//     pub fn x(&self) -> f32 {
-//         self.0
-//     }
-//
-//     pub fn y(&self) -> f32 {
-//         self.1
-//     }
-// }
-// ```
-pub(crate) fn convert_named_struct_to_tuple_struct(
-    acc: &mut Assists,
-    ctx: &AssistContext<'_>,
-) -> Option<()> {
-    let strukt = ctx
-        .find_node_at_offset::<ast::Struct>()
-        .map(Either::Left)
-        .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
-    let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
-    let record_fields = match field_list {
-        ast::FieldList::RecordFieldList(it) => it,
-        ast::FieldList::TupleFieldList(_) => return None,
-    };
-    let strukt_def = match &strukt {
-        Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
-        Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
-    };
-    let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
-
-    acc.add(
-        AssistId("convert_named_struct_to_tuple_struct", AssistKind::RefactorRewrite),
-        "Convert to tuple struct",
-        target,
-        |edit| {
-            edit_field_references(ctx, edit, record_fields.fields());
-            edit_struct_references(ctx, edit, strukt_def);
-            edit_struct_def(ctx, edit, &strukt, record_fields);
-        },
-    )
-}
-
-fn edit_struct_def(
-    ctx: &AssistContext<'_>,
-    edit: &mut SourceChangeBuilder,
-    strukt: &Either<ast::Struct, ast::Variant>,
-    record_fields: ast::RecordFieldList,
-) {
-    let tuple_fields = record_fields
-        .fields()
-        .filter_map(|f| Some(ast::make::tuple_field(f.visibility(), f.ty()?)));
-    let tuple_fields = ast::make::tuple_field_list(tuple_fields);
-    let record_fields_text_range = record_fields.syntax().text_range();
-
-    edit.edit_file(ctx.file_id());
-    edit.replace(record_fields_text_range, tuple_fields.syntax().text());
-
-    if let Either::Left(strukt) = strukt {
-        if let Some(w) = strukt.where_clause() {
-            let mut where_clause = w.to_string();
-            if where_clause.ends_with(',') {
-                where_clause.pop();
-            }
-            where_clause.push(';');
-
-            edit.delete(w.syntax().text_range());
-            edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
-            edit.insert(record_fields_text_range.end(), where_clause);
-            edit.insert(record_fields_text_range.end(), ast::make::tokens::single_newline().text());
-
-            if let Some(tok) = strukt
-                .generic_param_list()
-                .and_then(|l| l.r_angle_token())
-                .and_then(|tok| tok.next_token())
-                .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
-            {
-                edit.delete(tok.text_range());
-            }
-        } else {
-            edit.insert(record_fields_text_range.end(), ";");
-        }
-    }
-
-    if let Some(tok) = record_fields
-        .l_curly_token()
-        .and_then(|tok| tok.prev_token())
-        .filter(|tok| tok.kind() == SyntaxKind::WHITESPACE)
-    {
-        edit.delete(tok.text_range())
-    }
-}
-
-fn edit_struct_references(
-    ctx: &AssistContext<'_>,
-    edit: &mut SourceChangeBuilder,
-    strukt: Either<hir::Struct, hir::Variant>,
-) {
-    let strukt_def = match strukt {
-        Either::Left(s) => Definition::Adt(hir::Adt::Struct(s)),
-        Either::Right(v) => Definition::Variant(v),
-    };
-    let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
-
-    let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> {
-        match_ast! {
-            match node {
-                ast::RecordPat(record_struct_pat) => {
-                    edit.replace(
-                        record_struct_pat.syntax().text_range(),
-                        ast::make::tuple_struct_pat(
-                            record_struct_pat.path()?,
-                            record_struct_pat
-                                .record_pat_field_list()?
-                                .fields()
-                                .filter_map(|pat| pat.pat())
-                        )
-                        .to_string()
-                    );
-                },
-                ast::RecordExpr(record_expr) => {
-                    let path = record_expr.path()?;
-                    let args = record_expr
-                        .record_expr_field_list()?
-                        .fields()
-                        .filter_map(|f| f.expr())
-                        .join(", ");
-
-                    edit.replace(record_expr.syntax().text_range(), format!("{path}({args})"));
-                },
-                _ => return None,
-            }
-        }
-        Some(())
-    };
-
-    for (file_id, refs) in usages {
-        edit.edit_file(file_id);
-        for r in refs {
-            for node in r.name.syntax().ancestors() {
-                if edit_node(edit, node).is_some() {
-                    break;
-                }
-            }
-        }
-    }
-}
-
-fn edit_field_references(
-    ctx: &AssistContext<'_>,
-    edit: &mut SourceChangeBuilder,
-    fields: impl Iterator<Item = ast::RecordField>,
-) {
-    for (index, field) in fields.enumerate() {
-        let field = match ctx.sema.to_def(&field) {
-            Some(it) => it,
-            None => continue,
-        };
-        let def = Definition::Field(field);
-        let usages = def.usages(&ctx.sema).all();
-        for (file_id, refs) in usages {
-            edit.edit_file(file_id);
-            for r in refs {
-                if let Some(name_ref) = r.name.as_name_ref() {
-                    // Only edit the field reference if it's part of a `.field` access
-                    if name_ref.syntax().parent().and_then(ast::FieldExpr::cast).is_some() {
-                        edit.replace(name_ref.syntax().text_range(), index.to_string());
-                    }
-                }
-            }
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::{check_assist, check_assist_not_applicable};
-
-    use super::*;
-
-    #[test]
-    fn not_applicable_other_than_record_struct() {
-        check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0(u32)"#);
-        check_assist_not_applicable(convert_named_struct_to_tuple_struct, r#"struct Foo$0;"#);
-    }
-
-    #[test]
-    fn convert_simple_struct() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct Inner;
-struct A$0 { inner: Inner }
-
-impl A {
-    fn new(inner: Inner) -> A {
-        A { inner }
-    }
-
-    fn new_with_default() -> A {
-        A::new(Inner)
-    }
-
-    fn into_inner(self) -> Inner {
-        self.inner
-    }
-}"#,
-            r#"
-struct Inner;
-struct A(Inner);
-
-impl A {
-    fn new(inner: Inner) -> A {
-        A(inner)
-    }
-
-    fn new_with_default() -> A {
-        A::new(Inner)
-    }
-
-    fn into_inner(self) -> Inner {
-        self.0
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_struct_referenced_via_self_kw() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct Inner;
-struct A$0 { inner: Inner }
-
-impl A {
-    fn new(inner: Inner) -> Self {
-        Self { inner }
-    }
-
-    fn new_with_default() -> Self {
-        Self::new(Inner)
-    }
-
-    fn into_inner(self) -> Inner {
-        self.inner
-    }
-}"#,
-            r#"
-struct Inner;
-struct A(Inner);
-
-impl A {
-    fn new(inner: Inner) -> Self {
-        Self(inner)
-    }
-
-    fn new_with_default() -> Self {
-        Self::new(Inner)
-    }
-
-    fn into_inner(self) -> Inner {
-        self.0
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_destructured_struct() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct Inner;
-struct A$0 { inner: Inner }
-
-impl A {
-    fn into_inner(self) -> Inner {
-        let A { inner: a } = self;
-        a
-    }
-
-    fn into_inner_via_self(self) -> Inner {
-        let Self { inner } = self;
-        inner
-    }
-}"#,
-            r#"
-struct Inner;
-struct A(Inner);
-
-impl A {
-    fn into_inner(self) -> Inner {
-        let A(a) = self;
-        a
-    }
-
-    fn into_inner_via_self(self) -> Inner {
-        let Self(inner) = self;
-        inner
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_struct_with_visibility() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct A$0 {
-    pub first: u32,
-    pub(crate) second: u64
-}
-
-impl A {
-    fn new() -> A {
-        A { first: 42, second: 42 }
-    }
-
-    fn into_first(self) -> u32 {
-        self.first
-    }
-
-    fn into_second(self) -> u64 {
-        self.second
-    }
-}"#,
-            r#"
-struct A(pub u32, pub(crate) u64);
-
-impl A {
-    fn new() -> A {
-        A(42, 42)
-    }
-
-    fn into_first(self) -> u32 {
-        self.0
-    }
-
-    fn into_second(self) -> u64 {
-        self.1
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_struct_with_wrapped_references() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct Inner$0 { uint: u32 }
-struct Outer { inner: Inner }
-
-impl Outer {
-    fn new() -> Self {
-        Self { inner: Inner { uint: 42 } }
-    }
-
-    fn into_inner(self) -> u32 {
-        self.inner.uint
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer { inner: Inner { uint: x } } = self;
-        x
-    }
-}"#,
-            r#"
-struct Inner(u32);
-struct Outer { inner: Inner }
-
-impl Outer {
-    fn new() -> Self {
-        Self { inner: Inner(42) }
-    }
-
-    fn into_inner(self) -> u32 {
-        self.inner.0
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer { inner: Inner(x) } = self;
-        x
-    }
-}"#,
-        );
-
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct Inner { uint: u32 }
-struct Outer$0 { inner: Inner }
-
-impl Outer {
-    fn new() -> Self {
-        Self { inner: Inner { uint: 42 } }
-    }
-
-    fn into_inner(self) -> u32 {
-        self.inner.uint
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer { inner: Inner { uint: x } } = self;
-        x
-    }
-}"#,
-            r#"
-struct Inner { uint: u32 }
-struct Outer(Inner);
-
-impl Outer {
-    fn new() -> Self {
-        Self(Inner { uint: 42 })
-    }
-
-    fn into_inner(self) -> u32 {
-        self.0.uint
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer(Inner { uint: x }) = self;
-        x
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_struct_with_multi_file_references() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-//- /main.rs
-struct Inner;
-struct A$0 { inner: Inner }
-
-mod foo;
-
-//- /foo.rs
-use crate::{A, Inner};
-fn f() {
-    let a = A { inner: Inner };
-}
-"#,
-            r#"
-//- /main.rs
-struct Inner;
-struct A(Inner);
-
-mod foo;
-
-//- /foo.rs
-use crate::{A, Inner};
-fn f() {
-    let a = A(Inner);
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn convert_struct_with_where_clause() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-struct Wrap$0<T>
-where
-    T: Display,
-{ field1: T }
-"#,
-            r#"
-struct Wrap<T>(T)
-where
-    T: Display;
-
-"#,
-        );
-    }
-
-    #[test]
-    fn not_applicable_other_than_record_variant() {
-        check_assist_not_applicable(
-            convert_named_struct_to_tuple_struct,
-            r#"enum Enum { Variant$0(usize) };"#,
-        );
-        check_assist_not_applicable(
-            convert_named_struct_to_tuple_struct,
-            r#"enum Enum { Variant$0 }"#,
-        );
-    }
-
-    #[test]
-    fn convert_simple_variant() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-enum A {
-    $0Variant { field1: usize },
-}
-
-impl A {
-    fn new(value: usize) -> A {
-        A::Variant { field1: value }
-    }
-
-    fn new_with_default() -> A {
-        A::new(Default::default())
-    }
-
-    fn value(self) -> usize {
-        match self {
-            A::Variant { field1: value } => value,
-        }
-    }
-}"#,
-            r#"
-enum A {
-    Variant(usize),
-}
-
-impl A {
-    fn new(value: usize) -> A {
-        A::Variant(value)
-    }
-
-    fn new_with_default() -> A {
-        A::new(Default::default())
-    }
-
-    fn value(self) -> usize {
-        match self {
-            A::Variant(value) => value,
-        }
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_variant_referenced_via_self_kw() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-enum A {
-    $0Variant { field1: usize },
-}
-
-impl A {
-    fn new(value: usize) -> A {
-        Self::Variant { field1: value }
-    }
-
-    fn new_with_default() -> A {
-        Self::new(Default::default())
-    }
-
-    fn value(self) -> usize {
-        match self {
-            Self::Variant { field1: value } => value,
-        }
-    }
-}"#,
-            r#"
-enum A {
-    Variant(usize),
-}
-
-impl A {
-    fn new(value: usize) -> A {
-        Self::Variant(value)
-    }
-
-    fn new_with_default() -> A {
-        Self::new(Default::default())
-    }
-
-    fn value(self) -> usize {
-        match self {
-            Self::Variant(value) => value,
-        }
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_destructured_variant() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-enum A {
-    $0Variant { field1: usize },
-}
-
-impl A {
-    fn into_inner(self) -> usize {
-        let A::Variant { field1: first } = self;
-        first
-    }
-
-    fn into_inner_via_self(self) -> usize {
-        let Self::Variant { field1: first } = self;
-        first
-    }
-}"#,
-            r#"
-enum A {
-    Variant(usize),
-}
-
-impl A {
-    fn into_inner(self) -> usize {
-        let A::Variant(first) = self;
-        first
-    }
-
-    fn into_inner_via_self(self) -> usize {
-        let Self::Variant(first) = self;
-        first
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_variant_with_wrapped_references() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-enum Inner {
-    $0Variant { field1: usize },
-}
-enum Outer {
-    Variant(Inner),
-}
-
-impl Outer {
-    fn new() -> Self {
-        Self::Variant(Inner::Variant { field1: 42 })
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer::Variant(Inner::Variant { field1: x }) = self;
-        x
-    }
-}"#,
-            r#"
-enum Inner {
-    Variant(usize),
-}
-enum Outer {
-    Variant(Inner),
-}
-
-impl Outer {
-    fn new() -> Self {
-        Self::Variant(Inner::Variant(42))
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer::Variant(Inner::Variant(x)) = self;
-        x
-    }
-}"#,
-        );
-
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-enum Inner {
-    Variant(usize),
-}
-enum Outer {
-    $0Variant { field1: Inner },
-}
-
-impl Outer {
-    fn new() -> Self {
-        Self::Variant { field1: Inner::Variant(42) }
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer::Variant { field1: Inner::Variant(x) } = self;
-        x
-    }
-}"#,
-            r#"
-enum Inner {
-    Variant(usize),
-}
-enum Outer {
-    Variant(Inner),
-}
-
-impl Outer {
-    fn new() -> Self {
-        Self::Variant(Inner::Variant(42))
-    }
-
-    fn into_inner_destructed(self) -> u32 {
-        let Outer::Variant(Inner::Variant(x)) = self;
-        x
-    }
-}"#,
-        );
-    }
-
-    #[test]
-    fn convert_variant_with_multi_file_references() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-//- /main.rs
-struct Inner;
-enum A {
-    $0Variant { field1: Inner },
-}
-
-mod foo;
-
-//- /foo.rs
-use crate::{A, Inner};
-fn f() {
-    let a = A::Variant { field1: Inner };
-}
-"#,
-            r#"
-//- /main.rs
-struct Inner;
-enum A {
-    Variant(Inner),
-}
-
-mod foo;
-
-//- /foo.rs
-use crate::{A, Inner};
-fn f() {
-    let a = A::Variant(Inner);
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn convert_directly_used_variant() {
-        check_assist(
-            convert_named_struct_to_tuple_struct,
-            r#"
-//- /main.rs
-struct Inner;
-enum A {
-    $0Variant { field1: Inner },
-}
-
-mod foo;
-
-//- /foo.rs
-use crate::{A::Variant, Inner};
-fn f() {
-    let a = Variant { field1: Inner };
-}
-"#,
-            r#"
-//- /main.rs
-struct Inner;
-enum A {
-    Variant(Inner),
-}
-
-mod foo;
-
-//- /foo.rs
-use crate::{A::Variant, Inner};
-fn f() {
-    let a = Variant(Inner);
-}
-"#,
-        );
-    }
-}
diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 970e948dfd..8d5cab283d 100644
--- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -9,7 +9,7 @@ use ide_db::{
     search::FileReference,
     FxHashSet, RootDatabase,
 };
-use itertools::Itertools;
+use itertools::{Itertools, Position};
 use syntax::{
     ast::{
         self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, HasAttrs, HasGenericParams,
@@ -298,7 +298,37 @@ fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList
     let name = variant.name()?;
     let ty = generics
         .filter(|generics| generics.generic_params().count() > 0)
-        .map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args())))
+        .map(|generics| {
+            let mut generic_str = String::with_capacity(8);
+
+            for (p, more) in generics.generic_params().with_position().map(|p| match p {
+                Position::First(p) | Position::Middle(p) => (p, true),
+                Position::Last(p) | Position::Only(p) => (p, false),
+            }) {
+                match p {
+                    ast::GenericParam::ConstParam(konst) => {
+                        if let Some(name) = konst.name() {
+                            generic_str.push_str(name.text().as_str());
+                        }
+                    }
+                    ast::GenericParam::LifetimeParam(lt) => {
+                        if let Some(lt) = lt.lifetime() {
+                            generic_str.push_str(lt.text().as_str());
+                        }
+                    }
+                    ast::GenericParam::TypeParam(ty) => {
+                        if let Some(name) = ty.name() {
+                            generic_str.push_str(name.text().as_str());
+                        }
+                    }
+                }
+                if more {
+                    generic_str.push_str(", ");
+                }
+            }
+
+            make::ty(&format!("{}<{}>", &name.text(), &generic_str))
+        })
         .unwrap_or_else(|| make::ty(&name.text()));
 
     // change from a record to a tuple field list
diff --git a/crates/ide-assists/src/handlers/generate_impl.rs b/crates/ide-assists/src/handlers/generate_impl.rs
index 307cea3d0a..68287a20bf 100644
--- a/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/crates/ide-assists/src/handlers/generate_impl.rs
@@ -52,7 +52,6 @@ mod tests {
 
     use super::*;
 
-    // FIXME: break up into separate test fns
     #[test]
     fn test_add_impl() {
         check_assist(
@@ -135,18 +134,6 @@ mod tests {
             }"#,
         );
 
-        check_assist(
-            generate_impl,
-            r#"
-            struct Defaulted<const N: i32 = 0> {}$0"#,
-            r#"
-            struct Defaulted<const N: i32 = 0> {}
-
-            impl<const N: i32> Defaulted<N> {
-                $0
-            }"#,
-        );
-
         check_assist(
             generate_impl,
             r#"pub trait Trait {}
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index a07318cefa..82bcc3dfa5 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -121,7 +121,6 @@ mod handlers {
     mod convert_iter_for_each_to_for;
     mod convert_let_else_to_match;
     mod convert_tuple_struct_to_named_struct;
-    mod convert_named_struct_to_tuple_struct;
     mod convert_to_guarded_return;
     mod convert_two_arm_bool_match_to_matches_macro;
     mod convert_while_to_loop;
@@ -219,7 +218,6 @@ mod handlers {
             convert_iter_for_each_to_for::convert_iter_for_each_to_for,
             convert_iter_for_each_to_for::convert_for_loop_with_for_each,
             convert_let_else_to_match::convert_let_else_to_match,
-            convert_named_struct_to_tuple_struct::convert_named_struct_to_tuple_struct,
             convert_to_guarded_return::convert_to_guarded_return,
             convert_tuple_struct_to_named_struct::convert_tuple_struct_to_named_struct,
             convert_two_arm_bool_match_to_matches_macro::convert_two_arm_bool_match_to_matches_macro,
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 38396cd7d7..4ab6e2627f 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -2,6 +2,8 @@
 
 use std::ops;
 
+use itertools::Itertools;
+
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 use hir::{db::HirDatabase, HirDisplay, Semantics};
 use ide_db::{famous_defs::FamousDefs, path_transform::PathTransform, RootDatabase, SnippetCap};
@@ -13,7 +15,7 @@ use syntax::{
         edit_in_place::{AttrsOwnerEdit, Removable},
         make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
     },
-    ted, AstNode, AstToken, Direction, SourceFile,
+    ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
     SyntaxKind::*,
     SyntaxNode, TextRange, TextSize, T,
 };
@@ -422,44 +424,34 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
 }
 
 fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str) -> String {
-    // Ensure lifetime params are before type & const params
-    let generic_params = adt.generic_param_list().map(|generic_params| {
-        let lifetime_params =
-            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
-        let ty_or_const_params = generic_params.type_or_const_params().filter_map(|param| {
-            // remove defaults since they can't be specified in impls
-            match param {
-                ast::TypeOrConstParam::Type(param) => {
-                    let param = param.clone_for_update();
-                    param.remove_default();
-                    Some(ast::GenericParam::TypeParam(param))
-                }
-                ast::TypeOrConstParam::Const(param) => {
-                    let param = param.clone_for_update();
-                    param.remove_default();
-                    Some(ast::GenericParam::ConstParam(param))
-                }
-            }
-        });
-
-        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
-    });
-
-    // FIXME: use syntax::make & mutable AST apis instead
-    // `trait_text` and `code` can't be opaque blobs of text
+    let generic_params = adt.generic_param_list();
     let mut buf = String::with_capacity(code.len());
-
-    // Copy any cfg attrs from the original adt
     buf.push_str("\n\n");
-    let cfg_attrs = adt
-        .attrs()
-        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
-    cfg_attrs.for_each(|attr| buf.push_str(&format!("{attr}\n")));
-
-    // `impl{generic_params} {trait_text} for {name}{generic_params.to_generic_args()}`
+    adt.attrs()
+        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false))
+        .for_each(|attr| buf.push_str(format!("{}\n", attr).as_str()));
     buf.push_str("impl");
     if let Some(generic_params) = &generic_params {
-        format_to!(buf, "{generic_params}");
+        let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
+        let toc_params = generic_params.type_or_const_params().map(|toc_param| {
+            let type_param = match toc_param {
+                ast::TypeOrConstParam::Type(x) => x,
+                ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(),
+            };
+            let mut buf = String::new();
+            if let Some(it) = type_param.name() {
+                format_to!(buf, "{}", it.syntax());
+            }
+            if let Some(it) = type_param.colon_token() {
+                format_to!(buf, "{} ", it);
+            }
+            if let Some(it) = type_param.type_bound_list() {
+                format_to!(buf, "{}", it.syntax());
+            }
+            buf
+        });
+        let generics = lifetimes.chain(toc_params).format(", ");
+        format_to!(buf, "<{}>", generics);
     }
     buf.push(' ');
     if let Some(trait_text) = trait_text {
@@ -468,15 +460,23 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
     }
     buf.push_str(&adt.name().unwrap().text());
     if let Some(generic_params) = generic_params {
-        format_to!(buf, "{}", generic_params.to_generic_args());
+        let lifetime_params = generic_params
+            .lifetime_params()
+            .filter_map(|it| it.lifetime())
+            .map(|it| SmolStr::from(it.text()));
+        let toc_params = generic_params
+            .type_or_const_params()
+            .filter_map(|it| it.name())
+            .map(|it| SmolStr::from(it.text()));
+        format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", "))
     }
 
     match adt.where_clause() {
         Some(where_clause) => {
-            format_to!(buf, "\n{where_clause}\n{{\n{code}\n}}");
+            format_to!(buf, "\n{}\n{{\n{}\n}}", where_clause, code);
         }
         None => {
-            format_to!(buf, " {{\n{code}\n}}");
+            format_to!(buf, " {{\n{}\n}}", code);
         }
     }
 
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index d96827326c..92ce26b422 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -232,13 +232,8 @@ pub(crate) fn token_as_doc_comment(doc_token: &SyntaxToken) -> Option<DocComment
     (match_ast! {
         match doc_token {
             ast::Comment(comment) => TextSize::try_from(comment.prefix().len()).ok(),
-            ast::String(string) => {
-                doc_token.parent_ancestors().find_map(ast::Attr::cast).filter(|attr| attr.simple_name().as_deref() == Some("doc"))?;
-                if doc_token.parent_ancestors().find_map(ast::MacroCall::cast).filter(|mac| mac.path().and_then(|p| p.segment()?.name_ref()).as_ref().map(|n| n.text()).as_deref() == Some("include_str")).is_some() {
-                    return None;
-                }
-                string.open_quote_text_range().map(|it| it.len())
-            },
+            ast::String(string) => doc_token.parent_ancestors().find_map(ast::Attr::cast)
+                .filter(|attr| attr.simple_name().as_deref() == Some("doc")).and_then(|_| string.open_quote_text_range().map(|it| it.len())),
             _ => None,
         }
     }).map(|prefix_len| DocCommentToken { prefix_len, doc_token: doc_token.clone() })
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index d0be1b3f40..36a648fe4a 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -48,14 +48,10 @@ pub(crate) fn goto_definition(
             _ => 1,
         })?;
     if let Some(doc_comment) = token_as_doc_comment(&original_token) {
-        return doc_comment.get_definition_with_descend_at(
-            sema,
-            position.offset,
-            |def, _, link_range| {
-                let nav = def.try_to_nav(db)?;
-                Some(RangeInfo::new(link_range, vec![nav]))
-            },
-        );
+        return doc_comment.get_definition_with_descend_at(sema, position.offset, |def, _, _| {
+            let nav = def.try_to_nav(db)?;
+            Some(RangeInfo::new(original_token.text_range(), vec![nav]))
+        });
     }
     let navs = sema
         .descend_into_macros(original_token.clone())
@@ -99,14 +95,6 @@ fn try_lookup_include_path(
     if !matches!(&*name.text(), "include" | "include_str" | "include_bytes") {
         return None;
     }
-
-    // Ignore non-built-in macros to account for shadowing
-    if let Some(it) = sema.resolve_macro_call(&macro_call) {
-        if !matches!(it.kind(sema.db), hir::MacroKind::BuiltIn) {
-            return None;
-        }
-    }
-
     let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
     let size = sema.db.file_text(file_id).len().try_into().ok()?;
     Some(NavigationTarget {
@@ -168,6 +156,9 @@ mod tests {
     fn check(ra_fixture: &str) {
         let (analysis, position, expected) = fixture::annotations(ra_fixture);
         let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
+        if navs.is_empty() {
+            panic!("unresolved reference")
+        }
 
         let cmp = |&FileRange { file_id, range }: &_| (file_id, range.start());
         let navs = navs
@@ -1357,10 +1348,6 @@ fn f(e: Enum) {
         check(
             r#"
 //- /main.rs
-
-#[rustc_builtin_macro]
-macro_rules! include_str {}
-
 fn main() {
     let str = include_str!("foo.txt$0");
 }
@@ -1370,42 +1357,6 @@ fn main() {
 "#,
         );
     }
-
-    #[test]
-    fn goto_doc_include_str() {
-        check(
-            r#"
-//- /main.rs
-#[rustc_builtin_macro]
-macro_rules! include_str {}
-
-#[doc = include_str!("docs.md$0")]
-struct Item;
-
-//- /docs.md
-// docs
-//^file
-"#,
-        );
-    }
-
-    #[test]
-    fn goto_shadow_include() {
-        check(
-            r#"
-//- /main.rs
-macro_rules! include {
-    ("included.rs") => {}
-}
-
-include!("included.rs$0");
-
-//- /included.rs
-// empty
-"#,
-        );
-    }
-
     #[cfg(test)]
     mod goto_impl_of_trait_fn {
         use super::check;
diff --git a/crates/ide/src/highlight_related.rs b/crates/ide/src/highlight_related.rs
index 540a115832..1bdd626f1e 100644
--- a/crates/ide/src/highlight_related.rs
+++ b/crates/ide/src/highlight_related.rs
@@ -1373,22 +1373,6 @@ fn main() {
     ().func$0();
      //^^^^
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn test_assoc_type_highlighting() {
-        check(
-            r#"
-trait Trait {
-    type Output;
-      // ^^^^^^
-}
-impl Trait for () {
-    type Output$0 = ();
-      // ^^^^^^
-}
 "#,
         );
     }
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 72ddf80928..8c3e8681d9 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -717,6 +717,7 @@ fn cargo_to_crate_graph(
                 load_proc_macro,
                 &mut pkg_to_lib_crate,
                 &public_deps,
+                libproc_macro,
                 cargo,
                 &pkg_crates,
                 build_scripts,
@@ -782,6 +783,7 @@ fn handle_rustc_crates(
     load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
     pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
     public_deps: &SysrootPublicDeps,
+    libproc_macro: Option<CrateId>,
     cargo: &CargoWorkspace,
     pkg_crates: &FxHashMap<Package, Vec<(CrateId, TargetKind)>>,
     build_scripts: &WorkspaceBuildScripts,
@@ -843,6 +845,19 @@ fn handle_rustc_crates(
                         rustc_workspace[tgt].is_proc_macro,
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
+
+                    // Even crates that don't set proc-macro = true are allowed to depend on proc_macro
+                    // (just none of the APIs work when called outside of a proc macro).
+                    if let Some(proc_macro) = libproc_macro {
+                        add_dep_with_prelude(
+                            crate_graph,
+                            crate_id,
+                            CrateName::new("proc_macro").unwrap(),
+                            proc_macro,
+                            cargo[tgt].is_proc_macro,
+                        );
+                    }
+
                     // Add dependencies on core / std / alloc for this crate
                     public_deps.add(crate_id, crate_graph);
                     rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index a4e6550984..71566d5de6 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -25,7 +25,7 @@ itertools = "0.10.3"
 scip = "0.1.1"
 lsp-types = { version = "0.93.1", features = ["proposed"] }
 parking_lot = "0.12.1"
-xflags = "0.3.0"
+xflags = "0.2.4"
 oorandom = "11.1.3"
 rustc-hash = "1.1.0"
 serde = { version = "1.0.137", features = ["derive"] }
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index eabfcf1944..f6a6802972 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -37,15 +37,16 @@ fn main() {
         process::exit(code);
     }
 
-    let flags = flags::RustAnalyzer::from_env_or_exit();
-    if let Err(err) = try_main(flags) {
+    if let Err(err) = try_main() {
         tracing::error!("Unexpected error: {}", err);
         eprintln!("{}", err);
         process::exit(101);
     }
 }
 
-fn try_main(flags: flags::RustAnalyzer) -> Result<()> {
+fn try_main() -> Result<()> {
+    let flags = flags::RustAnalyzer::from_env()?;
+
     #[cfg(debug_assertions)]
     if flags.wait_dbg || env::var("RA_WAIT_DBG").is_ok() {
         #[allow(unused_mut)]
@@ -75,6 +76,10 @@ fn try_main(flags: flags::RustAnalyzer) -> Result<()> {
                 println!("rust-analyzer {}", rust_analyzer::version());
                 return Ok(());
             }
+            if cmd.help {
+                println!("{}", flags::RustAnalyzer::HELP);
+                return Ok(());
+            }
             with_extra_thread("LspServer", run_server)?;
         }
         flags::RustAnalyzerCmd::ProcMacro(flags::ProcMacro) => {
diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs
index 5bcc97e226..aa32654fbd 100644
--- a/crates/rust-analyzer/src/cli/flags.rs
+++ b/crates/rust-analyzer/src/cli/flags.rs
@@ -31,6 +31,8 @@ xflags::xflags! {
         default cmd lsp-server {
             /// Print version.
             optional --version
+            /// Print help.
+            optional -h, --help
 
             /// Dump a LSP config JSON schema.
             optional --print-config-schema
@@ -52,10 +54,10 @@ xflags::xflags! {
         }
 
         /// Batch typecheck project and print summary statistics
-        cmd analysis-stats {
+        cmd analysis-stats
             /// Directory with Cargo.toml.
             required path: PathBuf
-
+        {
             optional --output format: OutputFormat
 
             /// Randomize order in which crates, modules, and items are processed.
@@ -82,37 +84,38 @@ xflags::xflags! {
             optional --skip-inference
         }
 
-        cmd diagnostics {
+        cmd diagnostics
             /// Directory with Cargo.toml.
             required path: PathBuf
-
+        {
             /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis.
             optional --disable-build-scripts
             /// Don't use expand proc macros.
             optional --disable-proc-macros
         }
 
-        cmd ssr {
+        cmd ssr
             /// A structured search replace rule (`$a.foo($b) ==> bar($a, $b)`)
             repeated rule: SsrRule
-        }
+        {}
 
-        cmd search {
+        cmd search
             /// A structured search replace pattern (`$a.foo($b)`)
             repeated pattern: SsrPattern
+        {
             /// Prints debug information for any nodes with source exactly equal to snippet.
             optional --debug snippet: String
         }
 
         cmd proc-macro {}
 
-        cmd lsif {
+        cmd lsif
             required path: PathBuf
-        }
+        {}
 
-        cmd scip {
+        cmd scip
             required path: PathBuf
-        }
+        {}
     }
 }
 
@@ -147,6 +150,7 @@ pub enum RustAnalyzerCmd {
 #[derive(Debug)]
 pub struct LspServer {
     pub version: bool,
+    pub help: bool,
     pub print_config_schema: bool,
 }
 
@@ -214,10 +218,7 @@ pub struct Scip {
 }
 
 impl RustAnalyzer {
-    #[allow(dead_code)]
-    pub fn from_env_or_exit() -> Self {
-        Self::from_env_or_exit_()
-    }
+    pub const HELP: &'static str = Self::HELP_;
 
     #[allow(dead_code)]
     pub fn from_env() -> xflags::Result<Self> {
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 229e7419b7..eadebbe8a2 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -235,24 +235,6 @@ impl ast::GenericParamList {
             }
         }
     }
-
-    /// Constructs a matching [`ast::GenericArgList`]
-    pub fn to_generic_args(&self) -> ast::GenericArgList {
-        let args = self.generic_params().filter_map(|param| match param {
-            ast::GenericParam::LifetimeParam(it) => {
-                Some(ast::GenericArg::LifetimeArg(make::lifetime_arg(it.lifetime()?)))
-            }
-            ast::GenericParam::TypeParam(it) => {
-                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
-            }
-            ast::GenericParam::ConstParam(it) => {
-                // Name-only const params get parsed as `TypeArg`s
-                Some(ast::GenericArg::TypeArg(make::type_arg(make::ext::ty_name(it.name()?))))
-            }
-        });
-
-        make::generic_arg_list(args)
-    }
 }
 
 impl ast::WhereClause {
@@ -266,42 +248,6 @@ impl ast::WhereClause {
     }
 }
 
-impl ast::TypeParam {
-    pub fn remove_default(&self) {
-        if let Some((eq, last)) = self
-            .syntax()
-            .children_with_tokens()
-            .find(|it| it.kind() == T![=])
-            .zip(self.syntax().last_child_or_token())
-        {
-            ted::remove_all(eq..=last);
-
-            // remove any trailing ws
-            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
-                last.detach();
-            }
-        }
-    }
-}
-
-impl ast::ConstParam {
-    pub fn remove_default(&self) {
-        if let Some((eq, last)) = self
-            .syntax()
-            .children_with_tokens()
-            .find(|it| it.kind() == T![=])
-            .zip(self.syntax().last_child_or_token())
-        {
-            ted::remove_all(eq..=last);
-
-            // remove any trailing ws
-            if let Some(last) = self.syntax().last_token().filter(|it| it.kind() == WHITESPACE) {
-                last.detach();
-            }
-        }
-    }
-}
-
 pub trait Removable: AstNode {
     fn remove(&self);
 }
@@ -318,7 +264,7 @@ impl Removable for ast::TypeBoundList {
 impl ast::PathSegment {
     pub fn get_or_create_generic_arg_list(&self) -> ast::GenericArgList {
         if self.generic_arg_list().is_none() {
-            let arg_list = make::generic_arg_list(empty()).clone_for_update();
+            let arg_list = make::generic_arg_list().clone_for_update();
             ted::append_child(self.syntax(), arg_list.syntax());
         }
         self.generic_arg_list().unwrap()
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index c9a21e12c0..83f8bbac58 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -88,9 +88,6 @@ pub mod ext {
         block_expr(None, None)
     }
 
-    pub fn ty_name(name: ast::Name) -> ast::Type {
-        ty_path(ident_path(&format!("{name}")))
-    }
     pub fn ty_bool() -> ast::Type {
         ty_path(ident_path("bool"))
     }
@@ -163,7 +160,6 @@ pub fn assoc_item_list() -> ast::AssocItemList {
     ast_from_text("impl C for D {}")
 }
 
-// FIXME: `ty_params` should be `ast::GenericArgList`
 pub fn impl_(
     ty: ast::Path,
     params: Option<ast::GenericParamList>,
@@ -189,6 +185,10 @@ pub fn impl_trait(
     ast_from_text(&format!("impl{ty_params} {trait_} for {ty}{ty_params} {{}}"))
 }
 
+pub(crate) fn generic_arg_list() -> ast::GenericArgList {
+    ast_from_text("const S: T<> = ();")
+}
+
 pub fn path_segment(name_ref: ast::NameRef) -> ast::PathSegment {
     ast_from_text(&format!("type __ = {name_ref};"))
 }
@@ -718,21 +718,6 @@ pub fn generic_param_list(
     ast_from_text(&format!("fn f<{args}>() {{ }}"))
 }
 
-pub fn type_arg(ty: ast::Type) -> ast::TypeArg {
-    ast_from_text(&format!("const S: T<{ty}> = ();"))
-}
-
-pub fn lifetime_arg(lifetime: ast::Lifetime) -> ast::LifetimeArg {
-    ast_from_text(&format!("const S: T<{lifetime}> = ();"))
-}
-
-pub(crate) fn generic_arg_list(
-    args: impl IntoIterator<Item = ast::GenericArg>,
-) -> ast::GenericArgList {
-    let args = args.into_iter().join(", ");
-    ast_from_text(&format!("const S: T<{args}> = ();"))
-}
-
 pub fn visibility_pub_crate() -> ast::Visibility {
     ast_from_text("pub(crate) struct S")
 }
diff --git a/editors/code/package.json b/editors/code/package.json
index ccf62d002b..f1dd3aa79f 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1301,15 +1301,6 @@
                     "endsPattern": "^\\[Finished running\\b"
                 },
                 "pattern": "$rustc"
-            },
-            {
-                "name": "rustc-run",
-                "base": "$rustc",
-                "fileLocation": [
-                    "autoDetect",
-                    "${command:rust-analyzer.cargoWorkspaceRootForCurrentRun}"
-                ],
-                "pattern": "$rustc-run"
             }
         ],
         "colors": [
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 6b10073aa8..b9ad525e36 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -842,7 +842,6 @@ export function run(ctx: Ctx): Cmd {
         item.detail = "rerun";
         prevRunnable = item;
         const task = await createTask(item.runnable, ctx.config);
-        ctx.cargoWorkspaceRootForCurrentRun = item.cargoWorkspaceRoot;
         return await vscode.tasks.executeTask(task);
     };
 }
@@ -947,6 +946,3 @@ export function linkToCommand(ctx: Ctx): Cmd {
         }
     };
 }
-export function getCargoWorkspaceDir(ctx: Ctx): Cmd {
-    return async () => ctx.cargoWorkspaceRootForCurrentRun;
-}
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index b6c0eedfb1..26510011d4 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -17,10 +17,6 @@ export type Workspace =
       };
 
 export class Ctx {
-    // Helps VS Code to correctly link problems from runnables. This is used by
-    // `rust-analyzer.cargoWorkspaceRootForCurrentRun` command of $rustc-run problem matcher.
-    cargoWorkspaceRootForCurrentRun?: string = undefined;
-
     private constructor(
         readonly config: Config,
         private readonly extCtx: vscode.ExtensionContext,
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 6e6c2513dd..41bde4195e 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -189,7 +189,6 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
     ctx.registerCommand("resolveCodeAction", commands.resolveCodeAction);
     ctx.registerCommand("applyActionGroup", commands.applyActionGroup);
     ctx.registerCommand("gotoLocation", commands.gotoLocation);
-    ctx.registerCommand("cargoWorkspaceRootForCurrentRun", commands.getCargoWorkspaceDir);
 
     ctx.registerCommand("linkToCommand", commands.linkToCommand);
 }
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 100c0fe2d8..22e5eda682 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -89,14 +89,12 @@ export async function selectRunnable(
 
 export class RunnableQuickPick implements vscode.QuickPickItem {
     public label: string;
-    public cargoWorkspaceRoot?: string;
     public description?: string | undefined;
     public detail?: string | undefined;
     public picked?: boolean | undefined;
 
     constructor(public runnable: ra.Runnable) {
         this.label = runnable.label;
-        this.cargoWorkspaceRoot = runnable.args.workspaceRoot;
     }
 }
 
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index 44697f95ba..e6239deeb2 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -128,7 +128,7 @@ export async function buildCargoTask(
         name,
         TASK_SOURCE,
         exec,
-        ["$rustc-run"]
+        ["$rustc"]
     );
 }
 
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 14816912b7..95d44e9b9d 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -11,5 +11,5 @@ anyhow = "1.0.57"
 flate2 = "1.0.24"
 write-json = "0.1.2"
 xshell = "0.2.2"
-xflags = "0.3.0"
+xflags = "0.2.4"
 # Avoid adding more dependencies to this crate
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs
index 0fce488983..993c64ccea 100644
--- a/xtask/src/flags.rs
+++ b/xtask/src/flags.rs
@@ -7,6 +7,10 @@ xflags::xflags! {
 
     /// Run custom build command.
     cmd xtask {
+        default cmd help {
+            /// Print help information.
+            optional -h, --help
+        }
 
         /// Install rust-analyzer server or editor plugin.
         cmd install {
@@ -38,9 +42,9 @@ xflags::xflags! {
             optional --dry-run
         }
         /// Builds a benchmark version of rust-analyzer and puts it into `./target`.
-        cmd bb {
+        cmd bb
             required suffix: String
-        }
+        {}
     }
 }
 
@@ -54,6 +58,7 @@ pub struct Xtask {
 
 #[derive(Debug)]
 pub enum XtaskCmd {
+    Help(Help),
     Install(Install),
     FuzzTests(FuzzTests),
     Release(Release),
@@ -63,6 +68,11 @@ pub enum XtaskCmd {
     Bb(Bb),
 }
 
+#[derive(Debug)]
+pub struct Help {
+    pub help: bool,
+}
+
 #[derive(Debug)]
 pub struct Install {
     pub client: bool,
@@ -101,10 +111,7 @@ pub struct Bb {
 }
 
 impl Xtask {
-    #[allow(dead_code)]
-    pub fn from_env_or_exit() -> Self {
-        Self::from_env_or_exit_()
-    }
+    pub const HELP: &'static str = Self::HELP_;
 
     #[allow(dead_code)]
     pub fn from_env() -> xflags::Result<Self> {
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index a37f469adc..335ac324a5 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -25,12 +25,15 @@ use std::{
 use xshell::{cmd, Shell};
 
 fn main() -> anyhow::Result<()> {
-    let flags = flags::Xtask::from_env_or_exit();
-
     let sh = &Shell::new()?;
     sh.change_dir(project_root());
 
+    let flags = flags::Xtask::from_env()?;
     match flags.subcommand {
+        flags::XtaskCmd::Help(_) => {
+            println!("{}", flags::Xtask::HELP);
+            Ok(())
+        }
         flags::XtaskCmd::Install(cmd) => cmd.run(sh),
         flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
         flags::XtaskCmd::Release(cmd) => cmd.run(sh),


Test patch:
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 4f626105a5..c04cd16519 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -93,12 +93,12 @@ macro_rules! option_env {() => {}}
 
 fn main() { option_env!("TEST_ENV_VAR"); }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! option_env {() => {}}
 
-fn main() { std::option::Option::None:: < &str>; }
-"##]],
+fn main() { $crate::option::Option::None:: < &str>; }
+"#]],
     );
 }
 
@@ -191,7 +191,7 @@ fn main() {
     format_args!("{} {:?}", arg1(a, b, c), arg2);
 }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! format_args {
     ($fmt:expr) => ({ /* compiler built-in */ });
@@ -199,9 +199,9 @@ macro_rules! format_args {
 }
 
 fn main() {
-    std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(arg1(a, b, c)), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(arg2), std::fmt::Display::fmt), ]);
+    $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]);
 }
-"##]],
+"#]],
     );
 }
 
@@ -219,7 +219,7 @@ fn main() {
     format_args!("{} {:?}", a::<A,B>(), b);
 }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! format_args {
     ($fmt:expr) => ({ /* compiler built-in */ });
@@ -227,9 +227,9 @@ macro_rules! format_args {
 }
 
 fn main() {
-    std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A, B>()), std::fmt::Display::fmt), std::fmt::ArgumentV1::new(&(b), std::fmt::Display::fmt), ]);
+    $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]);
 }
-"##]],
+"#]],
     );
 }
 
@@ -248,7 +248,7 @@ fn main() {
         format_args!/*+errors*/("{} {:?}", a.);
 }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[rustc_builtin_macro]
 macro_rules! format_args {
     ($fmt:expr) => ({ /* compiler built-in */ });
@@ -258,9 +258,9 @@ macro_rules! format_args {
 fn main() {
     let _ =
         /* parse error: expected field name or number */
-std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a.), std::fmt::Display::fmt), ]);
+$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]);
 }
-"##]],
+"#]],
     );
 }
 
diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs
index a155adcec6..47cc3341e7 100644
--- a/crates/hir-ty/src/tests/regression.rs
+++ b/crates/hir-ty/src/tests/regression.rs
@@ -1488,6 +1488,7 @@ fn regression_11688_4() {
 
 #[test]
 fn gat_crash_1() {
+    cov_mark::check!(ignore_gats);
     check_no_mismatches(
         r#"
 trait ATrait {}
@@ -1526,22 +1527,30 @@ unsafe impl Storage for InlineStorage {
 
 #[test]
 fn gat_crash_3() {
-    check_no_mismatches(
-        r#"
+    // FIXME: This test currently crashes rust analyzer in a debug build but not in a
+    // release build (i.e. for the user). With the assumption that tests will always be run
+    // in debug mode, we catch the unwind and expect that it panicked. See the
+    // [`crate::utils::generics`] function for more information.
+    cov_mark::check!(ignore_gats);
+    std::panic::catch_unwind(|| {
+        check_no_mismatches(
+            r#"
 trait Collection {
-type Item;
-type Member<T>: Collection<Item = T>;
-fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
+    type Item;
+    type Member<T>: Collection<Item = T>;
+    fn add(&mut self, value: Self::Item) -> Result<(), Self::Error>;
 }
 struct ConstGen<T, const N: usize> {
-data: [T; N],
+    data: [T; N],
 }
 impl<T, const N: usize> Collection for ConstGen<T, N> {
-type Item = T;
-type Member<U> = ConstGen<U, N>;
+    type Item = T;
+    type Member<U> = ConstGen<U, N>;
 }
-    "#,
-    );
+        "#,
+        );
+    })
+    .expect_err("must panic");
 }
 
 #[test]
@@ -1694,16 +1703,3 @@ fn foo(a: &dyn DoesNotExist) {
         "#,
     );
 }
-
-#[test]
-fn self_assoc_with_const_generics_crash() {
-    check_no_mismatches(
-        r#"
-trait Trait { type Item; }
-impl<T, const N: usize> Trait for [T; N] {
-    type Item = ();
-    fn f<U>(_: Self::Item) {}
-}
-        "#,
-    );
-}
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index f7f2417d07..a3bb66e379 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -232,7 +232,6 @@ fn assist_order_field_struct() {
     assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
     assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
     assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
-    assert_eq!(assists.next().expect("expected assist").label, "Convert to tuple struct");
     assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
 }
 
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 2c4000efe0..d403f86c6d 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -407,47 +407,6 @@ fn main() {
     )
 }
 
-#[test]
-fn doctest_convert_named_struct_to_tuple_struct() {
-    check_doc_test(
-        "convert_named_struct_to_tuple_struct",
-        r#####"
-struct Point$0 { x: f32, y: f32 }
-
-impl Point {
-    pub fn new(x: f32, y: f32) -> Self {
-        Point { x, y }
-    }
-
-    pub fn x(&self) -> f32 {
-        self.x
-    }
-
-    pub fn y(&self) -> f32 {
-        self.y
-    }
-}
-"#####,
-        r#####"
-struct Point(f32, f32);
-
-impl Point {
-    pub fn new(x: f32, y: f32) -> Self {
-        Point(x, y)
-    }
-
-    pub fn x(&self) -> f32 {
-        self.0
-    }
-
-    pub fn y(&self) -> f32 {
-        self.1
-    }
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_convert_to_guarded_return() {
     check_doc_test(