Skip to content

Commit 1375ce6

Browse files
authored
Merge pull request #68359 from Azoy/packs-pack-packs
[Runtime] Add a function to check type creation
2 parents d2e7b05 + 80187e8 commit 1375ce6

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,18 @@ void swift_initRawStructMetadata(StructMetadata *self,
10461046
const TypeLayout *likeType,
10471047
int32_t count);
10481048

1049+
/// Check if the given generic arguments are valid inputs for the generic type
1050+
/// context and if so call the metadata access function and return the metadata.
1051+
///
1052+
/// Note: This expects the caller to heap allocate all pack pointers within the
1053+
/// generic arguments via 'swift_allocateMetadataPack'.
1054+
SWIFT_RUNTIME_STDLIB_SPI
1055+
SWIFT_CC(swift)
1056+
const Metadata *_swift_instantiateCheckedGenericMetadata(
1057+
const TypeContextDescriptor *context,
1058+
const void * const *genericArgs,
1059+
size_t genericArgsSize);
1060+
10491061
#pragma clang diagnostic pop
10501062

10511063
} // end namespace swift

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2830,6 +2830,41 @@ swift_getOpaqueTypeConformance(const void * const *arguments,
28302830
arguments, static_cast<const OpaqueTypeDescriptor *>(descriptor), index);
28312831
}
28322832

2833+
SWIFT_RUNTIME_STDLIB_SPI
2834+
SWIFT_CC(swift)
2835+
const Metadata *swift::_swift_instantiateCheckedGenericMetadata(
2836+
const TypeContextDescriptor *context,
2837+
const void * const *genericArgs,
2838+
size_t genericArgsSize) {
2839+
context = swift_auth_data_non_address(
2840+
context, SpecialPointerAuthDiscriminators::ContextDescriptor);
2841+
2842+
if (!context->isGeneric()) {
2843+
return nullptr;
2844+
}
2845+
2846+
DemanglerForRuntimeTypeResolution<StackAllocatedDemangler<2048>> demangler;
2847+
2848+
llvm::ArrayRef<MetadataOrPack> genericArgsRef(
2849+
reinterpret_cast<const MetadataOrPack *>(genericArgs), genericArgsSize);
2850+
llvm::SmallVector<unsigned, 8> genericParamCounts;
2851+
llvm::SmallVector<const void *, 8> allGenericArgs;
2852+
2853+
auto result = _gatherGenericParameters(context, genericArgsRef,
2854+
/* parent */ nullptr,
2855+
genericParamCounts, allGenericArgs,
2856+
demangler);
2857+
2858+
// _gatherGenericParameters returns llvm::None on success.
2859+
if (result.hasValue()) {
2860+
return nullptr;
2861+
}
2862+
2863+
auto accessFunction = context->getAccessFunction();
2864+
2865+
return accessFunction(MetadataState::Complete, allGenericArgs).Value;
2866+
}
2867+
28332868
#if SWIFT_OBJC_INTEROP
28342869

28352870
// Return the ObjC class for the given type name.

