Repository: rust-lang/rust-analyzer
Pull request #17002 (2024-04-03 07:02:07)

internal: Consider ADT generic parameter defaults for unsubstituted layout calculations
For one, this brings back layout information for lifetime generic ADTs (which "regressed" when we started adding lifetimes to chalks-ir), but it also allows layout calculation to work for definitions that don't actually use the generics (where its only used in a `PhantomData` for example)


Patch:
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index cb118a3684..41acd3555e 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -74,6 +74,10 @@ impl<D> TyBuilder<D> {
         (self.data, subst)
     }
 
+    pub fn build_into_subst(self) -> Substitution {
+        self.build_internal().1
+    }
+
     pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
         assert!(self.remaining() > 0);
         let arg = arg.cast(Interner);
@@ -291,7 +295,6 @@ impl TyBuilder<hir_def::AdtId> {
     ) -> 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) {
@@ -301,13 +304,16 @@ impl TyBuilder<hir_def::AdtId> {
                 }
             }
             // 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()))
+                    .chain(self.param_kinds[self.vec.len()..].iter().map(|it| match it {
+                        ParamKind::Type => TyKind::Error.intern(Interner).cast(Interner),
+                        ParamKind::Lifetime => error_lifetime().cast(Interner),
+                        ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
+                    }))
                     .take(self.param_kinds.len()),
             );
             self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d1735e9f1d..503c549327 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1418,16 +1418,14 @@ impl Adt {
     }
 
     pub fn layout(self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
-        if !db.generic_params(self.into()).is_empty() {
-            return Err(LayoutError::HasPlaceholder);
-        }
-        let krate = self.krate(db).id;
         db.layout_of_adt(
             self.into(),
-            Substitution::empty(Interner),
+            TyBuilder::adt(db, self.into())
+                .fill_with_defaults(db, || TyKind::Error.intern(Interner))
+                .build_into_subst(),
             db.trait_environment(self.into()),
         )
-        .map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
+        .map(|layout| Layout(layout, db.target_data_layout(self.krate(db).id).unwrap()))
     }
 
     /// Turns this ADT into a type. Any type parameters of the ADT will be
diff --git a/crates/proc-macro-api/src/lib.rs b/crates/proc-macro-api/src/lib.rs
index fd49164464..3c0c904bab 100644
--- a/crates/proc-macro-api/src/lib.rs
+++ b/crates/proc-macro-api/src/lib.rs
@@ -37,7 +37,7 @@ pub enum ProcMacroKind {
     CustomDerive,
     Attr,
     // This used to be called FuncLike, so that's what the server expects currently.
-    #[serde(alias = "bang")]
+    #[serde(alias = "Bang")]
     #[serde(rename(serialize = "FuncLike", deserialize = "FuncLike"))]
     Bang,
 }


Test patch:
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index d1721f1191..754fb2eccd 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -2322,6 +2322,49 @@ fn test_hover_layout_of_variant() {
     );
 }
 
+#[test]
+fn test_hover_layout_of_variant_generic() {
+    check(
+        r#"enum Option<T> {
+    Some(T),
+    None$0
+}"#,
+        expect![[r#"
+            *None*
+
+            ```rust
+            test::Option
+            ```
+
+            ```rust
+            None
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn test_hover_layout_generic_unused() {
+    check(
+        r#"
+//- minicore: phantom_data
+struct S$0<T>(core::marker::PhantomData<T>);
+"#,
+        expect![[r#"
+            *S*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            struct S<T>(PhantomData<T>)
+            ```
+        "#]],
+    );
+}
+
 #[test]
 fn test_hover_layout_of_enum() {
     check(
@@ -3673,6 +3716,7 @@ struct S$0T<const C: usize = 1, T = Foo>(T);
             ```
 
             ```rust
+            // size = 0, align = 1
             struct ST<const C: usize = 1, T = Foo>(T)
             ```
         "#]],
@@ -3694,6 +3738,7 @@ struct S$0T<const C: usize = {40 + 2}, T = Foo>(T);
             ```
 
             ```rust
+            // size = 0, align = 1
             struct ST<const C: usize = {const}, T = Foo>(T)
             ```
         "#]],
@@ -3716,6 +3761,7 @@ struct S$0T<const C: usize = VAL, T = Foo>(T);
             ```
 
             ```rust
+            // size = 0, align = 1
             struct ST<const C: usize = VAL, T = Foo>(T)
             ```
         "#]],
@@ -7872,6 +7918,7 @@ struct Pedro$0<'a> {
             ```
 
             ```rust
+            // size = 16 (0x10), align = 8, niches = 1
             struct Pedro<'a>
             ```
         "#]],