Skip to content

Commit f1dba0e

Browse files
committed
[Generic signature builder] Substitute requirements instead of threading a PA around.
This essentially undoes the implementation in 51da51d, which implicitly did a substitution of the Self type in a protocol's requirement signature by threading around the replacement PA. This is brittle because every part of the code needs to take and pass around the argument. By preemptively substituting, the whole requirement is in the right form from the time it enters `addRequirement`. The infrastructure here also allows simplifying some code.
1 parent dd597cc commit f1dba0e

File tree

3 files changed

+69
-66
lines changed

3 files changed

+69
-66
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ class GenericSignatureBuilder {
172172
/// requirement mismatch.
173173
bool addSameTypeRequirement(
174174
Type T1, Type T2, RequirementSource Source,
175-
PotentialArchetype *basePA,
176175
llvm::function_ref<void(Type, Type)> diagnoseMismatch);
177176

178177
/// Add the requirements placed on the given abstract type parameter
@@ -258,7 +257,6 @@ class GenericSignatureBuilder {
258257
bool addRequirement(const Requirement &req, RequirementSource source);
259258

260259
bool addRequirement(const Requirement &req, RequirementSource source,
261-
PotentialArchetype *basePA,
262260
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited);
263261

264262
bool addLayoutRequirement(PotentialArchetype *PAT,
@@ -323,12 +321,7 @@ class GenericSignatureBuilder {
323321
/// signature are fully resolved).
324322
///
325323
/// For any type that cannot refer to an archetype, this routine returns null.
326-
///
327-
/// A non-null \c basePA is used in place of the "true" potential archetype
328-
/// for a GenericTypeParamType, effectively performing a substitution like,
329-
/// e.g., Self = <some PA>.
330-
PotentialArchetype *resolveArchetype(Type type,
331-
PotentialArchetype *basePA = nullptr);
324+
PotentialArchetype *resolveArchetype(Type type);
332325

333326
/// \brief Dump all of the requirements, both specified and inferred.
334327
LLVM_ATTRIBUTE_DEPRECATED(

include/swift/AST/Requirement.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,31 @@ class Requirement {
8686
return SecondType;
8787
}
8888

89+
/// \brief Subst the types involved in this requirement.
90+
///
91+
/// The \c args arguments are passed through to Type::subst. This doesn't
92+
/// touch the superclasses, protocols or layout constraints.
93+
template <typename... Args>
94+
Optional<Requirement> subst(Args &&... args) const {
95+
auto newFirst = getFirstType().subst(std::forward<Args>(args)...);
96+
if (!newFirst)
97+
return None;
98+
99+
switch (getKind()) {
100+
case RequirementKind::SameType: {
101+
auto newSecond = getSecondType().subst(std::forward<Args>(args)...);
102+
if (!newSecond)
103+
return None;
104+
return Requirement(getKind(), newFirst, newSecond);
105+
}
106+
case RequirementKind::Conformance:
107+
case RequirementKind::Superclass:
108+
return Requirement(getKind(), newFirst, getSecondType());
109+
case RequirementKind::Layout:
110+
return Requirement(getKind(), newFirst, getLayoutConstraint());
111+
}
112+
}
113+
89114
/// \brief Retrieve the layout constraint.
90115
LayoutConstraint getLayoutConstraint() const {
91116
assert(getKind() == RequirementKind::Layout);

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 43 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,12 +1019,8 @@ LazyResolver *GenericSignatureBuilder::getLazyResolver() const {
10191019
return Context.getLazyResolver();
10201020
}
10211021

1022-
auto GenericSignatureBuilder::resolveArchetype(Type type, PotentialArchetype *basePA)
1023-
-> PotentialArchetype * {
1022+
auto GenericSignatureBuilder::resolveArchetype(Type type) -> PotentialArchetype * {
10241023
if (auto genericParam = type->getAs<GenericTypeParamType>()) {
1025-
if (basePA)
1026-
return basePA;
1027-
10281024
unsigned index = GenericParamKey(genericParam).findIndexIn(
10291025
Impl->GenericParams);
10301026
if (index < Impl->GenericParams.size())
@@ -1034,7 +1030,7 @@ auto GenericSignatureBuilder::resolveArchetype(Type type, PotentialArchetype *ba
10341030
}
10351031

10361032
if (auto dependentMember = type->getAs<DependentMemberType>()) {
1037-
auto base = resolveArchetype(dependentMember->getBase(), basePA);
1033+
auto base = resolveArchetype(dependentMember->getBase());
10381034
if (!base)
10391035
return nullptr;
10401036

@@ -1112,9 +1108,15 @@ bool GenericSignatureBuilder::addConformanceRequirement(PotentialArchetype *PAT,
11121108
if (Proto->isRequirementSignatureComputed()) {
11131109
auto reqSig = Proto->getRequirementSignature();
11141110

1115-
for (auto req : reqSig->getRequirements()) {
1111+
auto concreteSelf = T->getDependentType({}, /*allowUnresolved=*/true);
1112+
auto subMap = SubstitutionMap::getProtocolSubstitutions(
1113+
Proto, concreteSelf, ProtocolConformanceRef(Proto));
1114+
1115+
for (auto rawReq : reqSig->getRequirements()) {
1116+
auto req = rawReq.subst(subMap);
1117+
assert(req && "substituting Self in requirement shouldn't fail");
11161118
RequirementSource InnerSource(Kind, Source.getLoc());
1117-
addRequirement(req, InnerSource, T, Visited);
1119+
addRequirement(*req, InnerSource, Visited);
11181120
}
11191121
} else {
11201122
// Conformances to inherit protocols are explicit in a protocol requirement
@@ -1333,9 +1335,8 @@ bool GenericSignatureBuilder::addSameTypeRequirementBetweenArchetypes(
13331335
Type concrete2 = T2->getConcreteType();
13341336

13351337
if (concrete1 && concrete2) {
1336-
bool mismatch =
1337-
addSameTypeRequirement(concrete1, concrete2, Source, nullptr,
1338-
[&](Type type1, Type type2) {
1338+
bool mismatch = addSameTypeRequirement(
1339+
concrete1, concrete2, Source, [&](Type type1, Type type2) {
13391340
Diags.diagnose(Source.getLoc(),
13401341
diag::requires_same_type_conflict,
13411342
T1->getDependentType(/*FIXME: */{ }, true), type1,
@@ -1411,9 +1412,8 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
14111412
// If we've already been bound to a type, we're either done, or we have a
14121413
// problem.
14131414
if (auto oldConcrete = T->getConcreteType()) {
1414-
bool mismatch =
1415-
addSameTypeRequirement(oldConcrete, Concrete, Source, nullptr,
1416-
[&](Type type1, Type type2) {
1415+
bool mismatch = addSameTypeRequirement(
1416+
oldConcrete, Concrete, Source, [&](Type type1, Type type2) {
14171417
Diags.diagnose(Source.getLoc(),
14181418
diag::requires_same_type_conflict,
14191419
T->getDependentType(/*FIXME: */{ }, true), type1,
@@ -1486,30 +1486,25 @@ bool GenericSignatureBuilder::addSameTypeRequirementToConcrete(
14861486
}
14871487

14881488
bool GenericSignatureBuilder::addSameTypeRequirement(
1489-
Type type1, Type type2,
1490-
RequirementSource source,
1491-
PotentialArchetype *basePA,
1492-
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
1489+
Type type1, Type type2, RequirementSource source,
1490+
llvm::function_ref<void(Type, Type)> diagnoseMismatch) {
14931491
// Local class to handle matching the two sides of the same-type constraint.
14941492
class ReqTypeMatcher : public TypeMatcher<ReqTypeMatcher> {
14951493
GenericSignatureBuilder &builder;
14961494
RequirementSource source;
1497-
PotentialArchetype *basePA;
14981495
llvm::function_ref<void(Type, Type)> diagnoseMismatch;
14991496

15001497
public:
1501-
ReqTypeMatcher(GenericSignatureBuilder &builder,
1502-
RequirementSource source,
1503-
PotentialArchetype *basePA,
1498+
ReqTypeMatcher(GenericSignatureBuilder &builder, RequirementSource source,
15041499
llvm::function_ref<void(Type, Type)> diagnoseMismatch)
1505-
: builder(builder), source(source), basePA(basePA),
1506-
diagnoseMismatch(diagnoseMismatch) { }
1500+
: builder(builder), source(source), diagnoseMismatch(diagnoseMismatch) {
1501+
}
15071502

15081503
bool mismatch(TypeBase *firstType, TypeBase *secondType,
15091504
Type sugaredFirstType) {
15101505
// Find the potential archetypes.
1511-
PotentialArchetype *pa1 = builder.resolveArchetype(firstType, basePA);
1512-
PotentialArchetype *pa2 = builder.resolveArchetype(secondType, basePA);
1506+
PotentialArchetype *pa1 = builder.resolveArchetype(firstType);
1507+
PotentialArchetype *pa2 = builder.resolveArchetype(secondType);
15131508

15141509
// If both sides of the requirement are type parameters, equate them.
15151510
if (pa1 && pa2)
@@ -1527,7 +1522,7 @@ bool GenericSignatureBuilder::addSameTypeRequirement(
15271522
diagnoseMismatch(sugaredFirstType, secondType);
15281523
return false;
15291524
}
1530-
} matcher(*this, source, basePA, diagnoseMismatch);
1525+
} matcher(*this, source, diagnoseMismatch);
15311526

15321527
return !matcher.match(type1, type2);
15331528
}
@@ -1697,17 +1692,16 @@ bool GenericSignatureBuilder::addRequirement(const RequirementRepr &Req) {
16971692
bool GenericSignatureBuilder::addRequirement(const Requirement &req,
16981693
RequirementSource source) {
16991694
llvm::SmallPtrSet<ProtocolDecl *, 8> Visited;
1700-
return addRequirement(req, source, nullptr, Visited);
1695+
return addRequirement(req, source, Visited);
17011696
}
17021697

17031698
bool GenericSignatureBuilder::addRequirement(
17041699
const Requirement &req, RequirementSource source,
1705-
PotentialArchetype *basePA,
17061700
llvm::SmallPtrSetImpl<ProtocolDecl *> &Visited) {
17071701
switch (req.getKind()) {
17081702
case RequirementKind::Superclass: {
17091703
// FIXME: Diagnose this.
1710-
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
1704+
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
17111705
if (!pa) return false;
17121706

17131707
assert(req.getSecondType()->getClassOrBoundGenericClass());
@@ -1716,15 +1710,15 @@ bool GenericSignatureBuilder::addRequirement(
17161710

17171711
case RequirementKind::Layout: {
17181712
// FIXME: Diagnose this.
1719-
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
1713+
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
17201714
if (!pa) return false;
17211715

17221716
return addLayoutRequirement(pa, req.getLayoutConstraint(), source);
17231717
}
17241718

17251719
case RequirementKind::Conformance: {
17261720
// FIXME: Diagnose this.
1727-
PotentialArchetype *pa = resolveArchetype(req.getFirstType(), basePA);
1721+
PotentialArchetype *pa = resolveArchetype(req.getFirstType());
17281722
if (!pa) return false;
17291723

17301724
SmallVector<ProtocolDecl *, 4> conformsTo;
@@ -1744,7 +1738,7 @@ bool GenericSignatureBuilder::addRequirement(
17441738

17451739
case RequirementKind::SameType:
17461740
return addSameTypeRequirement(
1747-
req.getFirstType(), req.getSecondType(), source, basePA,
1741+
req.getFirstType(), req.getSecondType(), source,
17481742
[&](Type type1, Type type2) {
17491743
if (source.getLoc().isValid())
17501744
Diags.diagnose(source.getLoc(),
@@ -1804,25 +1798,21 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
18041798

18051799
// Handle the requirements.
18061800
RequirementSource source(RequirementSource::Inferred, Loc);
1807-
for (const auto &req : genericSig->getRequirements()) {
1808-
switch (req.getKind()) {
1809-
case RequirementKind::SameType: {
1810-
auto firstType = req.getFirstType().subst(
1811-
getTypeSubstitution,
1812-
Builder.getLookupConformanceFn());
1813-
if (!firstType)
1814-
break;
1801+
for (const auto &rawReq : genericSig->getRequirements()) {
1802+
auto req =
1803+
rawReq.subst(getTypeSubstitution, Builder.getLookupConformanceFn());
1804+
if (!req)
1805+
continue;
18151806

1807+
switch (req->getKind()) {
1808+
case RequirementKind::SameType: {
1809+
auto firstType = req->getFirstType();
18161810
auto firstPA = Builder.resolveArchetype(firstType);
18171811

18181812
if (firstPA && isOuterArchetype(firstPA))
18191813
return Action::Continue;
18201814

1821-
auto secondType = req.getSecondType().subst(
1822-
getTypeSubstitution,
1823-
Builder.getLookupConformanceFn());
1824-
if (!secondType)
1825-
break;
1815+
auto secondType = req->getSecondType();
18261816
auto secondPA = Builder.resolveArchetype(secondType);
18271817

18281818
if (firstPA && secondPA) {
@@ -1843,12 +1833,7 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
18431833
case RequirementKind::Superclass:
18441834
case RequirementKind::Layout:
18451835
case RequirementKind::Conformance: {
1846-
auto subjectType = req.getFirstType().subst(
1847-
getTypeSubstitution,
1848-
Builder.getLookupConformanceFn());
1849-
if (!subjectType)
1850-
break;
1851-
1836+
auto subjectType = req->getFirstType();
18521837
auto subjectPA = Builder.resolveArchetype(subjectType);
18531838
if (!subjectPA) {
18541839
break;
@@ -1857,19 +1842,19 @@ class GenericSignatureBuilder::InferRequirementsWalker : public TypeWalker {
18571842
if (isOuterArchetype(subjectPA))
18581843
return Action::Continue;
18591844

1860-
if (req.getKind() == RequirementKind::Conformance) {
1861-
auto proto = req.getSecondType()->castTo<ProtocolType>();
1845+
if (req->getKind() == RequirementKind::Conformance) {
1846+
auto proto = req->getSecondType()->castTo<ProtocolType>();
18621847
if (Builder.addConformanceRequirement(subjectPA, proto->getDecl(),
18631848
source)) {
18641849
return Action::Stop;
18651850
}
1866-
} else if (req.getKind() == RequirementKind::Layout) {
1867-
if (Builder.addLayoutRequirement(subjectPA, req.getLayoutConstraint(),
1868-
source)) {
1851+
} else if (req->getKind() == RequirementKind::Layout) {
1852+
if (Builder.addLayoutRequirement(
1853+
subjectPA, req->getLayoutConstraint(), source)) {
18691854
return Action::Stop;
18701855
}
18711856
} else {
1872-
if (Builder.addSuperclassRequirement(subjectPA, req.getSecondType(),
1857+
if (Builder.addSuperclassRequirement(subjectPA, req->getSecondType(),
18731858
source)) {
18741859
return Action::Stop;
18751860
}

0 commit comments

Comments
 (0)