about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs99
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs114
3 files changed, 120 insertions, 124 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 1d880c9eeeb..ebaaef66db6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -249,13 +249,62 @@ impl GenericParams {
         self.lifetimes.iter()
     }
 
+    pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
+        self.type_or_consts.iter().find_map(|(id, p)| {
+            if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
+                Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
+            } else {
+                None
+            }
+        })
+    }
+
+    pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
+        self.type_or_consts.iter().find_map(|(id, p)| {
+            if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
+                Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
+            } else {
+                None
+            }
+        })
+    }
+
+    #[inline]
+    pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
+        if self.type_or_consts.is_empty() {
+            return None;
+        }
+        matches!(
+            self.type_or_consts[SELF_PARAM_ID_IN_SELF],
+            TypeOrConstParamData::TypeParamData(TypeParamData {
+                provenance: TypeParamProvenance::TraitSelf,
+                ..
+            })
+        )
+        .then(|| SELF_PARAM_ID_IN_SELF)
+    }
+
+    pub fn find_lifetime_by_name(
+        &self,
+        name: &Name,
+        parent: GenericDefId,
+    ) -> Option<LifetimeParamId> {
+        self.lifetimes.iter().find_map(|(id, p)| {
+            if &p.name == name {
+                Some(LifetimeParamId { local_id: id, parent })
+            } else {
+                None
+            }
+        })
+    }
+
     pub(crate) fn generic_params_query(
         db: &dyn DefDatabase,
         def: GenericDefId,
     ) -> Interned<GenericParams> {
         let _p = tracing::info_span!("generic_params_query").entered();
 
-        let krate = def.module(db).krate;
+        let krate = def.krate(db);
         let cfg_options = db.crate_graph();
         let cfg_options = &cfg_options[krate].cfg_options;
 
@@ -368,54 +417,6 @@ impl GenericParams {
             }),
         }
     }
-
-    pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
-        self.type_or_consts.iter().find_map(|(id, p)| {
-            if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
-                Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
-            } else {
-                None
-            }
-        })
-    }
-
-    pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
-        self.type_or_consts.iter().find_map(|(id, p)| {
-            if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
-                Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
-            } else {
-                None
-            }
-        })
-    }
-
-    pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
-        if self.type_or_consts.is_empty() {
-            return None;
-        }
-        matches!(
-            self.type_or_consts[SELF_PARAM_ID_IN_SELF],
-            TypeOrConstParamData::TypeParamData(TypeParamData {
-                provenance: TypeParamProvenance::TraitSelf,
-                ..
-            })
-        )
-        .then(|| SELF_PARAM_ID_IN_SELF)
-    }
-
-    pub fn find_lifetime_by_name(
-        &self,
-        name: &Name,
-        parent: GenericDefId,
-    ) -> Option<LifetimeParamId> {
-        self.lifetimes.iter().find_map(|(id, p)| {
-            if &p.name == name {
-                Some(LifetimeParamId { local_id: id, parent })
-            } else {
-                None
-            }
-        })
-    }
 }
 
 #[derive(Clone, Default)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index 7fc60c41d70..a96c101a388 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -2,8 +2,8 @@
 //!
 //! The layout for generics as expected by chalk are as follows:
 //! - Optional Self parameter
-//! - Type or Const parameters
 //! - Lifetime parameters
+//! - Type or Const parameters
 //! - Parent parameters
 //!
 //! where parent follows the same scheme.
@@ -20,19 +20,23 @@ use hir_def::{
     LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
 use intern::Interned;
+use itertools::chain;
 use stdx::TupleExt;
 
 use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution};
 
 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)));
-    Generics { def, params: db.generic_params(def), parent_generics }
+    let params = db.generic_params(def);
+    let has_trait_self_param = params.trait_self_param().is_some();
+    Generics { def, params, parent_generics, has_trait_self_param }
 }
 #[derive(Clone, Debug)]
 pub(crate) struct Generics {
     def: GenericDefId,
     params: Interned<GenericParams>,
     parent_generics: Option<Box<Generics>>,
+    has_trait_self_param: bool,
 }
 
 impl<T> ops::Index<T> for Generics
@@ -74,10 +78,6 @@ impl Generics {
         self.params.iter_type_or_consts().map(from_toc_id(self)).map(TupleExt::head)
     }
 
