Skip to content

Commit 5f58b26

Browse files
committed
Use GenericSignature::getSubstitutions() in AttributeChecker::visitSpecializeAttr.
Rather than implement an ad hoc version of GenericSignature::getSubstitutions(), walk the requirements enough to check the validity of the @_specialize attribute and then use GenericSignature::getSubstitutions() to actually form the resulting substitutions. One less place in the code where we depend on witness markers.
1 parent 3161a77 commit 5f58b26

File tree

1 file changed

+50
-56
lines changed

1 file changed

+50
-56
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 50 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1417,65 +1417,59 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
14171417
}
14181418
// Initialize each TypeLoc in this attribute with a concrete type,
14191419
// and populate a substitution map from GenericTypeParamType to concrete Type.
1420-
TypeSubstitutionMap subMap;
1420+
SubstitutionMap subMap;
14211421
for (unsigned paramIdx = 0; paramIdx < numTypes; ++paramIdx) {
14221422

14231423
auto *genericTypeParamTy = genericSig->getGenericParams()[paramIdx];
14241424
auto &tl = attr->getTypeLocs()[paramIdx];
14251425

14261426
auto ty = TC.resolveType(tl.getTypeRepr(), DC, None);
1427-
if (ty && !ty->hasError()) {
1428-
if (ty->getCanonicalType()->hasArchetype()) {
1429-
TC.diagnose(attr->getLocation(),
1430-
diag::cannot_partially_specialize_generic_function);
1431-
return;
1432-
}
1433-
tl.setType(ty, /*validated=*/true);
1434-
subMap[genericTypeParamTy->getCanonicalType().getPointer()] = ty;
1427+
if (!ty || ty->hasError()) {
1428+
attr->setInvalid();
1429+
return;
1430+
}
1431+
1432+
if (ty->getCanonicalType()->hasArchetype()) {
1433+
TC.diagnose(attr->getLocation(),
1434+
diag::cannot_partially_specialize_generic_function);
1435+
attr->setInvalid();
1436+
return;
14351437
}
1438+
1439+
tl.setType(ty, /*validated=*/true);
1440+
subMap.addSubstitution(genericTypeParamTy->getCanonicalType(), ty);
14361441
}
1437-
// Build a list of Substitutions.
1438-
//
1439-
// This walks the generic signature's requirements, similar to
1440-
// Solution::computeSubstitutions but with several differences:
1441-
// - It does not operate within the type constraint system.
1442-
// - This is the first point at which diagnostics must be emitted for
1443-
// bad conformances. Self and super requirements must also be
1444-
// checked and diagnosed.
1445-
// - This does not make use of Archetypes since it is directly substituting
1446-
// in place of GenericTypeParams.
1447-
//
1448-
// FIXME: Refactor to use GenericSignature->getSubstitutions()?
1449-
SmallVector<Substitution, 4> substitutions;
1450-
auto currentModule = FD->getParentModule();
1451-
Type currentFromTy;
1452-
Type currentReplacement;
1442+
1443+
// Capture the conformances needed for the substitution map.
1444+
CanType currentType;
14531445
SmallVector<ProtocolConformanceRef, 4> currentConformances;
1446+
auto flushConformances = [&] {
1447+
subMap.addConformances(currentType,
1448+
TC.Context.AllocateCopy(currentConformances));
1449+
currentConformances.clear();
1450+
};
1451+
14541452
for (const auto &req : genericSig->getRequirements()) {
1453+
// If we're on to a new dependent type, flush the conformances gathered
1454+
// thus far.
1455+
CanType canFirstType = req.getFirstType()->getCanonicalType();
1456+
if (req.getKind() != RequirementKind::WitnessMarker &&
1457+
canFirstType != currentType) {
1458+
if (currentType) flushConformances();
1459+
currentType = canFirstType;
1460+
}
14551461

14561462
switch (req.getKind()) {
14571463
case RequirementKind::WitnessMarker:
1458-
// Flush the current conformances.
1459-
if (currentFromTy) {
1460-
substitutions.push_back({
1461-
currentReplacement,
1462-
DC->getASTContext().AllocateCopy(currentConformances)
1463-
});
1464-
currentConformances.clear();
1465-
}
1466-
// Each witness marker starts a new substitution.
1467-
currentFromTy = req.getFirstType();
1468-
currentReplacement = currentFromTy.subst(currentModule, subMap, None);
14691464
break;
14701465

14711466
case RequirementKind::Conformance: {
1472-
assert(currentFromTy->getCanonicalType()
1473-
== req.getFirstType()->getCanonicalType() && "bad WitnessMarker");
14741467
// Get the conformance and record it.
1468+
auto firstType = req.getFirstType().subst(subMap);
14751469
auto protoType = req.getSecondType()->castTo<ProtocolType>();
14761470
ProtocolConformance *conformance = nullptr;
14771471
bool conforms =
1478-
TC.conformsToProtocol(currentReplacement,
1472+
TC.conformsToProtocol(firstType,
14791473
protoType->getDecl(),
14801474
DC,
14811475
(ConformanceCheckFlags::InExpression|
@@ -1484,47 +1478,47 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
14841478
if (!conforms || !conformance) {
14851479
TC.diagnose(attr->getLocation(),
14861480
diag::cannot_convert_argument_value_protocol,
1487-
currentReplacement, protoType);
1488-
// leaks prior conformances
1481+
firstType, protoType);
1482+
attr->setInvalid();
14891483
return;
14901484
}
1491-
currentConformances.push_back(
1492-
ProtocolConformanceRef(protoType->getDecl(), conformance));
1485+
1486+
currentConformances.push_back(ProtocolConformanceRef(conformance));
14931487
break;
14941488
}
14951489
case RequirementKind::Superclass: {
14961490
// Superclass requirements aren't recorded in substitutions.
1497-
auto firstTy = req.getFirstType().subst(currentModule, subMap, None);
1498-
auto superTy = req.getSecondType().subst(currentModule, subMap, None);
1491+
auto firstTy = req.getFirstType().subst(subMap);
1492+
auto superTy = req.getSecondType().subst(subMap);
14991493
if (!TC.isSubtypeOf(firstTy, superTy, DC)) {
15001494
TC.diagnose(attr->getLocation(), diag::type_does_not_inherit,
15011495
FD->getInterfaceType(), firstTy, superTy);
1496+
attr->setInvalid();
1497+
return;
15021498
}
15031499
break;
15041500
}
15051501
case RequirementKind::SameType: {
15061502
// Same-type requirements are type checked but not recorded in
15071503
// substitutions.
1508-
auto firstTy = req.getFirstType().subst(currentModule, subMap, None);
1509-
auto sameTy = req.getSecondType().subst(currentModule, subMap, None);
1504+
auto firstTy = req.getFirstType().subst(subMap);
1505+
auto sameTy = req.getSecondType().subst(subMap);
15101506
if (!firstTy->isEqual(sameTy)) {
15111507
TC.diagnose(attr->getLocation(), diag::types_not_equal,
15121508
FD->getInterfaceType(), firstTy, sameTy);
1513-
1509+
attr->setInvalid();
15141510
return;
15151511
}
15161512
break;
15171513
}
15181514
}
15191515
}
1520-
// Flush the final conformances.
1521-
if (currentFromTy) {
1522-
substitutions.push_back({
1523-
currentReplacement,
1524-
DC->getASTContext().AllocateCopy(currentConformances),
1525-
});
1526-
currentConformances.clear();
1527-
}
1516+
if (currentType) flushConformances();
1517+
1518+
// Compute the substitutions.
1519+
SmallVector<Substitution, 4> substitutions;
1520+
genericSig->getSubstitutions(*FD->getParentModule(), subMap, substitutions);
1521+
15281522
// Package the Substitution list in the SpecializeAttr's ConcreteDeclRef.
15291523
attr->setConcreteDecl(
15301524
ConcreteDeclRef(DC->getASTContext(), FD, substitutions));

0 commit comments

Comments
 (0)