Skip to content
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

Feat.rewrite.lifetime #915

Merged
merged 14 commits into from
May 11, 2023
Merged

Feat.rewrite.lifetime #915

merged 14 commits into from
May 11, 2023

Conversation

aneksteind
Copy link
Contributor

@aneksteind aneksteind commented May 5, 2023

Rewrites structs to reflect hypothetical lifetimes accepted by polonius.

e.g.

pub struct Data<'d> {
    pub pi: *mut i32,
    pub pa: *mut A<'d>,
    pub a: A<'d>,
}
pub struct A<'a> {
    pub rd: &'a Data<'a>,
    pub pra: *mut &'a mut A<'a>,
}

struct VecTup<'a> {
    bar: *mut Vec<(VecTup<'a>, *mut A<'a>)>,
}

gets rewritten to

pub struct Data<'d,'h0,'h1,'h2> {
    pub pi: &'h0 mut (i32),
    pub pa: &'h1 mut (A<'d,'h0,'h1,'h2>),
    pub a: A<'d,'h0,'h1,'h2>,
}

pub struct A<'a,'h0,'h1,'h2> {
    pub rd: &'a (Data<'a,'h0,'h1,'h2>),
    pub pra: &'h2 core::cell::Cell<(&'a (A<'a,'h0,'h1,'h2>))>,
}

struct VecTup<'a,'h3,'h4,'h0,'h1,'h2> {
    bar: &'h3 (Vec<(VecTup<'a,'h3,'h4,'h0,'h1,'h2>, &'h4 (A<'a,'h0,'h1,'h2>))>),
}

