Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
346 changes: 316 additions & 30 deletions compiler/rustc_const_eval/src/const_eval/type_info.rs

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ symbols! {
CoercePointeeValidated,
CoerceUnsized,
Command,
Const,
ConstParamTy,
ConstParamTy_,
Context,
Expand All @@ -233,6 +234,7 @@ symbols! {
Duration,
Encodable,
Encoder,
Enum,
Enumerate,
Eq,
Equal,
Expand Down Expand Up @@ -290,6 +292,7 @@ symbols! {
IteratorMap,
Layout,
Left,
Lifetime,
LinkedList,
LintDiagnostic,
LintPass,
Expand Down Expand Up @@ -369,6 +372,7 @@ symbols! {
Stdin,
Str,
String,
Struct,
StructuralPartialEq,
SubdiagMessage,
Subdiagnostic,
Expand All @@ -392,6 +396,7 @@ symbols! {
Ty,
TyCtxt,
TyKind,
Type,
Unknown,
Unsize,
UnsizedConstParamTy,
Expand Down Expand Up @@ -1080,6 +1085,7 @@ symbols! {
ffi_returns_twice,
field,
field_init_shorthand,
fields,
file,
file_options,
flags,
Expand Down Expand Up @@ -1168,6 +1174,7 @@ symbols! {
generic_const_parameter_types,
generic_param_attrs,
generic_pattern_types,
generics,
get_context,
global_alloc_ty,
global_allocator,
Expand Down Expand Up @@ -2463,6 +2470,7 @@ symbols! {
values,
var,
variant_count,
variants,
vec,
vec_as_mut_slice,
vec_as_slice,
Expand Down
84 changes: 84 additions & 0 deletions library/core/src/mem/type_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ pub enum TypeKind {
Tuple(Tuple),
/// Arrays.
Array(Array),
/// Structs.
Struct(Struct),
/// Enums.
Enum(Enum),
/// Primitive boolean type.
Bool(Bool),
/// Primitive character type.
Expand Down Expand Up @@ -75,6 +79,8 @@ pub struct Tuple {
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Field {
/// The name of the field.
pub name: &'static str,
/// The field's type.
pub ty: TypeId,
/// Offset in bytes from the parent type
Expand All @@ -92,6 +98,84 @@ pub struct Array {
pub len: usize,
}

/// Compile-time type information about arrays.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Struct {
/// Instantiated generics of the struct.
pub generics: &'static [Generic],
/// All fields of the struct.
pub fields: &'static [Field],
/// Whether the struct field list is non-exhaustive.
pub non_exhaustive: bool,
}

/// Compile-time type information about enums.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Enum {
/// Instantiated generics of the enum.
pub generics: &'static [Generic],
/// All variants of the enum.
pub variants: &'static [Variant],
/// Whether the enum variant list is non-exhaustive.
pub non_exhaustive: bool,
}

/// Compile-time type information about variants of enums.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Variant {
/// The name of the variant.
pub name: &'static str,
/// All fields of the variant.
pub fields: &'static [Field],
/// Whether the enum variant fields is non-exhaustive.
pub non_exhaustive: bool,
}

/// Compile-time type information about instantiated generics of structs, enum and union variants.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub enum Generic {
/// Lifetimes.
Lifetime(Lifetime),
/// Types.
Type(GenericType),
/// Const parameters.
Const(Const),
}

/// Compile-time type information about generic lifetimes.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Lifetime {
// No additional information to provide for now.
}

/// Compile-time type information about instantiated generic types.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct GenericType {
/// The const's type.
pub ty: TypeId,
}

/// Compile-time type information about generic const parameters.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct Const {
/// The const's type.
pub ty: TypeId,
}

/// Compile-time type information about `bool`.
#[derive(Debug)]
#[non_exhaustive]
Expand Down
105 changes: 104 additions & 1 deletion library/coretests/tests/mem/type_info.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#![allow(dead_code)]

use std::any::{Any, TypeId};
use std::mem::type_info::{Type, TypeKind};
use std::mem::type_info::{Const, Generic, GenericType, Type, TypeKind};

#[test]
fn test_arrays() {
Expand Down Expand Up @@ -58,6 +60,107 @@ fn test_tuples() {
}
}

#[test]
fn test_structs() {
use TypeKind::*;

const {
struct TestStruct {
first: u8,
second: u16,
}

let Type { kind: Struct(ty), size, .. } = Type::of::<TestStruct>() else { panic!() };
assert!(size == Some(size_of::<TestStruct>()));
assert!(!ty.non_exhaustive);
assert!(ty.fields.len() == 2);
assert!(ty.fields[0].name == "first");
assert!(ty.fields[1].name == "second");
}

const {
#[non_exhaustive]
struct NonExhaustive {
a: u8,
}

let Type { kind: Struct(ty), .. } = Type::of::<NonExhaustive>() else { panic!() };
assert!(ty.non_exhaustive);
}

const {
struct TupleStruct(u8, u16);

let Type { kind: Struct(ty), .. } = Type::of::<TupleStruct>() else { panic!() };
assert!(ty.fields.len() == 2);
assert!(ty.fields[0].name == "0");
assert!(ty.fields[0].ty == TypeId::of::<u8>());
assert!(ty.fields[1].name == "1");
assert!(ty.fields[1].ty == TypeId::of::<u16>());
}

const {
struct Generics<'a, T, const C: u64> {
a: T,
z: &'a (), // FIXME(type_info): offset of this field is dumped as 0, which may not be correct
}

let Type { kind: Struct(ty), .. } = Type::of::<Generics<'static, i32, 1_u64>>() else {
panic!()
};
assert!(ty.fields.len() == 2);
assert!(ty.generics.len() == 3);

let Generic::Lifetime(_) = ty.generics[0] else { panic!() };
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[1] else { panic!() };
assert!(generic_ty == TypeId::of::<i32>());
let Generic::Const(Const { ty: const_ty, .. }) = ty.generics[2] else { panic!() };
assert!(const_ty == TypeId::of::<u64>());
}
}

#[test]
fn test_enums() {
use TypeKind::*;

const {
enum E {
Some(u32),
None,
#[non_exhaustive]
Foomp {
a: (),
b: &'static str,
},
}

let Type { kind: Enum(ty), size, .. } = Type::of::<E>() else { panic!() };
assert!(size == Some(size_of::<E>()));
assert!(ty.variants.len() == 3);

assert!(ty.variants[0].name == "Some");
assert!(!ty.variants[0].non_exhaustive);
assert!(ty.variants[0].fields.len() == 1);

assert!(ty.variants[1].name == "None");
assert!(!ty.variants[1].non_exhaustive);
assert!(ty.variants[1].fields.len() == 0);

assert!(ty.variants[2].name == "Foomp");
assert!(ty.variants[2].non_exhaustive);
assert!(ty.variants[2].fields.len() == 2);
}

const {
let Type { kind: Enum(ty), size, .. } = Type::of::<Option<i32>>() else { panic!() };
assert!(size == Some(size_of::<Option<i32>>()));
assert!(ty.variants.len() == 2);
assert!(ty.generics.len() == 1);
let Generic::Type(GenericType { ty: generic_ty, .. }) = ty.generics[0] else { panic!() };
assert!(generic_ty == TypeId::of::<i32>());
}
}

#[test]
fn test_primitives() {
use TypeKind::*;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/generics/wrong-number-of-args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ mod r#trait {
//~| HELP remove

type D = Box<dyn GenericType>;
//~^ ERROR missing generics for trait `GenericType`
//~^ ERROR missing generics for trait `r#trait::GenericType`
//~| HELP add missing

type E = Box<dyn GenericType<String, usize>>;
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/generics/wrong-number-of-args.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ note: trait defined here, with 1 lifetime parameter: `'a`
LL | trait GenericLifetime<'a> {
| ^^^^^^^^^^^^^^^ --

error[E0107]: missing generics for trait `GenericType`
error[E0107]: missing generics for trait `r#trait::GenericType`
--> $DIR/wrong-number-of-args.rs:129:22
|
LL | type D = Box<dyn GenericType>;
Expand Down
8 changes: 4 additions & 4 deletions tests/ui/missing-trait-bounds/issue-69725.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
error[E0599]: the method `clone` exists for struct `Struct<A>`, but its trait bounds were not satisfied
error[E0599]: the method `clone` exists for struct `issue_69725::Struct<A>`, but its trait bounds were not satisfied
--> $DIR/issue-69725.rs:9:32
|
LL | let _ = Struct::<A>::new().clone();
| ^^^^^ method cannot be called on `Struct<A>` due to unsatisfied trait bounds
| ^^^^^ method cannot be called on `issue_69725::Struct<A>` due to unsatisfied trait bounds
|
::: $DIR/auxiliary/issue-69725.rs:2:1
|
LL | pub struct Struct<A>(A);
| -------------------- doesn't satisfy `Struct<A>: Clone`
| -------------------- doesn't satisfy `issue_69725::Struct<A>: Clone`
|
= note: the following trait bounds were not satisfied:
`A: Clone`
which is required by `Struct<A>: Clone`
which is required by `issue_69725::Struct<A>: Clone`
help: consider restricting the type parameter to satisfy the trait bound
|
LL | fn crash<A>() where A: Clone {
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/privacy/issue-79593.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod foo {
Pub {};
//~^ ERROR missing field `private` in initializer of `Pub`
Enum::Variant { x: () };
//~^ ERROR missing field `y` in initializer of `Enum`
//~^ ERROR missing field `y` in initializer of `foo::Enum`
}
}

Expand All @@ -21,9 +21,9 @@ fn correct() {

fn wrong() {
foo::Enum::Variant { x: () };
//~^ ERROR missing field `y` in initializer of `Enum`
//~^ ERROR missing field `y` in initializer of `foo::Enum`
foo::Enum::Variant { };
//~^ ERROR missing fields `x` and `y` in initializer of `Enum`
//~^ ERROR missing fields `x` and `y` in initializer of `foo::Enum`
}

fn main() {}
6 changes: 3 additions & 3 deletions tests/ui/privacy/issue-79593.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0063]: missing field `private` in initializer of `Pub`
LL | Pub {};
| ^^^ missing `private`

error[E0063]: missing field `y` in initializer of `Enum`
error[E0063]: missing field `y` in initializer of `foo::Enum`
--> $DIR/issue-79593.rs:12:9
|
LL | Enum::Variant { x: () };
Expand All @@ -18,13 +18,13 @@ LL | foo::Pub {};
|
= note: private field `private` that was not provided

error[E0063]: missing field `y` in initializer of `Enum`
error[E0063]: missing field `y` in initializer of `foo::Enum`
--> $DIR/issue-79593.rs:23:5
|
LL | foo::Enum::Variant { x: () };
| ^^^^^^^^^^^^^^^^^^ missing `y`

error[E0063]: missing fields `x` and `y` in initializer of `Enum`
error[E0063]: missing fields `x` and `y` in initializer of `foo::Enum`
--> $DIR/issue-79593.rs:25:5
|
LL | foo::Enum::Variant { };
Expand Down
Loading