-    pub(crate) fn iter_self_lt_id(&self) -> impl DoubleEndedIterator<Item = GenericParamId> + '_ {
-        self.params.iter_lt().map(from_lt_id(self)).map(TupleExt::head)
-    }
-
     /// Iterate over the params followed by the parent params.
     pub(crate) fn iter(
         &self,
@@ -89,10 +89,9 @@ impl Generics {
     pub(crate) fn iter_self(
         &self,
     ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
-        self.params
-            .iter_type_or_consts()
-            .map(from_toc_id(self))
-            .chain(self.params.iter_lt().map(from_lt_id(self)))
+        let mut toc = self.params.iter_type_or_consts().map(from_toc_id(self));
+        let trait_self_param = self.has_trait_self_param.then(|| toc.next()).flatten();
+        chain!(trait_self_param, self.params.iter_lt().map(from_lt_id(self)), toc)
     }
 
     /// Iterator over types and const params of parent.
@@ -100,8 +99,9 @@ impl Generics {
         &self,
     ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
         self.parent_generics().into_iter().flat_map(|it| {
-            let lt_iter = it.params.iter_lt().map(from_lt_id(it));
-            it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter)
+            let mut toc = it.params.iter_type_or_consts().map(from_toc_id(it));
+            let trait_self_param = it.has_trait_self_param.then(|| toc.next()).flatten();
+            chain!(trait_self_param, it.params.iter_lt().map(from_lt_id(it)), toc)
         })
     }
 
@@ -146,7 +146,10 @@ impl Generics {
         if param.parent == self.def {
             let idx = param.local_id.into_raw().into_u32() as usize;
             debug_assert!(idx <= self.params.len_type_or_consts());
-            Some(idx)
+            if self.params.trait_self_param() == Some(param.local_id) {
+                return Some(idx);
+            }
+            Some(self.params.len_lifetimes() + idx)
         } else {
             debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent));
             self.parent_generics()
@@ -164,7 +167,7 @@ impl Generics {
         if lifetime.parent == self.def {
             let idx = lifetime.local_id.into_raw().into_u32() as usize;
             debug_assert!(idx <= self.params.len_lifetimes());
-            Some(self.params.len_type_or_consts() + idx)
+            Some(self.params.trait_self_param().is_some() as usize + idx)
         } else {
             debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent));
             self.parent_generics()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index a6dd41ae20e..d421e72d364 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -384,14 +384,18 @@ impl<'a> TyLoweringContext<'a> {
                             type_params,
                             const_params,
                             _impl_trait_params,
-                            _lifetime_params,
+                            lifetime_params,
                         ) = self
                             .generics()
                             .expect("variable impl trait lowering must be in a generic def")
                             .provenance_split();
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + self_param as usize + type_params + const_params,
+                            idx as usize
+                                + self_param as usize
+                                + type_params
+                                + const_params
+                                + lifetime_params,
                         ))
                         .intern(Interner)
                     }
