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

.chalk syntax writer: Fix name de-duplication bug #585

Merged
merged 3 commits into from
Aug 2, 2020

Conversation

super-tuple
Copy link
Contributor

While working on #575, we found a bug in the name de-duplication logic. To ensure we have unique names, we store a mapping between ids and names for ids that don't have unique names. This state was managed inside of write_items, but we call write_items twice when we output the data from the LoggingRustIrDatabase. It is called once to output the logged items, and once to output the necessary stub items. The id to name mappings are lost between these calls, which breaks the unique name guarantee.

We fixed this by creating the mapping information store outside of the display code, and passing it into calls to write_items. We also significantly improved the name de-duplication tests.

super-tuple and others added 2 commits July 25, 2020 15:44
In preparation for future changes, we wanted to split the WriterState
into a public and a private version. This is needed to support
persisting WriterState between writes. We also encapsulated the `db`
field behind a method, so it can be moved later on.

Co-authored-by: David Ross <daboross@daboross.net>
This fixes two bugs in unique name generation. The bug which prompted
this change is related to stub items: LoggingRustIrDatabase calls
`write_stub_items` and `write_items` separately, and unique name choices
were not persisted between these calls. The second bug, discovered by
our test framework, was that associated type names were not made unique
within a trait.

We refactored writer state into a public `WriterState`, and a private
`InternalWriterState`. The public WriterState holds a copy of the DB and
the name de-duplication information. The private `InternalWriterState`
holds the current debrujin index information and formatting data.

The public `WriterState` is created outside of the display code, and is
saved between writes. In the case of the LoggingDB, it is stored inside
the logging db. This ensures that all writes from the LoggingDB have
consistent unique names.

Storing `WriterState` persistently is not strictly necessary; to fix the
unique name choice bug, we only need to persist it between the calls to
`write_stub_items` and `write_items` in `Display::fmt`. But storing it
longer was easy to do, and not less correct.

Co-authored-by: David Ross <daboross@daboross.net>
Copy link
Member

@detrumi detrumi left a comment

Choose a reason for hiding this comment

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

Wow, that's a lot of changes again. LGTM, some small suggestions and nits.

}

fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> {
self.db.borrow().hidden_opaque_type(id)
self.db.hidden_opaque_type(id)
}

fn impls_for_trait(
Copy link
Member

Choose a reason for hiding this comment

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

You missed a db.borrow() call here, and in closure_inputs_and_output as well

/// given database, and must keep the same ID<->item relationships.
pub(super) fn wrap_db_ref<'a, DB2: ?Sized, P2, F>(&'a self, f: F) -> WriterState<I, DB2, P2>
where
P: 'a,
Copy link
Member

Choose a reason for hiding this comment

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

This bound doesn't seem to be needed

Copy link
Contributor

@daboross daboross Aug 1, 2020

Choose a reason for hiding this comment

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

I think we need it because f takes &'a P, that being sound requires P: 'a, and since we're just introducing 'a here, there's no guarantee it really is shorter than P?

We need 'a at all, because we want to be able to create a P2 which directly wraps P, and in order to do that the &P needs a lifetime that's guaranteed to outlive the function. If it was just FnOnce(&P) -> P2, then the &P could have been created inside wrap_db_ref, and then it really would be unsound to have P2 wrapping P.

Edit: I was 100% sure we'd checked that it doesn't compile without P: 'a, but it must have been some other change. Looks like it is redundant!

chalk-solve/src/display/state.rs Show resolved Hide resolved
We fixed nitpick froms rust-lang#585:
 * Removed excess .borrow() calls introduced by a git merge.
 * Removed uneeded life-time bound.

Thanks detrumi for the feedback!

Co-authored-by: David Ross <daboross@daboross.net>
@detrumi
Copy link
Member

detrumi commented Aug 2, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Aug 2, 2020

📌 Commit 888da92 has been approved by detrumi

@bors
Copy link
Contributor

bors commented Aug 2, 2020

⌛ Testing commit 888da92 with merge 6a46a7c...

@bors
Copy link
Contributor

bors commented Aug 2, 2020

☀️ Test successful - checks-actions
Approved by: detrumi
Pushing 6a46a7c to master...

@bors bors merged commit 6a46a7c into rust-lang:master Aug 2, 2020
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.

4 participants