Skip to content

Commit a410885

Browse files
committed
Teach _gatherGenericParameters to handle only key arguments
1 parent 8cfcc24 commit a410885

File tree

4 files changed

+147
-23
lines changed

4 files changed

+147
-23
lines changed

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,20 @@ _gatherGenericParameters(const ContextDescriptor *context,
12401240
};
12411241
};
12421242

1243+
auto generics = context->getGenericContext();
1244+
unsigned numOfKeyArgs = 0;
1245+
auto hasOnlyKeyArgs = false;
1246+
1247+
if (generics) {
1248+
for (auto genericParam : generics->getGenericParams()) {
1249+
if (genericParam.hasKeyArgument()) {
1250+
numOfKeyArgs += 1;
1251+
}
1252+
}
1253+
1254+
hasOnlyKeyArgs = genericArgs.size() == numOfKeyArgs;
1255+
}
1256+
12431257
// Figure out the various levels of generic parameters we have in
12441258
// this type.
12451259
(void)_gatherGenericParameterCounts(context,
@@ -1252,6 +1266,8 @@ _gatherGenericParameters(const ContextDescriptor *context,
12521266
// Okay: genericArgs is the innermost set of generic arguments.
12531267
} else if (genericArgs.size() == numTotalGenericParams && !parent) {
12541268
// Okay: genericArgs is the complete set of generic arguments.
1269+
} else if (hasOnlyKeyArgs) {
1270+
// Okay: geneircArgs is the set of key generic arguments.
12551271
} else {
12561272
auto commonString = makeCommonErrorStringGetter();
12571273
auto genericArgsSize = genericArgs.size();
@@ -1263,7 +1279,7 @@ _gatherGenericParameters(const ContextDescriptor *context,
12631279
" total params";
12641280
});
12651281
}
1266-
1282+
12671283
// If there are generic parameters at any level, check the generic
12681284
// requirements and fill in the generic arguments vector.
12691285
if (!genericParamCounts.empty()) {
@@ -1280,10 +1296,11 @@ _gatherGenericParameters(const ContextDescriptor *context,
12801296
allGenericArgs.insert(allGenericArgs.end(),
12811297
genericArgs.begin(), genericArgs.end());
12821298

1299+
assert(generics);
1300+
auto genericParams = generics->getGenericParams();
1301+
12831302
// Copy the generic arguments needed for metadata from the generic
12841303
// arguments "as written".
1285-
auto generics = context->getGenericContext();
1286-
assert(generics);
12871304
{
12881305
// Add a placeholder length for each shape class.
12891306
auto packShapeHeader = generics->getGenericPackShapeHeader();
@@ -1292,24 +1309,31 @@ _gatherGenericParameters(const ContextDescriptor *context,
12921309
allGenericArgsVec.resize(packShapeHeader.NumShapeClasses);
12931310
}
12941311

1295-
// If we have the wrong number of generic arguments, fail.
1296-
auto genericParams = generics->getGenericParams();
1297-
unsigned n = genericParams.size();
1298-
if (allGenericArgs.size() != n) {
1312+
// If we don't have either the same number of parameter key arguments or
1313+
// the total number of generic parameters, fail.
1314+
if (allGenericArgs.size() != numOfKeyArgs &&
1315+
allGenericArgs.size() != genericParams.size()) {
12991316
auto commonString = makeCommonErrorStringGetter();
13001317
auto argsVecSize = allGenericArgsVec.size();
13011318
return TypeLookupError([=] {
13021319
return commonString() + "have " + std::to_string(argsVecSize) +
1303-
"generic args, expected " + std::to_string(n);
1320+
"generic args, expected at least " + std::to_string(numOfKeyArgs);
13041321
});
13051322
}
13061323

13071324
// Add metadata for each canonical generic parameter.
13081325
auto packShapeDescriptors = generics->getGenericPackShapeDescriptors();
13091326
unsigned packIdx = 0;
13101327

1311-
for (unsigned i = 0; i != n; ++i) {
1312-
const auto &param = genericParams[i];
1328+
// Increments by 1 every iteration if we have all generic arguments, or
1329+
// only increments by 1 everytime we see a key argument.
1330+
unsigned i = 0;
1331+
1332+
for (auto &param : genericParams) {
1333+
if (hasOnlyKeyArgs && !param.hasKeyArgument()) {
1334+
continue;
1335+
}
1336+
13131337
auto arg = allGenericArgs[i];
13141338

13151339
switch (param.getKind()) {
@@ -1364,6 +1388,10 @@ _gatherGenericParameters(const ContextDescriptor *context,
13641388
std::to_string(static_cast<uint8_t>(param.getKind()));
13651389
});
13661390
}
1391+
1392+
if ((hasOnlyKeyArgs && param.hasKeyArgument()) || !hasOnlyKeyArgs) {
1393+
i += 1;
1394+
}
13671395
}
13681396
}
13691397

@@ -1378,7 +1406,7 @@ _gatherGenericParameters(const ContextDescriptor *context,
13781406
},
13791407
[&substitutions](const Metadata *type, unsigned index) {
13801408
return substitutions.getWitnessTable(type, index);
1381-
});
1409+
}, /* allowsUnresolvedSubject */ hasOnlyKeyArgs);
13821410
if (error)
13831411
return *error;
13841412