@@ -816,8 +820,8 @@ impl<'a> TyLoweringContext<'a> {
 
         // Order is
         // - Optional Self parameter
-        // - Type or Const parameters
         // - Lifetime parameters
+        // - Type or Const parameters
         // - Parent parameters
         let def_generics = generics(self.db.upcast(), def);
         let (
@@ -839,7 +843,6 @@ impl<'a> TyLoweringContext<'a> {
 
         let ty_error = || TyKind::Error.intern(Interner).cast(Interner);
         let mut def_toc_iter = def_generics.iter_self_type_or_consts_id();
-        let mut def_lt_iter = def_generics.iter_self_lt_id();
         let fill_self_param = || {
             if self_param {
                 let self_ty = explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(ty_error);
@@ -852,56 +855,56 @@ impl<'a> TyLoweringContext<'a> {
         };
         let mut had_explicit_args = false;
 
-        let mut lifetimes = SmallVec::<[_; 1]>::new();
         if let Some(&GenericArgs { ref args, has_self_type, .. }) = args_and_bindings {
-            if !has_self_type {
-                fill_self_param();
-            }
-            let expected_num = if has_self_type {
-                self_param as usize + type_params + const_params
+            // Fill in the self param first
+            if has_self_type && self_param {
+                had_explicit_args = true;
+                if let Some(id) = def_toc_iter.next() {
+                    assert!(matches!(id, GenericParamId::TypeParamId(_)));
+                    had_explicit_args = true;
+                    if let GenericArg::Type(ty) = &args[0] {
+                        substs.push(self.lower_ty(ty).cast(Interner));
+                    }
+                }
             } else {
-                type_params + const_params
+                fill_self_param()
             };
-            let skip = if has_self_type && !self_param { 1 } else { 0 };
-            // if non-lifetime args are provided, it should be all of them, but we can't rely on that
+
+            // Then fill in the supplied lifetime args, or error lifetimes if there are too few
+            // (default lifetimes aren't a thing)
             for arg in args
                 .iter()
-                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
-                .skip(skip)
-                .take(expected_num)
+                .filter_map(|arg| match arg {
+                    GenericArg::Lifetime(arg) => Some(self.lower_lifetime(arg)),
+                    _ => None,
+                })
+                .chain(iter::repeat(error_lifetime()))
+                .take(lifetime_params)
             {
-                if let Some(id) = def_toc_iter.next() {
-                    had_explicit_args = true;
-                    let arg = generic_arg_to_chalk(
-                        self.db,
-                        id,
-                        arg,
-                        &mut (),
-                        |_, type_ref| self.lower_ty(type_ref),
-                        |_, const_ref, ty| self.lower_const(const_ref, ty),
-                        |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
-                    );
-                    substs.push(arg);
-                }
+                substs.push(arg.cast(Interner));
             }
 
-            for arg in args
+            let skip = if has_self_type { 1 } else { 0 };
+            // Fill in supplied type and const args
+            // Note if non-lifetime args are provided, it should be all of them, but we can't rely on that
+            for (arg, id) in args
                 .iter()
-                .filter(|arg| matches!(arg, GenericArg::Lifetime(_)))
-                .take(lifetime_params)
+                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
+                .skip(skip)
+                .take(type_params + const_params)
+                .zip(def_toc_iter)
             {
-                if let Some(id) = def_lt_iter.next() {
-                    let arg = generic_arg_to_chalk(
-                        self.db,
-                        id,
-                        arg,
-                        &mut (),
-                        |_, type_ref| self.lower_ty(type_ref),
-                        |_, const_ref, ty| self.lower_const(const_ref, ty),
-                        |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
-                    );
-                    lifetimes.push(arg);
-                }
+                had_explicit_args = true;
+                let arg = generic_arg_to_chalk(
+                    self.db,
+                    id,
+                    arg,
+                    &mut (),
+                    |_, type_ref| self.lower_ty(type_ref),
+                    |_, const_ref, ty| self.lower_const(const_ref, ty),
+                    |_, lifetime_ref| self.lower_lifetime(lifetime_ref),
+                );
+                substs.push(arg);
             }
         } else {
             fill_self_param();
@@ -923,16 +926,16 @@ impl<'a> TyLoweringContext<'a> {
             }
             _ => false,
         };
-        if (!infer_args || had_explicit_args) && !is_assoc_ty() {
+        let fill_defaults = (!infer_args || had_explicit_args) && !is_assoc_ty();
+        if fill_defaults {
             let defaults = &*self.db.generic_defaults(def);
             let (item, _parent) = defaults.split_at(item_len);
-            let (toc, lt) = item.split_at(item_len - lifetime_params);
             let parent_from = item_len - substs.len();
 
             let mut rem =
                 def_generics.iter_id().skip(substs.len()).map(param_to_err).collect::<Vec<_>>();
             // Fill in defaults for type/const params
-            for (idx, default_ty) in toc[substs.len()..].iter().enumerate() {
+            for (idx, default_ty) in item[substs.len()..].iter().enumerate() {
                 // each default can depend on the previous parameters
                 let substs_so_far = Substitution::from_iter(
                     Interner,
@@ -940,20 +943,9 @@ impl<'a> TyLoweringContext<'a> {
                 );
                 substs.push(default_ty.clone().substitute(Interner, &substs_so_far));
             }
-            let n_lifetimes = lifetimes.len();
-            // Fill in deferred lifetimes
-            substs.extend(lifetimes);
-            // Fill in defaults for lifetime params
-            for default_ty in &lt[n_lifetimes..] {
-                // these are always errors so skipping is fine
-                substs.push(default_ty.skip_binders().clone());
-            }
-            // Fill in remaining def params and parent params
+            // Fill in remaining parent params
             substs.extend(rem.drain(parent_from..));
         } else {
-            substs.extend(def_toc_iter.map(param_to_err));
-            // Fill in deferred lifetimes
-            substs.extend(lifetimes);
             // Fill in remaining def params and parent params
             substs.extend(def_generics.iter_id().skip(substs.len()).map(param_to_err));
         }
@@ -1725,8 +1717,8 @@ pub(crate) fn generic_predicates_query(
         })
         .collect::<Vec<_>>();
 
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    if !subst.is_empty(Interner) {
+    if generics.len() > 0 {
+        let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
         let explicitly_unsized_tys = ctx.unsized_types.into_inner();
         if let Some(implicitly_sized_predicates) =
             implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)