Skip to content

Commit 63c484a

Browse files
committed
[6.0][Runtime] Fix key argument indexing when checking invertible protocols.
Track the key argument index separately from the generic parameter index when performing the invertible protocol checking in _checkGenericRequirements. This keeps the indexing correct when a non-key argument is followed by a key argument. rdar://128774651 (cherry picked from commit b86fe88)
1 parent e7c2412 commit 63c484a

File tree

5 files changed

+53
-25
lines changed

5 files changed

+53
-25
lines changed

stdlib/public/runtime/DynamicCast.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,8 +1864,8 @@ static DynamicCastResult tryCastToExtendedExistential(
18641864
[&substitutions](unsigned depth, unsigned index) {
18651865
return substitutions.getMetadata(depth, index).Ptr;
18661866
},
1867-
[&substitutions](unsigned ordinal) {
1868-
return substitutions.getMetadataOrdinal(ordinal).Ptr;
1867+
[&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) {
1868+
return substitutions.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
18691869
},
18701870
[](const Metadata *type, unsigned index) -> const WitnessTable * {
18711871
swift_unreachable("Resolution of witness tables is not supported");

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,7 +1193,7 @@ class SubstGenericParametersFromWrittenArgs {
11931193
genericParamCounts(genericParamCounts) {}
11941194

11951195
MetadataOrPack getMetadata(unsigned depth, unsigned index) const;
1196-
MetadataOrPack getMetadataOrdinal(unsigned ordinal) const;
1196+
MetadataOrPack getMetadataFullOrdinal(unsigned ordinal) const;
11971197
const WitnessTable *getWitnessTable(const Metadata *type,
11981198
unsigned index) const;
11991199
};
@@ -1413,8 +1413,8 @@ _gatherGenericParameters(const ContextDescriptor *context,
14131413
[&substitutions](unsigned depth, unsigned index) {
14141414
return substitutions.getMetadata(depth, index).Ptr;
14151415
},
1416-
[&substitutions](unsigned ordinal) {
1417-
return substitutions.getMetadataOrdinal(ordinal).Ptr;
1416+
[&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) {
1417+
return substitutions.getMetadataFullOrdinal(fullOrdinal).Ptr;
14181418
},
14191419
[&substitutions](const Metadata *type, unsigned index) {
14201420
return substitutions.getWitnessTable(type, index);
@@ -1847,12 +1847,12 @@ class DecodedMetadataBuilder {
18471847
// FIXME: variadic generics
18481848
return genArgs[index].getMetadata();
18491849
},
1850-
[genArgs](unsigned ordinal) {
1851-
if (ordinal >= genArgs.size())
1850+
[genArgs](unsigned fullOrdinal, unsigned keyOrdinal) {
1851+
if (fullOrdinal >= genArgs.size())
18521852
return (const Metadata*)nullptr;
18531853

18541854
// FIXME: variadic generics
1855-
return genArgs[ordinal].getMetadata();
1855+
return genArgs[fullOrdinal].getMetadata();
18561856
},
18571857
[](const Metadata *type, unsigned index) -> const WitnessTable * {
18581858
swift_unreachable("never called");
@@ -2810,8 +2810,8 @@ swift_distributed_getWitnessTables(GenericEnvironmentDescriptor *genericEnv,
28102810
[&substFn](unsigned depth, unsigned index) {
28112811
return substFn.getMetadata(depth, index).Ptr;
28122812
},
2813-
[&substFn](unsigned ordinal) {
2814-
return substFn.getMetadataOrdinal(ordinal).Ptr;
2813+
[&substFn](unsigned fullOrdinal, unsigned keyOrdinal) {
2814+
return substFn.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
28152815
},
28162816
[&substFn](const Metadata *type, unsigned index) {
28172817
return substFn.getWitnessTable(type, index);
@@ -3239,8 +3239,8 @@ SubstGenericParametersFromMetadata::getMetadata(
32393239
return MetadataOrPack(genericArgs[flatIndex]);
32403240
}
32413241

3242-
MetadataOrPack
3243-
SubstGenericParametersFromMetadata::getMetadataOrdinal(unsigned ordinal) const {
3242+
MetadataOrPack SubstGenericParametersFromMetadata::getMetadataKeyArgOrdinal(
3243+
unsigned ordinal) const {
32443244
// Don't attempt anything if we have no generic parameters.
32453245
if (genericArgs == nullptr)
32463246
return MetadataOrPack();
@@ -3277,8 +3277,8 @@ MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadata(
32773277
return MetadataOrPack();
32783278
}
32793279

3280-
MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadataOrdinal(
3281-
unsigned ordinal) const {
3280+
MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadataFullOrdinal(
3281+
unsigned ordinal) const {
32823282
if (ordinal < allGenericArgs.size()) {
32833283
return MetadataOrPack(allGenericArgs[ordinal]);
32843284
}

stdlib/public/runtime/Private.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -295,11 +295,13 @@ class TypeInfo {
295295
std::function<const void *(unsigned depth, unsigned index)>;
296296

297297
/// Callback used to provide the substitution of a generic parameter
298-
/// (described by the ordinal, or "flat index") to its metadata.
298+
/// (described by the ordinal, or "flat index") to its metadata. The index may
299+
/// be "full" or it may be only relative to key arguments. The call is
300+
/// provided both indexes and may use the one it requires.
299301
///
300302
/// The return type here is a lie; it's actually a MetadataOrPack.
301303
using SubstGenericParameterOrdinalFn =
302-
std::function<const void *(unsigned ordinal)>;
304+
std::function<const void *(unsigned fullOrdinal, unsigned keyOrdinal)>;
303305

304306
/// Callback used to provide the substitution of a witness table based on
305307
/// its index into the enclosing generic environment.
@@ -460,7 +462,7 @@ class TypeInfo {
460462
const void * const *getGenericArgs() const { return genericArgs; }
461463

462464
MetadataOrPack getMetadata(unsigned depth, unsigned index) const;
463-
MetadataOrPack getMetadataOrdinal(unsigned ordinal) const;
465+
MetadataOrPack getMetadataKeyArgOrdinal(unsigned ordinal) const;
464466
const WitnessTable *getWitnessTable(const Metadata *type,
465467
unsigned index) const;
466468
};

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,8 @@ ProtocolConformanceDescriptor::getWitnessTable(const Metadata *type) const {
340340
[&substitutions](unsigned depth, unsigned index) {
341341
return substitutions.getMetadata(depth, index).Ptr;
342342
},
343-
[&substitutions](unsigned ordinal) {
344-
return substitutions.getMetadataOrdinal(ordinal).Ptr;
343+
[&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) {
344+
return substitutions.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
345345
},
346346
[&substitutions](const Metadata *type, unsigned index) {
347347
return substitutions.getWitnessTable(type, index);
@@ -1843,8 +1843,8 @@ checkInvertibleRequirements(const Metadata *type,
18431843
[&substFn](unsigned depth, unsigned index) {
18441844
return substFn.getMetadata(depth, index).Ptr;
18451845
},
1846-
[&substFn](unsigned ordinal) {
1847-
return substFn.getMetadataOrdinal(ordinal).Ptr;
1846+
[&substFn](unsigned fullOrdinal, unsigned keyOrdinal) {
1847+
return substFn.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
18481848
},
18491849
[&substFn](const Metadata *type, unsigned index) {
18501850
return substFn.getWitnessTable(type, index);
@@ -1886,6 +1886,7 @@ std::optional<TypeLookupError> swift::_checkGenericRequirements(
18861886

18871887
// Now, check all of the generic arguments for invertible protocols.
18881888
unsigned numGenericParams = genericParams.size();
1889+
unsigned keyIndex = 0;
18891890
for (unsigned index = 0; index != numGenericParams; ++index) {
18901891
// Non-key arguments don't need to be checked, because they are
18911892
// aliased to another type.
@@ -1896,7 +1897,7 @@ std::optional<TypeLookupError> swift::_checkGenericRequirements(
18961897
if (index < allSuppressed.size())
18971898
suppressed = allSuppressed[index];
18981899

1899-
MetadataOrPack metadataOrPack(substGenericParamOrdinal(index));
1900+
MetadataOrPack metadataOrPack(substGenericParamOrdinal(index, keyIndex));
19001901
switch (genericParams[index].getKind()) {
19011902
case GenericParamKind::Type: {
19021903
if (!metadataOrPack || metadataOrPack.isMetadataPack()) {
@@ -1937,6 +1938,7 @@ std::optional<TypeLookupError> swift::_checkGenericRequirements(
19371938
return TYPE_LOOKUP_ERROR_FMT("unknown generic parameter kind %u",
19381939
index);
19391940
}
1941+
keyIndex++;
19401942
}
19411943

19421944
// Success!

test/Interpreter/conditional_conformances_runtime.swift

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,35 @@ extension Dictionary: P where Value == (Key) -> Bool {
3333

3434

3535
let yx = Y(wrapped: X())
36-
assert(tryAsP(yx) == 11)
36+
precondition(tryAsP(yx) == 11)
3737

3838
let dict: [Int : (Int) -> Bool] = [:]
39-
assert(tryAsP(dict) == 2)
39+
precondition(tryAsP(dict) == 2)
4040

4141
let yDict = Y(wrapped: dict)
42-
assert(tryAsP(yDict) == 12)
42+
precondition(tryAsP(yDict) == 12)
4343

44+
// <rdar://128774651> Generic argument indexing runs off the end when a key
45+
// argument comes after a non-key argument.
46+
struct Outer<T> {}
47+
48+
extension Outer where T == Int {
49+
struct Inner<U> {
50+
// Add some stored properties that will have field offsets in the metadata.
51+
// If we read past the end of the generic arguments, we'll find these and
52+
// crash on something that's definitely not a valid pointer.
53+
var a: T?
54+
var b: T?
55+
var c: T?
56+
var d: T?
57+
}
58+
}
59+
60+
extension Outer.Inner: P where U == String {
61+
func foo() -> Int { return 1 }
62+
}
63+
64+
let conformingInner: Any = Outer.Inner<String>()
65+
let nonconformingInner: Any = Outer.Inner<Int>()
66+
precondition(conformingInner is P)
67+
precondition(!(nonconformingInner is P))

0 commit comments

Comments
 (0)