stdlib/public/runtime/Private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,8 @@ class TypeInfo {
523523
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
524524
llvm::SmallVectorImpl<const void *> &extraArguments,
525525
SubstGenericParameterFn substGenericParam,
526-
SubstDependentWitnessTableFn substWitnessTable);
526+
SubstDependentWitnessTableFn substWitnessTable,
527+
bool allowsUnresolvedSubject = false);
527528

528529
/// A helper function which avoids performing a store if the destination
529530
/// address already contains the source value. This is useful when

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1344,24 +1344,37 @@ static llvm::Optional<TypeLookupError>
13441344
checkGenericRequirement(const GenericRequirementDescriptor &req,
13451345
llvm::SmallVectorImpl<const void *> &extraArguments,
13461346
SubstGenericParameterFn substGenericParam,
1347-
SubstDependentWitnessTableFn substWitnessTable) {
1347+
SubstDependentWitnessTableFn substWitnessTable,
1348+
bool allowsUnresolvedSubject) {
13481349
assert(!req.getFlags().isPackRequirement());
13491350

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

1355+
const Metadata *subjectType = nullptr;
1356+
13541357
// Resolve the subject generic parameter.
13551358
auto result = swift_getTypeByMangledName(
13561359
MetadataState::Abstract, req.getParam(), extraArguments.data(),
13571360
substGenericParam, substWitnessTable);
1358-
if (result.getError())
1361+
1362+
if (!allowsUnresolvedSubject && result.isError()) {
13591363
return *result.getError();
1360-
const Metadata *subjectType = result.getType().getMetadata();
1364+
}
1365+
1366+
if (!result.isError()) {
1367+
subjectType = result.getType().getMetadata();
1368+
}
13611369

13621370
// Check the requirement.
13631371
switch (req.getKind()) {
13641372
case GenericRequirementKind::Protocol: {
1373+
// Protocol requirements _require_ a subject type.
1374+
if (result.isError()) {
1375+
return *result.getError();
1376+
}
1377+
13651378
const WitnessTable *witnessTable = nullptr;
13661379
if (!_conformsToProtocol(nullptr, subjectType, req.getProtocol(),
13671380
&witnessTable)) {
@@ -1382,16 +1395,37 @@ checkGenericRequirement(const GenericRequirementDescriptor &req,
13821395
}
13831396

13841397
case GenericRequirementKind::SameType: {
1398+
// Same type requirements don't require a valid subject.
1399+
1400+
const Metadata *sameType = nullptr;
1401+
13851402
// Demangle the second type under the given substitutions.
13861403
auto result = swift_getTypeByMangledName(
13871404
MetadataState::Abstract, req.getMangledTypeName(),
13881405
extraArguments.data(), substGenericParam, substWitnessTable);
1389-
if (result.getError())
1406+
1407+
if (!allowsUnresolvedSubject && result.isError()) {
13901408
return *result.getError();
1391-
auto otherType = result.getType().getMetadata();
1409+
}
1410+
1411+
if (!result.isError()) {
1412+
sameType = result.getType().getMetadata();
1413+
}
1414+
1415+
// If we don't have one of either the subject type or the same type and we
1416+
// have the other, then return this as a success. This assumes the given
1417+
// extra arguments have provided only the required key arguments in which
1418+
// case some same type constraints may concretize some generic arguments
1419+
// making them non-key.
1420+
//
1421+
// Note: We don't need to check for allowsUnresolvedSubject here because
1422+
// these can only be null in the case where we do allow it.
1423+
if ((!subjectType && sameType) || (subjectType && !sameType)) {
1424+
return llvm::None;
1425+
}
13921426

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

14041438
case GenericRequirementKind::Layout: {
1439+
// Layout requirements _require_ a subject type.
1440+
if (result.isError()) {
1441+
return *result.getError();
1442+
}
1443+
14051444
return satisfiesLayoutConstraint(req, subjectType);
14061445
}
14071446

14081447
case GenericRequirementKind::BaseClass: {
1448+
// Base class requirements _require_ a subject type.
1449+
if (result.isError()) {
1450+
return *result.getError();
1451+
}
1452+
14091453
// Demangle the base type under the given substitutions.
14101454
auto result = swift_getTypeByMangledName(
14111455
MetadataState::Abstract, req.getMangledTypeName(),
@@ -1594,7 +1638,8 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
15941638
llvm::ArrayRef<GenericRequirementDescriptor> requirements,
15951639
llvm::SmallVectorImpl<const void *> &extraArguments,
15961640
SubstGenericParameterFn substGenericParam,
1597-
SubstDependentWitnessTableFn substWitnessTable) {
1641+
SubstDependentWitnessTableFn substWitnessTable,
1642+
bool allowsUnresolvedSubject) {
15981643
for (const auto &req : requirements) {
15991644
if (req.getFlags().isPackRequirement()) {
16001645
auto error = checkGenericPackRequirement(req, extraArguments,
@@ -1605,7 +1650,8 @@ llvm::Optional<TypeLookupError> swift::_checkGenericRequirements(
16051650
} else {
16061651
auto error = checkGenericRequirement(req, extraArguments,
16071652
substGenericParam,
1608-
substWitnessTable);
1653+
substWitnessTable,
1654+
allowsUnresolvedSubject);
16091655
if (error)
16101656
return error;
16111657
}

test/Runtime/check_create_type.swift

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func metaPointer(_ x: Any.Type) -> UnsafeRawPointer {
3030
unsafeBitCast(x, to: UnsafeRawPointer.self)
3131
}
3232

33-
testSuite.test("_swift_checkedCreateType non-variadic") {
33+
testSuite.test("_swift_instantiateCheckedGenericMetadata non-variadic") {
3434
let dictMeta = unsafeBitCast(
3535
[Int: Int].self as Any.Type,
3636
to: UnsafeRawPointer.self
@@ -53,7 +53,7 @@ testSuite.test("_swift_checkedCreateType non-variadic") {
5353
}
5454
}
5555

56-
testSuite.test("_swift_checkedCreateType variadic") {
56+
testSuite.test("_swift_instantiateCheckedGenericMetadata variadic") {
5757
let variMeta = unsafeBitCast(
5858
Variadic< >.self as Any.Type,
5959
to: UnsafeRawPointer.self
@@ -84,7 +84,7 @@ testSuite.test("_swift_checkedCreateType variadic") {
8484
}
8585
}
8686

87-
testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
87+
testSuite.test("_swift_instantiateCheckedGenericMetadata variadic nested with requirements") {
8888
let nestedMeta = unsafeBitCast(
8989
Variadic< >.Nested<()>.self as Any.Type,
9090
to: UnsafeRawPointer.self
@@ -126,4 +126,53 @@ testSuite.test("_swift_checkedCreateType variadic nested with requirements") {
126126
}
127127
}
128128

129+
struct Generic<T> {}
130+
struct Generic2<T, U> {}
131+
132+
extension Generic where T == Int {
133+
struct Nested {}
134+
}
135+
136+
extension Generic2 where T == U? {
137+
struct Nested {}
138+
}
139+
140+
testSuite.test("_swift_instantiateCheckedGenericMetadata concrete generic types (same type conretized)") {
141+
let nestedMeta1 = metaPointer(Generic<Int>.Nested.self)
142+
let nestedDesc1 = nestedMeta1.load(
143+
fromByteOffset: MemoryLayout<Int>.size,
144+
as: UnsafeRawPointer.self
145+
)
146+
147+
let genericArgs1: [UnsafeRawPointer?] = []
148+
149+
genericArgs1.withUnsafeBufferPointer {
150+
let nested = _instantiateCheckedGenericMetadata(
151+
nestedDesc1,
152+
UnsafeRawPointer($0.baseAddress!),
153+
UInt($0.count)
154+
)
155+
156+
expectTrue(nested == Generic<Int>.Nested.self)
157+
}
158+
159+
let nestedMeta2 = metaPointer(Generic2<Int?, Int>.Nested.self)
160+
let nestedDesc2 = nestedMeta2.load(
161+
fromByteOffset: MemoryLayout<Int>.size,
162+
as: UnsafeRawPointer.self
163+
)
164+
165+
let genericArgs2 = [metaPointer(String.self)]
166+
167+
genericArgs2.withUnsafeBufferPointer {
168+
let nested = _instantiateCheckedGenericMetadata(
169+
nestedDesc2,
170+
UnsafeRawPointer($0.baseAddress!),
171+
UInt($0.count)
172+
)
173+
174+
expectTrue(nested == Generic2<String?, String>.Nested.self)
175+
}
176+
}
177+
129178
runAllTests()

0 commit comments

Comments
 (0)