Consider ADT generic parameter defaults for unsubstituted layout calculations

This commit is contained in:
Lukas Wirth 2024-04-03 08:57:48 +02:00
parent c3b8c2a254
commit 86967032f7
4 changed files with 61 additions and 10 deletions

View file

@ -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));

View file

@ -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

View file

@ -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>
```
"#]],

View file

@ -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,
}