test/Runtime/check_create_type.swift

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking)
2+
// REQUIRES: executable_test
3+
4+
// UNSUPPORTED: CPU=arm64e
5+
// UNSUPPORTED: use_os_stdlib
6+
// UNSUPPORTED: back_deployment_runtime
7+
8+
import StdlibUnittest
9+
10+
let testSuite = TestSuite("CheckedCreateType")
11+
12+
struct Variadic<each T> {
13+
struct Nested<U, each V: Equatable> {}
14+
}
15+
16+
@_silgen_name("swift_allocateMetadataPack")
17+
func allocateMetadataPack(
18+
_ packPointer: UnsafeRawPointer,
19+
_ packCount: UInt
20+
) -> UnsafeRawPointer
21+
22+
@_silgen_name("_swift_instantiateCheckedGenericMetadata")
23+
func _instantiateCheckedGenericMetadata(
24+
_ descriptor: UnsafeRawPointer,
25+
_ genericArgs: UnsafeRawPointer,
26+
_ genericArgsSize: UInt
27+
) -> Any.Type?
28+
29+
func metaPointer(_ x: Any.Type) -> UnsafeRawPointer {
30+
unsafeBitCast(x, to: UnsafeRawPointer.self)
31+
}
32+
33+
testSuite.test("_swift_checkedCreateType non-variadic") {
34+
let dictMeta = unsafeBitCast(
35+
[Int: Int].self as Any.Type,
36+
to: UnsafeRawPointer.self
37+
)
38+
let dictDesc = dictMeta.load(
39+
fromByteOffset: MemoryLayout<Int>.size,
40+
as: UnsafeRawPointer.self
41+
)
42+
43+
let dictGenericArgs: [Any.Type] = [String.self, Double.self]
44+
45+
dictGenericArgs.withUnsafeBufferPointer {
46+
let newDict = _instantiateCheckedGenericMetadata(
47+
dictDesc,
48+
UnsafeRawPointer($0.baseAddress!),
49+
UInt($0.count)
50+
)
51+
52+
expectTrue(newDict == [String: Double].self)
53+
}
54+
}
55+
56+
testSuite.test("_swift_checkedCreateType variadic") {
57+
let variMeta = unsafeBitCast(
58+
Variadic< >.self as Any.Type,
59+
to: UnsafeRawPointer.self
60+
)
61+
let variDesc = variMeta.load(
62+
fromByteOffset: MemoryLayout<Int>.size,
63+
as: UnsafeRawPointer.self
64+
)
65+
66+
let variPack: [Any.Type] = [Int.self, Int8.self, UInt8.self]
67+
68+
variPack.withUnsafeBufferPointer { pack in
69+
let packPointer = allocateMetadataPack(
70+
UnsafeRawPointer(pack.baseAddress!),
71+
UInt(pack.count)
72+
)
73+
let genericArgs = [packPointer]
74+
75+
genericArgs.withUnsafeBufferPointer { genericArgs in
76+
let newVari = _instantiateCheckedGenericMetadata(
77+
variDesc,
78+
UnsafeRawPointer(genericArgs.baseAddress!),
79+
UInt(genericArgs.count)
80+
)
81+
82+
expectTrue(newVari == Variadic<Int, Int8, UInt8>.self)
83+
}
84+
}
85+
}
86+
87+
testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
88+
let nestedMeta = unsafeBitCast(
89+
Variadic< >.Nested<()>.self as Any.Type,
90+
to: UnsafeRawPointer.self
91+
)
92+
let nestedDesc = nestedMeta.load(
93+
fromByteOffset: MemoryLayout<Int>.size,
94+
as: UnsafeRawPointer.self
95+
)
96+
97+
let variPack: [Any.Type] = [String.self, [Int].self, UInt64.self]
98+
99+
let nestedPack: [Any.Type] = [Int.self, Substring.self, Bool.self]
100+
101+
nestedPack.withUnsafeBufferPointer { nestedPack in
102+
variPack.withUnsafeBufferPointer { variPack in
103+
let nestedGenericArgs = [
104+
allocateMetadataPack(
105+
UnsafeRawPointer(variPack.baseAddress!),
106+
UInt(variPack.count)
107+
),
108+
metaPointer(Int16.self),
109+
allocateMetadataPack(
110+
UnsafeRawPointer(nestedPack.baseAddress!),
111+
UInt(nestedPack.count)
112+
)
113+
]
114+
115+
nestedGenericArgs.withUnsafeBufferPointer { nestedGenericArgs in
116+
117+
let newNested = _instantiateCheckedGenericMetadata(
118+
nestedDesc,
119+
UnsafeRawPointer(nestedGenericArgs.baseAddress!),
120+
UInt(nestedGenericArgs.count)
121+
)
122+
123+
expectTrue(newNested == Variadic<String, [Int], UInt64>.Nested<Int16, Int, Substring, Bool>.self)
124+
}
125+
}
126+
}
127+
}
128+
129+
runAllTests()

0 commit comments

Comments
 (0)