-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
Support trait objects in type info reflection #151239
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Support trait objects in type info reflection #151239
Conversation
|
|
This comment was marked as resolved.
This comment was marked as resolved.
| Type { | ||
| kind: DynTrait( | ||
| DynTrait { | ||
| super_traits: [ | ||
| TypeId(0xf726af39bcd0090512f636802780d009), | ||
| TypeId(0xd3eba1307d3a0b58acd77b80e4532fbf), | ||
| ], | ||
| is_auto: false, | ||
| auto_traits: [ | ||
| TypeId(0x0d5e48167084e668b711d10061f0446a), | ||
| ], | ||
| }, | ||
| ), | ||
| size: None, | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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) = ...
There was a problem hiding this comment.
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
This comment was marked as resolved.
This comment was marked as resolved.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
eb13b48 to
f782c2f
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
a7df6d9 to
b5eecb0
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@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 |
|
Assertions about 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 |
|
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 |
This comment has been minimized.
This comment has been minimized.
23c6f84 to
ae272ad
Compare
This comment has been minimized.
This comment has been minimized.
672e50f to
79bbbee
Compare
This comment has been minimized.
This comment has been minimized.
|
In rustc, associated type constraints are represented as separate projection predicates (e.g. ::Assoc = ...). 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? |
| self.write_immediate(imm, slice_place) | ||
| } | ||
|
|
||
| fn collect_super_traits( |
There was a problem hiding this comment.
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
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 |
f112908 to
ee32426
Compare
This comment has been minimized.
This comment has been minimized.
a605d21 to
ade493e
Compare
There was a problem hiding this 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?
| /// 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, | ||
| } |
There was a problem hiding this comment.
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?
This comment has been minimized.
This comment has been minimized.
ade493e to
ba614f0
Compare
|
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. |
like this? #[derive(Debug)]
// FIXME(type_info): Add supertraits
pub struct DynTraitPredicate {
...
}Also, we might need to do that for generics as well no? |
| /// The predicates of a dynamic trait. | ||
| pub predicates: &'static [DynTraitPredicate], |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
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. |
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 withdyn for<'a> Foo<'a>, though it works fine for normaldyn Footrait objectsr? @oli-obk