@aneksteind aneksteind force-pushed the feat.rewrite.lifetime branch 3 times, most recently from cf7eacc to 3f7bea0 Compare May 5, 2023 23:31
@aneksteind aneksteind changed the base branch from master to feat.rewrite.struct May 8, 2023 12:29
@aneksteind aneksteind force-pushed the feat.rewrite.lifetime branch 6 times, most recently from 590a3dd to 1199a8f Compare May 8, 2023 14:33
@aneksteind aneksteind force-pushed the feat.rewrite.lifetime branch 2 times, most recently from 3f14512 to a97d979 Compare May 8, 2023 16:03
@aneksteind aneksteind changed the base branch from feat.rewrite.struct to master May 8, 2023 17:30
@aneksteind aneksteind force-pushed the feat.rewrite.lifetime branch 5 times, most recently from c5e4266 to 7bbfc3d Compare May 8, 2023 19:18
@aneksteind aneksteind marked this pull request as ready for review May 8, 2023 19:19
if let Some(adt_metadata) = &self.acx.gacx.adt_metadata.table.get(&adt_def.did()) {
self.hir_rewrites.push((
hir_ty.span,
adt_ty_rw(adt_def, &adt_metadata.lifetime_params, substs),
Copy link
Collaborator

Choose a reason for hiding this comment

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

adt_metadata.lifetime_params tells you what lifetimes are declared on the type, not what lifetimes should be passed at this particular use of it. Due to the way we infer hypothetical lifetimes in ADTs, it happens to be the case that the names match up within struct fields (given struct Foo<'h0> { ... }, all uses will look like struct Bar<'h0, 'h1> { foo: &'h1 Foo<'h0> }, with the same name 'h0 in both places), but this isn't true in general.

struct Foo<'h0> { ... }
fn foo1<'a>(x: Foo<'a>, y: Foo<'a>) { ... }
fn foo2<'a, 'b>(x: Foo<'a>, y: Foo<'b>) { ... }

Given Foo, both the foo1 and foo2 signatures are valid, and they mean different things, so we need a way to express both of them.

RewriteLabel probably needs a field like &'tcx [OriginArg<'tcx>] representing the lifetime arguments of a particular Ty, with similar meaning to the labels of FieldMetadata's origin_args field. That will allow for distinctions like the above foo1/foo2 example.

For struct field types, the lifetime arguments can be set from the existing FieldMetadata::origin_args labels. For types in function signatures, we'll eventually need a similar setup to generate hypothetical parameters and so on, but for now that doesn't exist, so any region arguments should either be elided or left as 'static. Inside function bodies, the regions can always be elided.

Copy link
Contributor Author

@aneksteind aneksteind May 9, 2023

Choose a reason for hiding this comment

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

Thanks for the catch, the tests were wrong and didn't complain about this. I've addressed it in 37e14bc and took out the test for the function lifetime rewriting for the time being; I'll create an issue for it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Issue created #921

@aneksteind
Copy link
Contributor Author

@spernsteiner would you mind taking another look at this?

@aneksteind aneksteind force-pushed the feat.rewrite.lifetime branch from 961c23e to c114df6 Compare May 11, 2023 16:45
Copy link
Collaborator

@spernsteiner spernsteiner left a comment

Choose a reason for hiding this comment

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

This generally looks okay, but I have questions about a couple specific rewrite cases

c2rust-analyze/src/context.rs Show resolved Hide resolved
c2rust-analyze/src/rewrite/ty.rs Outdated Show resolved Hide resolved
c2rust-analyze/src/rewrite/ty.rs Outdated Show resolved Hide resolved
c2rust-analyze/src/rewrite/ty.rs Outdated Show resolved Hide resolved
Comment on lines +436 to +438
if let TyKind::Adt(adt_def, substs) = rw_lty.ty.kind() {
if !rw_lty.label.lifetime.is_empty() {
self.hir_rewrites.push((
Copy link
Collaborator

Choose a reason for hiding this comment

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

I was expecting this to generate a rewrite on every ADT with at least one lifetime, which would lead to unnecessary unfolding of type aliases. But I didn't see that effect when I ran it on this code:

struct Test<'a>(&'a u8);
type Alias<'a> = Test<'a>;
fn f<'a>(x: Alias<'a>) {}

I was expecting a rewrite from x: Alias<'a> to x: Test<'a>, but no such rewrite occurred. Under what conditions is label.lifetime non-empty? I was expecting it to be set to the original lifetime args ['a] in this case. Is it empty for structs that have no hypothetical lifetimes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alias doesn't get rewritten because it doesn't appear in the ADT metadata table, and that's because it's DefKind is a TyAlias and not one of Struct | Enum | Union

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is support for TyAlias for structs something that can be done in a follow-up PR?

Copy link
Contributor Author

@aneksteind aneksteind May 11, 2023

Choose a reason for hiding this comment

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

Issue created in #926

)))
}
_ => {
other_params.push(Rewrite::PrintTy(gp.name.ident().to_string()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Will this swallow constraints, rewriting struct Foo<T: Clone>(...) into struct Foo<T>(...)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Issue created in #927. Would you mind elaborating on that issue as to how fresh hypothetical lifetimes would be spliced in?

@spernsteiner
Copy link
Collaborator

spernsteiner commented May 11, 2023

I think ideally we would be able to either insert additional lifetime arguments before/after some existing argument (<T> -> <'h0, T> or <'a> -> <'a, 'h0>, with the rewrite being placed on a zero-width span <{}T> or <'a{}>) or generate a whole generics list from scratch if none is present (Foo -> Foo<'h0>, again attaching the rewrite to a zero-width span Foo{}). This would minimize disruption of the existing source code. But it might be better to just add a TODO or open an issue to avoid this complexity for now.

aneksteind and others added 11 commits May 11, 2023 16:54
Co-authored-by: Khyber Sen <kkysen@gmail.com>
Co-authored-by: Khyber Sen <kkysen@gmail.com>
Co-authored-by: Khyber Sen <kkysen@gmail.com>
Co-authored-by: Khyber Sen <kkysen@gmail.com>
Co-authored-by: Khyber Sen <kkysen@gmail.com>
Co-authored-by: Khyber Sen <kkysen@gmail.com>
@aneksteind aneksteind force-pushed the feat.rewrite.lifetime branch from c114df6 to b61367a Compare May 11, 2023 20:57
David Anekstein and others added 3 commits May 11, 2023 16:58
@aneksteind aneksteind merged commit caf1fd5 into master May 11, 2023
@aneksteind aneksteind deleted the feat.rewrite.lifetime branch May 11, 2023 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants