Skip to content

Conversation

@izagawd
Copy link

@izagawd izagawd commented Jan 17, 2026

Tracking issue: #146922

Adds type_info support for trait object types by introducing a DynTrait variant

I can't seem to get it to work correctly with dyn for<'a> Foo<'a>, though it works fine for normal dyn Foo trait objects

r? @oli-obk

@rustbot
Copy link
Collaborator

rustbot commented Jan 17, 2026

The reflection data structures are tied exactly to the implementation
in the compiler. Make sure to also adjust rustc_const_eval/src/const_eval/type_info.rs

cc @oli-obk

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 17, 2026
@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Jan 17, 2026
@rustbot
Copy link
Collaborator

rustbot commented Jan 17, 2026

oli-obk is not on the review rotation at the moment.
They may take a while to respond.

@izagawd izagawd marked this pull request as draft January 17, 2026 09:30
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 17, 2026
@SpriteOvO SpriteOvO added the F-type_info #![feature(type_info)] label Jan 17, 2026
@izagawd

This comment was marked as resolved.

Comment on lines 219 to 307
Type {
kind: DynTrait(
DynTrait {
super_traits: [
TypeId(0xf726af39bcd0090512f636802780d009),
TypeId(0xd3eba1307d3a0b58acd77b80e4532fbf),
],
is_auto: false,
auto_traits: [
TypeId(0x0d5e48167084e668b711d10061f0446a),
],
},
),
size: None,
}
Copy link
Member

@SpriteOvO SpriteOvO Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trait A {}
trait B: A {}
trait C: B {}

The quoted dump is the type info for dyn C + Send. How do we determine whether it has trait C?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't think I fully understand the question. Could you elaborate?

Copy link
Member

@SpriteOvO SpriteOvO Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For clear, I replaced the type ID number with type name in the following examples.

First, TypeId(dyn C) != TypeId(dyn C + Send), then the type info of dyn C + Send is

Type {
    kind: DynTrait(
        DynTrait {
            super_traits: [
                TypeId(B),
                TypeId(A),
            ],
            is_auto: false,
            auto_traits: [
                TypeId(Send),
            ],
        },
    ),
    size: None,
}

For the current PR implementation, if given a dyn C + Send (or type ID of it), we can know there are A, B and Send but no way of knowing C.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not include C in it since C is not a super trait of itself. I am assuming you want a field that represents the TypeId of the trait object itself?

Copy link
Member

@SpriteOvO SpriteOvO Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not exactly, dyn C and dyn C + Send are two different things, so it's not "the trait object itself".

Intuitively, I think DynTrait's layout should probably look something like this. Take dyn C + Send as an example again.

Type {
    kind: DynTrait(
        DynTrait {
            predicates: [ Predicate(Trait(C)), Predicate(Trait(Send)) ]
        },
    ),
    size: None,
}

Predicate {
    trait,
    negative: bool, // Not sure if possible, #144241
}

Trait(C) = Trait {
    supers: [ Trait(B), Trait(A) ],
    is_auto: false,
}

Trait(Send) = Trait {
    supers: [],
    is_auto: true,
}

Trait(B) = ...
Trait(A) = ...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes a lot of sense! I will go with this

@izagawd

This comment was marked as resolved.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@izagawd izagawd marked this pull request as ready for review January 18, 2026 12:42
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 18, 2026
@rustbot

This comment has been minimized.

@rustbot rustbot added the has-merge-commits PR has merge commits, merge with caution. label Jan 18, 2026
@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch from eb13b48 to f782c2f Compare January 18, 2026 12:53
@rustbot

This comment has been minimized.

@rustbot rustbot removed the has-merge-commits PR has merge commits, merge with caution. label Jan 18, 2026
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch from a7df6d9 to b5eecb0 Compare January 18, 2026 20:24
@rustbot

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@izagawd
Copy link
Author

izagawd commented Jan 18, 2026

@oli-obk @SpriteOvO It seems like the tests are failing due to TypeIds for some auto traits being different on different platforms. Do I have permission to change the nature of the tests to assert_eq! rather than stdout?

edit: got permission from @Noratrieb

@SpriteOvO
Copy link
Member

SpriteOvO commented Jan 18, 2026

Assertions about type_info are in library/coretests/tests/mem/type_info.rs, you can add your assert_eq cases to there.

Personally, I'd like to keep the dump. It provides a very clear view of the layout and changes, especially since this feature gate is still in its early development stages. Perhaps we could create a HashMap<TypeId, &'static str> mapping (just in tests/ui/reflection/dump.rs not stdlib) for displaying type names in the dump instead of unreadable numeric IDs. However, this can be done in another PR later.

