Skip to content

[5.9] [Runtime] Add a function to check type creation #68376

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
Sep 8, 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
12 changes: 12 additions & 0 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -1007,6 +1007,18 @@ SWIFT_RUNTIME_STDLIB_SPI
void _swift_registerConcurrencyStandardTypeDescriptors(
const ConcurrencyStandardTypeDescriptors *descriptors);

/// Check if the given generic arguments are valid inputs for the generic type
/// context and if so call the metadata access function and return the metadata.
///
/// Note: This expects the caller to heap allocate all pack pointers within the
/// generic arguments via 'swift_allocateMetadataPack'.
SWIFT_RUNTIME_STDLIB_SPI
SWIFT_CC(swift)
const Metadata *_swift_instantiateCheckedGenericMetadata(
const TypeContextDescriptor *context,
const void * const *genericArgs,
size_t genericArgsSize);

#pragma clang diagnostic pop

} // end namespace swift
Expand Down
35 changes: 35 additions & 0 deletions stdlib/public/runtime/MetadataLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2825,6 +2825,41 @@ swift_getOpaqueTypeConformance(const void * const *arguments,
arguments, static_cast<const OpaqueTypeDescriptor *>(descriptor), index);
}

SWIFT_RUNTIME_STDLIB_SPI
SWIFT_CC(swift)
const Metadata *swift::_swift_instantiateCheckedGenericMetadata(
const TypeContextDescriptor *context,
const void * const *genericArgs,
size_t genericArgsSize) {
context = swift_auth_data_non_address(
context, SpecialPointerAuthDiscriminators::ContextDescriptor);

if (!context->isGeneric()) {
return nullptr;
}

DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler;

llvm::ArrayRef<MetadataOrPack> genericArgsRef(
reinterpret_cast<const MetadataOrPack *>(genericArgs), genericArgsSize);
llvm::SmallVector<unsigned, 8> genericParamCounts;
llvm::SmallVector<const void *, 8> allGenericArgs;

auto result = _gatherGenericParameters(context, genericArgsRef,
/* parent */ nullptr,
genericParamCounts, allGenericArgs,
demangler);

// _gatherGenericParameters returns llvm::None on success.
if (result.hasValue()) {
return nullptr;
}

auto accessFunction = context->getAccessFunction();

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

#if SWIFT_OBJC_INTEROP

// Return the ObjC class for the given type name.
Expand Down
129 changes: 129 additions & 0 deletions test/Runtime/check_create_type.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking)
// REQUIRES: executable_test

// UNSUPPORTED: CPU=arm64e
// UNSUPPORTED: use_os_stdlib
// UNSUPPORTED: back_deployment_runtime

import StdlibUnittest

let testSuite = TestSuite("CheckedCreateType")

struct Variadic<each T> {
struct Nested<U, each V: Equatable> {}
}

@_silgen_name("swift_allocateMetadataPack")
func allocateMetadataPack(
_ packPointer: UnsafeRawPointer,
_ packCount: UInt
) -> UnsafeRawPointer

@_silgen_name("_swift_instantiateCheckedGenericMetadata")
func _instantiateCheckedGenericMetadata(
_ descriptor: UnsafeRawPointer,
_ genericArgs: UnsafeRawPointer,
_ genericArgsSize: UInt
) -> Any.Type?

func metaPointer(_ x: Any.Type) -> UnsafeRawPointer {
unsafeBitCast(x, to: UnsafeRawPointer.self)
}

testSuite.test("_swift_checkedCreateType non-variadic") {
let dictMeta = unsafeBitCast(
[Int: Int].self as Any.Type,
to: UnsafeRawPointer.self
)
let dictDesc = dictMeta.load(
fromByteOffset: MemoryLayout<Int>.size,
as: UnsafeRawPointer.self
)

let dictGenericArgs: [Any.Type] = [String.self, Double.self]

dictGenericArgs.withUnsafeBufferPointer {
let newDict = _instantiateCheckedGenericMetadata(
dictDesc,
UnsafeRawPointer($0.baseAddress!),
UInt($0.count)
)

expectTrue(newDict == [String: Double].self)
}
}

testSuite.test("_swift_checkedCreateType variadic") {
let variMeta = unsafeBitCast(
Variadic< >.self as Any.Type,
to: UnsafeRawPointer.self
)
let variDesc = variMeta.load(
fromByteOffset: MemoryLayout<Int>.size,
as: UnsafeRawPointer.self
)

let variPack: [Any.Type] = [Int.self, Int8.self, UInt8.self]

variPack.withUnsafeBufferPointer { pack in
let packPointer = allocateMetadataPack(
UnsafeRawPointer(pack.baseAddress!),
UInt(pack.count)
)
let genericArgs = [packPointer]

genericArgs.withUnsafeBufferPointer { genericArgs in
let newVari = _instantiateCheckedGenericMetadata(
variDesc,
UnsafeRawPointer(genericArgs.baseAddress!),
UInt(genericArgs.count)
)

expectTrue(newVari == Variadic<Int, Int8, UInt8>.self)
}
}
}

testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
let nestedMeta = unsafeBitCast(
Variadic< >.Nested<()>.self as Any.Type,
to: UnsafeRawPointer.self
)
let nestedDesc = nestedMeta.load(
fromByteOffset: MemoryLayout<Int>.size,
as: UnsafeRawPointer.self
)

let variPack: [Any.Type] = [String.self, [Int].self, UInt64.self]

let nestedPack: [Any.Type] = [Int.self, Substring.self, Bool.self]

nestedPack.withUnsafeBufferPointer { nestedPack in
variPack.withUnsafeBufferPointer { variPack in
let nestedGenericArgs = [
allocateMetadataPack(
UnsafeRawPointer(variPack.baseAddress!),
UInt(variPack.count)
),
metaPointer(Int16.self),
allocateMetadataPack(
UnsafeRawPointer(nestedPack.baseAddress!),
UInt(nestedPack.count)
)
]

nestedGenericArgs.withUnsafeBufferPointer { nestedGenericArgs in

let newNested = _instantiateCheckedGenericMetadata(
nestedDesc,
UnsafeRawPointer(nestedGenericArgs.baseAddress!),
UInt(nestedGenericArgs.count)
)

expectTrue(newNested == Variadic<String, [Int], UInt64>.Nested<Int16, Int, Substring, Bool>.self)
}
}
}
}

runAllTests()