You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
0 commit comments