@Noratrieb
Copy link
Member

TypeIds are not necessarily stable across compiler implementation detail changes so I would prefer to not check their values in. they could be normalized away

@rust-log-analyzer

This comment has been minimized.

@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch from 23c6f84 to ae272ad Compare January 19, 2026 01:16
@rustbot

This comment has been minimized.

@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch 3 times, most recently from 672e50f to 79bbbee Compare January 19, 2026 09:34
@rustbot

This comment has been minimized.

@izagawd
Copy link
Author

izagawd commented Jan 19, 2026

In rustc, associated type constraints are represented as separate projection predicates (e.g. ::Assoc = ...).
In this PR, I’m currently not modeling projections separately from the base trait predicate. they are kept “attached” to the trait entry.

I previously tried splitting them out, but that produced an odd shape where the first predicate became a bare trait object (no assoc constraints). That, in turn, caused it to emit a TypeId for a trait-object form that you likely wouldn’t encounter in normal Rust code

I’m not sure what the intended representation should be here. Should projections be emitted as separate predicates (mirroring rustc), or should they remain attached to the first trait predicate?
or is there a much better way to represent this?

self.write_immediate(imm, slice_place)
}

fn collect_super_traits(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could leave this out entirely and instead have some way to load just the list of super traits

@oli-obk
Copy link
Contributor

oli-obk commented Jan 19, 2026

I previously tried splitting them out, but that produced an odd shape where the first predicate became a bare trait object (no assoc constraints). That, in turn, caused it to emit a TypeId for a trait-object form that you likely wouldn’t encounter in normal Rust code

Ah yea that would be odd.

Nesting the assoc constraints back into their trait predicates makes sense.

I dislike the complexity of computing all the super traits somewhat. Maybe punting on them for now and requiring a separate function in the future could make this already somewhat useful without making the reflection code too complicated

@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch from f112908 to ee32426 Compare January 19, 2026 20:21
@rust-log-analyzer

This comment has been minimized.

@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch from a605d21 to ade493e Compare January 19, 2026 21:03
Copy link
Member

@SpriteOvO SpriteOvO left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For super traits and associated constraints, if you decide not to implement it for now, could you also leave a FIXME(type_info) comment as a note for them?

View changes since this review

Comment on lines +106 to +117
/// Compile-time type information about a dynamic trait.
#[derive(Debug)]
#[non_exhaustive]
#[unstable(feature = "type_info", issue = "146922")]
pub struct DynTraitPredicate {
/// The type of the trait as a dynamic trait type.
pub ty: TypeId,
/// Whether the trait is an auto trait
pub is_auto: bool,
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still prefer to separate Predicate and Trait into two structs, since they are not exactly the same concepts. Although Rust doesn't support !Send or ?Send in dyn predicates for now, but just in case we will add something else to Predicate in the future. Moreover, is_auto doesn't seem quite appropriate for describing predicates.

@oli-obk What do you think of this?

@rust-bors

This comment has been minimized.

@izagawd izagawd force-pushed the comptime-reflection-dyn-trait-variant branch from ade493e to ba614f0 Compare January 20, 2026 02:47
@rustbot
Copy link
Collaborator

rustbot commented Jan 20, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@izagawd
Copy link
Author

izagawd commented Jan 20, 2026

For super traits and associated constraints, if you decide not to implement it for now, could you also leave a FIXME(type_info) comment as a note for them?

View changes since this review

like this?

#[derive(Debug)]
// FIXME(type_info): Add supertraits
pub struct DynTraitPredicate {
    ...
}

Also, we might need to do that for generics as well no?

Comment on lines +104 to +105
/// The predicates of a dynamic trait.
pub predicates: &'static [DynTraitPredicate],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additionally, predicates perhaps should be unordered? (e.g. [Tr, Send] and [Send, Tr] should be equal)

But I'm not sure if const_eval can express an unordered set. Anyway, I just wanted to bring this up, not sure if there's a solution at the moment.

Copy link
Author

@izagawd izagawd Jan 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we keep the const-eval representation as a slice, but wrap it in a newtype (e.g. Unordered(&'static [T])) whose PartialEq, and other similar traits treats it as order-insensitive? That way we don’t need a real “set” in const_eval

@SpriteOvO
Copy link
Member

like this?

#[derive(Debug)]
// FIXME(type_info): Add supertraits
pub struct DynTraitPredicate {
    ...
}

Also, we might need to do that for generics as well no?

Yea. BTW, I'm adding generics info for ADT types in PR #151142. Once your PR is merged, I can also add generics info to traits later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-type_info #![feature(type_info)] S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants