Fixup Bidirectional Map #662
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The setters here were both implemented in such a way that the map would
lose the invariant that it was truly bidirectional. In particular, one
must ensure that previous mappings from keys to values were struck from
the bidirectional map before emplacing a new mapping, else the mirror
image of the mapping would retain extra entries.
In addition, document the misuse of this data structure in the driver.
The mapping from swiftdeps to swift files is a not a bijection. There
are three sources of data that can all give conflicting mappings from
swiftdeps files to swift files in particular:
This means we can have at most three conflicting maps from some
swiftdeps files to some swift file. Currently, the driver overwrites
this mapping and the last writer wins. This is the root cause of
a family of crashers where the output file map's contents disagreed from
run to run.
When a project workspace is set up with multiple files with the same
base name but differing extensions, XCBuild will disambiguate any
products by appending a GUID derived from the structure of the project.
That means, if foo.swift and foo.c live in the same target's inputs,
then the output file map will have an entry
foo-<GUID_1>.swiftdeps
This GUID is derived from the structure of the project itself, and
changes with that structure. So, for example, one can delete and re-add
a reference to a swift file and the output file map entry for that
swiftdeps file will regenerate
foo-<GUID_2>.swiftdeps
This means that the priors' swiftdeps files now disagree in content with
the output file map, and the output file map's entries currently win.
But, only partially. Because the bidirectional map was broken, it was
able to successfully answer queries about the extra injective mapping
between swift files and swiftdeps files. It was, however, not equipped
to handle the other direction, and so it used to crash. We have since
changed this to redo the incremental build to flush this state.
There is a remaining lurking bug here that involves an extra step.
Suppose you build in a normal way with foo.swift/foo.c setup. Then you
rebuild and cancel it after a frontend has emitted a new swiftdeps file,
finally, you crash the driver by exploiting this bug. The driver is now
in a state where swiftdeps disagree with the priors which disagree with
the output file map.
All this to say, we should take the earliest opportunity to remove
BidirectionalMap and its uses. But this commit is not the one to make
such a structural change to the driver.
rdar://77804636