-
Notifications
You must be signed in to change notification settings - Fork 26
Distinguish VTable unsizes, add metadata #926
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?
Conversation
The only general fix is a |
charon/src/ast/expressions.rs
Outdated
| Length(ConstGeneric), | ||
| VTablePtr(TraitRef), | ||
| VTableDirect(TraitRef, Option<GlobalDeclRef>), | ||
| VTableNested(TraitRef, Option<FieldId>), |
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 is looking more and more like UnsizingMetadata is a defunctionalization x) What I'd actually want instead of ptr := unsize(ptr, UnsizingMetadata::VTableNested("field1")) is ptr := ptr with metadata (copy ptr.metadata.field1). I'm not saying you have to do that in this PR though, and we should be careful not to introduce a reborrow that wasn't there.
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.
Also the TraitRef is basically useless once we have the GlobalDeclRef, so I propose we add ConstantExprKind::Vtable and change VTableDirect to take only a ConstantExpr.
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.
Ah, something else that can happen: dyn Trait -> dyn Sized, despite the fact that Sized is not a supertrait of Trait. We might need to store a vtable pointer to dyn Sized in every vtable.
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 decided to ignore that for now and just keep the same vtable.
| let _: GlobalDeclId = self.register_item( | ||
| let id = self.register_item( | ||
| span, | ||
| tref, | ||
| TransItemSourceKind::VTableInstance( | ||
| TraitImplSource::Normal, | ||
| ), | ||
| ); | ||
| Some(GlobalDeclRef { | ||
| // FIXME: this is wrong, I believe | ||
| generics: Box::new(GenericArgs::empty()), | ||
| id, | ||
| }) |
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.
You should be able to get the right generics using translate_item instead of register_item.
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.
nit: calling this unsizing feels wrong because we're not going from sized to unsized. I'd prefer dyn-cast-to-supertrait.rs
| ) | ||
| ); | ||
| 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.
You'll notice that even if we return ConstantExprKind::VTable in this branch, we can't register the vtable instance since we don't know the impl. That's a fundamental incompleteness in the choice I made to translate vtable instances lazily: it won't work for:
fn foo<T: Trait>(x: &T) -> &dyn Trait { x }
fn main() {
let _ = foo::<SomeType>(...);
}You might want a --always-translate-vtable-instances for your purposes. Or maybe we should do a static analysis at the end of translation to register all the ones that might be used indirectly like that 🤔. Or maybe if we see any dyn Trait anywhere then we just register all the vtable instances for that trait, kinda like how we deal with lazily translating methods. Yeah that's saner.
|
Thanks for this PR! But I also totally agree with @Nadrieril that we in fact cannot always have that explicit field of fn to_dyn<T : Trait>(t : &T) -> &dyn Trait { t } |
This is not a I understand that in both cases there is a possibility we can't get the |
If I'm understanding it correctly, this is always a problem as it is somehow conceptually impossible to know the field. And I think we have reached a consensus here. As for the explicit BTW, in Eurydice now, we are now actually getting the |
| ); | ||
| }; | ||
|
|
||
| // Add a binder that contains the existentially quantified type. |
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.
Can you use translate_dyn_binder here instead of managing the binder levels yourself?
Based on AeneasVerif/hax#6
Rename
UnsizingMetadata::VTablePtr->VTableDirect, and add to it an optionalGlobalDeclReffor the associated VTable. Note I don't do anything about the global's generics right now, which I believe is wrong. There are also cases where the global is not known because the impl atom isn'tImplExprAtom::Concrete; I have no idea how to fix this, maybe @ssyram knows, but for now it's already better than nothing :)Add
UnsizingMetadata::VTableNested, fordyn-dynunsizes. It also carries aTraitRef, along with an optionalFieldId, for the field in the current VTable that contains the sub-vtable to unsize to. Note here that the field id is optional, in the case of no-op unsizes (e.g.dyn T + 'static->dyn T).I believe we should distinguish these two cases, since fundamentally they operate differently: the former "creates" metadata from a statically known VTable address, the latter fetches a VTable dynamically, from the current VTable in the metadata.
To obtain the
FieldIdinVTableNestedI had to slightly reorganise the way fields are added to the vtable structure (commit 07a71ed)(disregard the branch name, this is a first step towards mono
dynbut I didn't get there)