Skip to content

5.9 [RemoteMirror] Fix handling of generic and zero-sized cases in MPEs #65525

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

Conversation

tbkka
Copy link
Contributor

@tbkka tbkka commented Apr 29, 2023

Explanation: Implements support for enums that have a mix of zero-sized and generic payloads. I believe this implements all of the outstanding cases for enum layouts in RemoteMirror.
Risk: Only affects RemoteMirror. Replaces a core piece of the layout calculation for all enum types in RemoteMirror
Reviewed: @mikeash
Resolves: rdar://106655244
Original PR: #64852
Tests: Several new unit tests were added

tbkka added 14 commits April 28, 2023 17:54
…hen building decl"

(Keeps the test, but reverts the code changes; the test will be updated later.)

This reverts most of commit 893d83b from PR swiftlang#62854
This is a more correct fix for the issue that inspired PR swiftlang#62854.
In particular, this does not change the numbering of generic
argument levels, and so does not break generic type parameter
lookups.

Added a new test case to verify that nested types that mix
generics and non-generics in different ways consistently identify
the correct generic argument labels.
The new logic no longer includes non-generic parent types as part
of the type reference.

This also combines the 32- and 64-bit tests validations, since they
were identical for this test anyway.
The recursive structure made it a little awkward to correctly
distinguish between the root node (which has to be included
regardless of whether it has direct generic params)
and the parent nodes (which must only be included if they
have direct params).

So I rewrote this to do a simple two-pass iteration:
* The first pass walks the parent list collecting candidates
* The second pass walks the list backwards, assigning generic params

We then just stack the start node onto the end of the
list regardless of whether it has generic params.
Handle the top node directly in `createBoundGenericType`
so that we can be sure to always include it regardless
of whether it has direct generic type params or not.

The helper function can now focus only on handling
parents (where we must only include ones that actually
contain generic type params).  This separates the two
different cases and makes it a little easier to follow.

I refactored `reconstructParentsOfBoundGenericType` to
be iterative rather than recursive, though I'm not sure that
really matters.
This exercises a number of cases that the previous logic got
wrong, including cases where MPEs are laid out like SPEs,
and cases where we use the SPE or MPE layout strategies for enums
that have no non-empty payloads.  (These cases are superficially
similar but differ in how they handle XIs.)

These new tests allowed me to correct a number logical flaws
about how layouts are selected.  In particular, cases with
generic payloads are always considered to be non-empty for
purposes of selecting a layout strategy.  Only cases that
are statically known to be empty are considered empty for
layout purposes.
A "generic" case is any case whose payload type depends
on generic type parameters for the enum or any enclosing type.
Some examples:

```
struct S<T> {
  enum E {
    case a        // Non-generic case
    case b(Int)   // Non-generic case
    case c(T)     // Generic case
    case d([U])   // Generic case
    case e([Int]) // Non-generic case
  }
}
```

This is important for correctly distinguishing MPE versus
SPE layouts.  A case is considered "empty" only if it
is either a non-payload case (`case a`) or if the payload
is zero-sized and non-generic.  Generic cases are always
treated as non-zero-sized for purposes of determining
the layout strategy.

Correctly testing this is tricky, since some of the
layout strategies differ only in whether they export
extra tag values as XIs.  The easiest way to verify is
to check whether wrapping the result in an `Optional<>`
adds another byte to the overall size.
In particular, the exactly internal layout of Array<> is quite
different between macOS and Linux, which makes it impractical
for use in tests like this.  An empty class is still a reference
and doesn't introduce so many complications.
@tbkka tbkka requested a review from a team as a code owner April 29, 2023 01:15
@tbkka
Copy link
Contributor Author

tbkka commented Apr 29, 2023

Note: This builds on #65524 -- that PR should be merged first since its contents are also included here.

@tbkka
Copy link
Contributor Author

tbkka commented Apr 29, 2023

@swift-ci Please test

@tbkka tbkka requested review from mikeash and btroller April 29, 2023 01:18
@tbkka
Copy link
Contributor Author

tbkka commented May 1, 2023

When I assembled this, I somehow missed a commit. Adding that in and re-testing.

@tbkka
Copy link
Contributor Author

tbkka commented May 1, 2023

@swift-ci Please test

@tbkka tbkka merged commit 39e6ac3 into swiftlang:release/5.9 May 2, 2023
@AnthonyLatsis AnthonyLatsis added the 🍒 release cherry pick Flag: Release branch cherry picks label May 3, 2023
@tbkka tbkka deleted the 5.9-tbkka-RemoteMirror-MPE-zero-sized-plus-generics branch August 1, 2024 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍒 release cherry pick Flag: Release branch cherry picks
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants