Skip to content

[Runtime] Wrap _checkGenericRequirements for _instantiateCheckedGenericMetadata #68844

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
merged 1 commit into from
Oct 10, 2023
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
32 changes: 22 additions & 10 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2846,17 +2846,29 @@ const Metadata *swift::_swift_instantiateCheckedGenericMetadata(
return nullptr;
}

DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler;
llvm::SmallVector<const void *, 8> extraArguments;

llvm::ArrayRef<MetadataOrPack> genericArgsRef(
reinterpret_cast<const MetadataOrPack *>(genericArgs), genericArgsSize);
llvm::SmallVector<unsigned, 8> genericParamCounts;
llvm::SmallVector<const void *, 8> allGenericArgs;
for (size_t i = 0; i != genericArgsSize; i += 1) {
extraArguments.push_back(genericArgs[i]);
}

auto result = _gatherGenericParameters(context, genericArgsRef,
/* parent */ nullptr,
genericParamCounts, allGenericArgs,
demangler);
// Check whether the generic requirements are satisfied, collecting
// any extra arguments we need for the instantiation function.
//
// Note: The extra arguemnts provided are not complete and do not include
// witness tables. This is fine for _checkGenericRequirements because it does
// not look for any of those.
SubstGenericParametersFromMetadata substitutions(context, extraArguments.data());

auto result = _checkGenericRequirements(
context->getGenericContext()->getGenericRequirements(), extraArguments,
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index).Ptr;
},
[](const Metadata *type, unsigned index) {
// In fact, just don't offer any witness tables if asked for one.
return nullptr;
}, /* allowsUnresolvedSubject */ true);

// _gatherGenericParameters returns llvm::None on success.
if (result.hasValue()) {
Expand All @@ -2865,7 +2877,7 @@ const Metadata *swift::_swift_instantiateCheckedGenericMetadata(

auto accessFunction = context->getAccessFunction();

return accessFunction(MetadataState::Complete, allGenericArgs).Value;
return accessFunction(MetadataState::Complete, extraArguments).Value;
}

#if SWIFT_OBJC_INTEROP
Expand Down
3 changes: 2 additions & 1 deletion stdlib/public/runtime/Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,8 @@ class TypeInfo {
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
llvm::SmallVectorImpl<const void *> &extraArguments,
SubstGenericParameterFn substGenericParam,
SubstDependentWitnessTableFn substWitnessTable);
SubstDependentWitnessTableFn substWitnessTable,
bool allowsUnresolvedSubject = false);

/// A helper function which avoids performing a store if the destination
/// address already contains the source value. This is useful when
Expand Down
62 changes: 54 additions & 8 deletions stdlib/public/runtime/ProtocolConformance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1344,24 +1344,37 @@ static llvm::Optional<TypeLookupError>
checkGenericRequirement(const GenericRequirementDescriptor &req,
llvm::SmallVectorImpl<const void *> &extraArguments,
SubstGenericParameterFn substGenericParam,
SubstDependentWitnessTableFn substWitnessTable) {
SubstDependentWitnessTableFn substWitnessTable,
bool allowsUnresolvedSubject) {
assert(!req.getFlags().isPackRequirement());

// Make sure we understand the requirement we're dealing with.
if (!req.hasKnownKind())
return TypeLookupError("unknown kind");

const Metadata *subjectType = nullptr;

// Resolve the subject generic parameter.
auto result = swift_getTypeByMangledName(
MetadataState::Abstract, req.getParam(), extraArguments.data(),
substGenericParam, substWitnessTable);
if (result.getError())

if (!allowsUnresolvedSubject && result.isError()) {
return *result.getError();
const Metadata *subjectType = result.getType().getMetadata();
}

if (!result.isError()) {
subjectType = result.getType().getMetadata();
}

// Check the requirement.
switch (req.getKind()) {
case GenericRequirementKind::Protocol: {
// Protocol requirements _require_ a subject type.
if (result.isError()) {
return *result.getError();
}

const WitnessTable *witnessTable = nullptr;
if (!_conformsToProtocol(nullptr, subjectType, req.getProtocol(),
&witnessTable)) {
Expand All @@ -1382,16 +1395,37 @@ checkGenericRequirement(const GenericRequirementDescriptor &req,
}

case GenericRequirementKind::SameType: {
// Same type requirements don't require a valid subject.

const Metadata *sameType = nullptr;

// Demangle the second type under the given substitutions.
auto result = swift_getTypeByMangledName(
MetadataState::Abstract, req.getMangledTypeName(),
extraArguments.data(), substGenericParam, substWitnessTable);
if (result.getError())

if (!allowsUnresolvedSubject && result.isError()) {
return *result.getError();
auto otherType = result.getType().getMetadata();
}

if (!result.isError()) {
sameType = result.getType().getMetadata();
}

// If we don't have one of either the subject type or the same type and we
// have the other, then return this as a success. This assumes the given
// extra arguments have provided only the required key arguments in which
// case some same type constraints may concretize some generic arguments
// making them non-key.
//
// Note: We don't need to check for allowsUnresolvedSubject here because
// these can only be null in the case where we do allow it.
if ((!subjectType && sameType) || (subjectType && !sameType)) {
return llvm::None;
}

// Check that the types are equivalent.
if (subjectType != otherType) {
if (subjectType != sameType) {
return TYPE_LOOKUP_ERROR_FMT(
"subject type %.*s does not match %.*s", (int)req.getParam().size(),
req.getParam().data(), (int)req.getMangledTypeName().size(),
Expand All @@ -1402,10 +1436,20 @@ checkGenericRequirement(const GenericRequirementDescriptor &req,
}

case GenericRequirementKind::Layout: {
// Layout requirements _require_ a subject type.
if (result.isError()) {
return *result.getError();
}

return satisfiesLayoutConstraint(req, subjectType);
}

case GenericRequirementKind::BaseClass: {
// Base class requirements _require_ a subject type.
if (result.isError()) {
return *result.getError();
}

// Demangle the base type under the given substitutions.
auto result = swift_getTypeByMangledName(
MetadataState::Abstract, req.getMangledTypeName(),
Expand Down Expand Up @@ -1594,7 +1638,8 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
llvm::SmallVectorImpl<const void *> &extraArguments,
SubstGenericParameterFn substGenericParam,
SubstDependentWitnessTableFn substWitnessTable) {
SubstDependentWitnessTableFn substWitnessTable,
bool allowsUnresolvedSubject) {
for (const auto &req : requirements) {
if (req.getFlags().isPackRequirement()) {
auto error = checkGenericPackRequirement(req, extraArguments,
Expand All @@ -1605,7 +1650,8 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
} else {
auto error = checkGenericRequirement(req, extraArguments,
substGenericParam,
substWitnessTable);
substWitnessTable,
allowsUnresolvedSubject);
if (error)
return error;
}
Expand Down
63 changes: 59 additions & 4 deletions test/Runtime/check_create_type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func metaPointer(_ x: Any.Type) -> UnsafeRawPointer {
unsafeBitCast(x, to: UnsafeRawPointer.self)
}

testSuite.test("_swift_checkedCreateType non-variadic") {
testSuite.test("_swift_instantiateCheckedGenericMetadata non-variadic") {
let dictMeta = unsafeBitCast(
[Int: Int].self as Any.Type,
to: UnsafeRawPointer.self
Expand All @@ -53,7 +53,7 @@ testSuite.test("_swift_checkedCreateType non-variadic") {
}
}

testSuite.test("_swift_checkedCreateType variadic") {
testSuite.test("_swift_instantiateCheckedGenericMetadata variadic") {
let variMeta = unsafeBitCast(
Variadic< >.self as Any.Type,
to: UnsafeRawPointer.self
Expand All @@ -70,7 +70,9 @@ testSuite.test("_swift_checkedCreateType variadic") {
UnsafeRawPointer(pack.baseAddress!),
UInt(pack.count)
)
let genericArgs = [packPointer]

// The 3 is the shape of the pack
let genericArgs = [UnsafeRawPointer(bitPattern: 3)!, packPointer]

genericArgs.withUnsafeBufferPointer { genericArgs in
let newVari = _instantiateCheckedGenericMetadata(
Expand All @@ -84,7 +86,7 @@ testSuite.test("_swift_checkedCreateType variadic") {
}
}

testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
testSuite.test("_swift_instantiateCheckedGenericMetadata variadic nested with requirements") {
let nestedMeta = unsafeBitCast(
Variadic< >.Nested<()>.self as Any.Type,
to: UnsafeRawPointer.self
Expand All @@ -101,6 +103,10 @@ testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
nestedPack.withUnsafeBufferPointer { nestedPack in
variPack.withUnsafeBufferPointer { variPack in
let nestedGenericArgs = [
// First shape class
UnsafeRawPointer(bitPattern: 3)!,
// Second shape class
UnsafeRawPointer(bitPattern: 3)!,
allocateMetadataPack(
UnsafeRawPointer(variPack.baseAddress!),
UInt(variPack.count)
Expand All @@ -126,4 +132,53 @@ testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
}
}

struct Generic<T> {}
struct Generic2<T, U> {}

extension Generic where T == Int {
struct Nested {}
}

extension Generic2 where T == U? {
struct Nested {}
}

testSuite.test("_swift_instantiateCheckedGenericMetadata concrete generic types (same type conretized)") {
let nestedMeta1 = metaPointer(Generic<Int>.Nested.self)
let nestedDesc1 = nestedMeta1.load(
fromByteOffset: MemoryLayout<Int>.size,
as: UnsafeRawPointer.self
)

let genericArgs1: [UnsafeRawPointer?] = []

genericArgs1.withUnsafeBufferPointer {
let nested = _instantiateCheckedGenericMetadata(
nestedDesc1,
UnsafeRawPointer($0.baseAddress!),
UInt($0.count)
)

expectTrue(nested == Generic<Int>.Nested.self)
}

let nestedMeta2 = metaPointer(Generic2<Int?, Int>.Nested.self)
let nestedDesc2 = nestedMeta2.load(
fromByteOffset: MemoryLayout<Int>.size,
as: UnsafeRawPointer.self
)

let genericArgs2 = [metaPointer(String.self)]

genericArgs2.withUnsafeBufferPointer {
let nested = _instantiateCheckedGenericMetadata(
nestedDesc2,
UnsafeRawPointer($0.baseAddress!),
UInt($0.count)
)

expectTrue(nested == Generic2<String?, String>.Nested.self)
}
}

runAllTests()