Skip to content

[6.0][Runtime] Fix key argument indexing when checking invertible protocols. #74357

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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions stdlib/public/runtime/DynamicCast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1864,8 +1864,8 @@ static DynamicCastResult tryCastToExtendedExistential(
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index).Ptr;
},
[&substitutions](unsigned ordinal) {
return substitutions.getMetadataOrdinal(ordinal).Ptr;
[&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) {
return substitutions.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
},
[](const Metadata *type, unsigned index) -> const WitnessTable * {
swift_unreachable("Resolution of witness tables is not supported");
Expand Down
24 changes: 12 additions & 12 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1193,7 +1193,7 @@ class SubstGenericParametersFromWrittenArgs {
genericParamCounts(genericParamCounts) {}

MetadataOrPack getMetadata(unsigned depth, unsigned index) const;
MetadataOrPack getMetadataOrdinal(unsigned ordinal) const;
MetadataOrPack getMetadataFullOrdinal(unsigned ordinal) const;
const WitnessTable *getWitnessTable(const Metadata *type,
unsigned index) const;
};
Expand Down Expand Up @@ -1413,8 +1413,8 @@ _gatherGenericParameters(const ContextDescriptor *context,
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index).Ptr;
},
[&substitutions](unsigned ordinal) {
return substitutions.getMetadataOrdinal(ordinal).Ptr;
[&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) {
return substitutions.getMetadataFullOrdinal(fullOrdinal).Ptr;
},
[&substitutions](const Metadata *type, unsigned index) {
return substitutions.getWitnessTable(type, index);
Expand Down Expand Up @@ -1847,12 +1847,12 @@ class DecodedMetadataBuilder {
// FIXME: variadic generics
return genArgs[index].getMetadata();
},
[genArgs](unsigned ordinal) {
if (ordinal >= genArgs.size())
[genArgs](unsigned fullOrdinal, unsigned keyOrdinal) {
if (fullOrdinal >= genArgs.size())
return (const Metadata*)nullptr;

// FIXME: variadic generics
return genArgs[ordinal].getMetadata();
return genArgs[fullOrdinal].getMetadata();
},
[](const Metadata *type, unsigned index) -> const WitnessTable * {
swift_unreachable("never called");
Expand Down Expand Up @@ -2810,8 +2810,8 @@ swift_distributed_getWitnessTables(GenericEnvironmentDescriptor *genericEnv,
[&substFn](unsigned depth, unsigned index) {
return substFn.getMetadata(depth, index).Ptr;
},
[&substFn](unsigned ordinal) {
return substFn.getMetadataOrdinal(ordinal).Ptr;
[&substFn](unsigned fullOrdinal, unsigned keyOrdinal) {
return substFn.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
},
[&substFn](const Metadata *type, unsigned index) {
return substFn.getWitnessTable(type, index);
Expand Down Expand Up @@ -3239,8 +3239,8 @@ SubstGenericParametersFromMetadata::getMetadata(
return MetadataOrPack(genericArgs[flatIndex]);
}

MetadataOrPack
SubstGenericParametersFromMetadata::getMetadataOrdinal(unsigned ordinal) const {
MetadataOrPack SubstGenericParametersFromMetadata::getMetadataKeyArgOrdinal(
unsigned ordinal) const {
// Don't attempt anything if we have no generic parameters.
if (genericArgs == nullptr)
return MetadataOrPack();
Expand Down Expand Up @@ -3277,8 +3277,8 @@ MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadata(
return MetadataOrPack();
}

MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadataOrdinal(
unsigned ordinal) const {
MetadataOrPack SubstGenericParametersFromWrittenArgs::getMetadataFullOrdinal(
unsigned ordinal) const {
if (ordinal < allGenericArgs.size()) {
return MetadataOrPack(allGenericArgs[ordinal]);
}
Expand Down
8 changes: 5 additions & 3 deletions stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,13 @@ class TypeInfo {
std::function<const void *(unsigned depth, unsigned index)>;

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

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

MetadataOrPack getMetadata(unsigned depth, unsigned index) const;
MetadataOrPack getMetadataOrdinal(unsigned ordinal) const;
MetadataOrPack getMetadataKeyArgOrdinal(unsigned ordinal) const;
const WitnessTable *getWitnessTable(const Metadata *type,
unsigned index) const;
};
Expand Down
12 changes: 7 additions & 5 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ ProtocolConformanceDescriptor::getWitnessTable(const Metadata *type) const {
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index).Ptr;
},
[&substitutions](unsigned ordinal) {
return substitutions.getMetadataOrdinal(ordinal).Ptr;
[&substitutions](unsigned fullOrdinal, unsigned keyOrdinal) {
return substitutions.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
},
[&substitutions](const Metadata *type, unsigned index) {
return substitutions.getWitnessTable(type, index);
Expand Down Expand Up @@ -1843,8 +1843,8 @@ checkInvertibleRequirements(const Metadata *type,
[&substFn](unsigned depth, unsigned index) {
return substFn.getMetadata(depth, index).Ptr;
},
[&substFn](unsigned ordinal) {
return substFn.getMetadataOrdinal(ordinal).Ptr;
[&substFn](unsigned fullOrdinal, unsigned keyOrdinal) {
return substFn.getMetadataKeyArgOrdinal(keyOrdinal).Ptr;
},
[&substFn](const Metadata *type, unsigned index) {
return substFn.getWitnessTable(type, index);
Expand Down Expand Up @@ -1886,6 +1886,7 @@ std::optional<TypeLookupError> swift::_checkGenericRequirements(

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

MetadataOrPack metadataOrPack(substGenericParamOrdinal(index));
MetadataOrPack metadataOrPack(substGenericParamOrdinal(index, keyIndex));
switch (genericParams[index].getKind()) {
case GenericParamKind::Type: {
if (!metadataOrPack || metadataOrPack.isMetadataPack()) {
Expand Down Expand Up @@ -1937,6 +1938,7 @@ std::optional<TypeLookupError> swift::_checkGenericRequirements(
return TYPE_LOOKUP_ERROR_FMT("unknown generic parameter kind %u",
index);
}
keyIndex++;
}

// Success!
Expand Down
30 changes: 27 additions & 3 deletions test/Interpreter/conditional_conformances_runtime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,35 @@ extension Dictionary: P where Value == (Key) -> Bool {


let yx = Y(wrapped: X())
assert(tryAsP(yx) == 11)
precondition(tryAsP(yx) == 11)

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

let yDict = Y(wrapped: dict)
assert(tryAsP(yDict) == 12)
precondition(tryAsP(yDict) == 12)

// <rdar://128774651> Generic argument indexing runs off the end when a key
// argument comes after a non-key argument.
struct Outer<T> {}

extension Outer where T == Int {
struct Inner<U> {
// Add some stored properties that will have field offsets in the metadata.
// If we read past the end of the generic arguments, we'll find these and
// crash on something that's definitely not a valid pointer.
var a: T?
var b: T?
var c: T?
var d: T?
}
}

extension Outer.Inner: P where U == String {
func foo() -> Int { return 1 }
}

let conformingInner: Any = Outer.Inner<String>()
let nonconformingInner: Any = Outer.Inner<Int>()
precondition(conformingInner is P)
precondition(!(nonconformingInner is P))