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

[metadata prespecialization] Check conformances. #32482

Conversation

nate-chandler
Copy link
Contributor

Previously, the metadata accessor for a generic type for which some metadata prespecialization was done only tested that the type metadata arguments were equal to those of the prespecialization. If the generic type had an argument which was constrained to conform to a protocol, the particular conformance to that protocol was determined at compile time, but the conformance was ignored in the metadata accessor. As a result it was possible--in certain multi-module cases--for the metadata accessor to incorrectly return a prespecialized metadata record whose type arguments matched the type arguments passed to the accessor but whose conformance arguments did not.

For example, given the following,

Base:
    struct K {}
    protocol P {}

Conformance1:
    import Base
    struct G<T : P> {}
    extension K : P {} // first conformance
    prespecialize( G<K>.self )

Conformance2:
    import Base
    extension K : P {} // second conformance

the metadata accessor for G defined in Conformance1 would behave like

MetadataResponse `metadata accessor for G`(
    MetadataRequest request,
    const Metadata *M,
    const WitnessTable *WT) {
  if (M == `type metadata for K`) {
    return `canonical prespecialized type metadata for G<K>`
  }
  return swift_getGenericMetadata(request, {M, WT});
}

Here, the WitnessTable argument is the witness table describing a conformance of the type whose metadata is provided to the protocol P.

The incorrect behavior occurs when calling the metadata accessor with these arguments:

some request
type metadata for K
protocol witness table for Base.K : Base.P in Conformance2

The accessor would return the canonical prespecialized type metadata for G<K>. The problem is that the prespecialized metadata contains the following generic arguments:

type metadata for K
protocol witness table for Base.K : Base.P in Conformance1;

Specificallly, the witness table is for the conformance from Conformance1, not the conformance from Conformance2.

Here, the problem is addressed by testing that the witness tables passed into the accessor are for the same conformance as the witness table referred to by the prespecialized record. Now, the metadata accessor for G will behave like

MetadataResponse `metadata accessor for G`(
    MetadataRequest request,
    const Metadata *M,
    const WitnessTable *WT) {
  if (M == `type metadata for K`
      swift_compareProtocolConformanceDescriptors(
        WT->getDescription(),
        `protocol conformance descriptor for Base.K : Base.P in Conformance1`)
     ) {
    return `canonical prespecialized type metadata for G<K>`
  }
  return swift_getGenericMetadata(request, {M, WT});
}

Consequently, when the accessor is called with the same arguments as before, the call to swift_compareProtocolConformanceDescriptors will return false and the non-matching prespecialized metadata will not be returned.

Dependent on #32471 .

@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 05bc1be9f85c6ca563e1db308c643a028970917f

@nate-chandler
Copy link
Contributor Author

@swift-ci please clean test os x platform

@nate-chandler nate-chandler force-pushed the generic-metadata-prespecialization-components/consider-conformances branch from 05bc1be to 0ae794b Compare June 23, 2020 00:45
@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 05bc1be9f85c6ca563e1db308c643a028970917f

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 05bc1be9f85c6ca563e1db308c643a028970917f

@nate-chandler
Copy link
Contributor Author

@swift-ci please clean test macos platform

@nate-chandler nate-chandler force-pushed the generic-metadata-prespecialization-components/consider-conformances branch from 0ae794b to 8ab8a5a Compare June 23, 2020 02:34
@nate-chandler
Copy link
Contributor Author

@swift-ci please test and merge

1 similar comment
@nate-chandler
Copy link
Contributor Author

@swift-ci please test and merge

Previously, the metadata accessor for a generic type for which some
metadata prespecialization was done only tested that the type metadata
arguments were equal to those of the prespecialization.  If the generic
type had an argument which was constrained to conform to a protocol, the
particular conformance to that protocol was determined at compile time,
but the conformance was ignored in the metadata accessor.  As a result
it was possible--in certain multi-module cases--for the metadata
accessor to incorrectly return a prespecialized metadata record whose
type arguments matched the type arguments passed to the accessor but
whose conformance arguments did not.

For example, given the following,

  Base:
    struct K {}
    protocol P {}

  Conformance1:
    import Base
    struct G<T : P> {}
    extension K : P {} // first conformance
    prespecialize( G<K>.self )

  Conformance2:
    import Base
    extension K : P {} // second conformance

the metadata accessor for G defined in Conformance1 would behave like

  MetadataResponse `metadata accessor for G`(
      MetadataRequest request,
      const Metadata *M,
      const WitnessTable *WT) {
    if (M == `type metadata for K`) {
      return `canonical prespecialized type metadata for G<K>`
    }
    return swift_getGenericMetadata(request, {M, WT});
  }

Here, the WitnessTable argument is the witness table describing a
conformance of the type whose metadata is provided to the protocol P.

The incorrect behavior occurs when calling the metadata accessor with
these arguments:

    `some request`
    `type metadata for K`
    `protocol witness table for Base.K : Base.P in Conformance2`

The accessor would return the `canonical prespecialized type metadata
for G<K>`.  The problem is that the prespecialized metadata contains the
following generic arguments:

    `type metadata for K`
    `protocol witness table for Base.K : Base.P in Conformance1`

Specificallly, the witness table is for the conformance from
Conformance1, not the conformance from Conformance2.

Here, the problem is addressed by testing that the witness tables passed
into the accessor are for the same conformance as the witness table
referred to by the prespecialized record.  Now, the metadata accessor
for G will behave like

  MetadataResponse `metadata accessor for G`(
      MetadataRequest request,
      const Metadata *M,
      const WitnessTable *WT) {
    if (M == `type metadata for K`
        swift_compareProtocolConformanceDescriptors(
          WT->getDescription(),
          `protocol conformance descriptor for Base.K : Base.P in Conformance1`)
       ) {
      return `canonical prespecialized type metadata for G<K>`
    }
    return swift_getGenericMetadata(request, {M, WT});
  }

Consequently, when the accessor is called with the same arguments as
before, the call to swift_compareProtocolConformanceDescriptors will
return false and the non-matching prespecialized metadata will not be
returned.
@nate-chandler nate-chandler force-pushed the generic-metadata-prespecialization-components/consider-conformances branch from 8ab8a5a to a5f0069 Compare June 23, 2020 03:34
@nate-chandler
Copy link
Contributor Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 0ae794bc4f8431271fd357dd0c94a3a45ce8da2a

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 0ae794bc4f8431271fd357dd0c94a3a45ce8da2a

@nate-chandler
Copy link
Contributor Author

@swift-ci please test macos platform

1 similar comment
@nate-chandler
Copy link
Contributor Author

@swift-ci please test macos platform

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - a5f0069

@nate-chandler
Copy link
Contributor Author

@swift-ci please clean test macos platform

@nate-chandler nate-chandler merged commit de8107e into swiftlang:master Jun 24, 2020
@nate-chandler nate-chandler deleted the generic-metadata-prespecialization-components/consider-conformances branch June 24, 2020 16:46
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.

None yet

2 participants