Skip to content

Commit a487630

Browse files
committed
SILGen: Create new archetypes for witness thunks instead of using the conformance
Sema produces a weird mix of requirement and witness archetypes when it builds witness substitutions. Instead of hacking around this in SILGen, just build new archetypes, since we already have to use an ArchetypeBuilder to get the correct generic signature on the interface type. Then, we just have to map the witnessSubs provided by Sema to use our new archetypes. This unblocks some work on generic inlining. Fixes <rdar://problem/28765006>.
1 parent c547fc1 commit a487630

File tree

1 file changed

+66
-70
lines changed

1 file changed

+66
-70
lines changed

lib/SILGen/SILGenDecl.cpp

Lines changed: 66 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,13 +1689,11 @@ static bool isSelfDerived(Type selfTy, Type t) {
16891689
/// requirement's type to get the type of the witness.
16901690
static CanAnyFunctionType
16911691
substSelfTypeIntoProtocolRequirementType(SILModule &M,
1692+
GenericEnvironment *reqtEnv,
16921693
CanGenericFunctionType reqtTy,
1693-
ProtocolConformance *conformance) {
1694-
if (conformance == nullptr) {
1695-
// Default witness thunks just get the requirement type without
1696-
// substituting Self.
1697-
return reqtTy;
1698-
}
1694+
ProtocolConformance *conformance,
1695+
GenericEnvironment *&genericEnv,
1696+
SubstitutionMap &thunkSubs) {
16991697

17001698
auto &C = M.getASTContext();
17011699

@@ -1775,67 +1773,51 @@ substSelfTypeIntoProtocolRequirementType(SILModule &M,
17751773
auto input = reqtTy->getInput().subst(subs)->getCanonicalType();
17761774
auto result = reqtTy->getResult().subst(subs)->getCanonicalType();
17771775

1776+
CanAnyFunctionType reqtSubstTy;
1777+
17781778
// The result might be fully concrete, if the witness had no generic
17791779
// signature, and the requirement had no additional generic parameters
17801780
// beyond `Self`.
17811781
if (!allParams.empty()) {
17821782
builder.finalize(SourceLoc());
17831783

17841784
auto *sig = builder.getGenericSignature();
1785+
genericEnv = builder.getGenericEnvironment();
1786+
1787+
// Outer generic parameters come from the generic context of
1788+
// the conformance (which might not be the same as the generic
1789+
// context of the witness, if the witness is defined in a
1790+
// superclass, concrete extension or protocol extension).
1791+
if (auto *outerEnv = conformance->getGenericEnvironment()) {
1792+
for (auto pair : outerEnv->getArchetypeToInterfaceMap()) {
1793+
auto archetypeTy = pair.first->getCanonicalType();
1794+
auto substTy = pair.second;
1795+
auto contextTy = ArchetypeBuilder::mapTypeIntoContext(
1796+
M.getSwiftModule(), genericEnv, substTy);
1797+
thunkSubs.addSubstitution(archetypeTy, contextTy);
1798+
}
1799+
}
17851800

1786-
return cast<GenericFunctionType>(
1801+
reqtSubstTy = cast<GenericFunctionType>(
17871802
GenericFunctionType::get(sig, input, result, reqtTy->getExtInfo())
17881803
->getCanonicalType());
1789-
}
1790-
1791-
return CanFunctionType::get(input, result, reqtTy->getExtInfo());
1792-
}
1793-
1794-
static GenericEnvironment *
1795-
getSubstitutedGenericEnvironment(SILModule &M,
1796-
GenericEnvironment *reqtEnv,
1797-
CanGenericSignature witnessSig,
1798-
ProtocolConformance *conformance) {
1799-
if (conformance == nullptr) {
1800-
// Default witness thunks just use the context archetypes of the requirement.
1801-
return reqtEnv;
1802-
}
1803-
1804-
SmallVector<GenericTypeParamType *, 4> genericParamTypes;
1805-
TypeSubstitutionMap witnessContextParams;
1806-
1807-
auto selfTy = conformance->getProtocol()->getSelfInterfaceType()
1808-
->getCanonicalType();
1804+
} else {
1805+
genericEnv = nullptr;
18091806

1810-
// Outer generic parameters come from the generic context of
1811-
// the conformance (which might not be the same as the generic
1812-
// context of the witness, if the witness is defined in a
1813-
// superclass, concrete extension or protocol extension).
1814-
if (auto *outerEnv = conformance->getGenericEnvironment()) {
1815-
witnessContextParams = outerEnv->getInterfaceToArchetypeMap();
1816-
for (auto *paramTy : outerEnv->getGenericParams())
1817-
genericParamTypes.push_back(paramTy);
1807+
reqtSubstTy = CanFunctionType::get(input, result, reqtTy->getExtInfo());
18181808
}
18191809

1820-
for (auto *paramTy : reqtEnv->getGenericParams().slice(1))
1821-
genericParamTypes.push_back(paramTy);
1822-
18231810
// Inner generic parameters come from the requirement and
18241811
// also map to the archetypes of the requirement.
1825-
for (auto pair : reqtEnv->getInterfaceToArchetypeMap()) {
1826-
// Skip the 'Self' parameter and friends.
1827-
if (isSelfDerived(selfTy, pair.first))
1828-
continue;
1829-
1830-
auto result = witnessContextParams.insert(pair);
1831-
assert(result.second);
1812+
for (auto pair : reqtEnv->getArchetypeToInterfaceMap()) {
1813+
auto archetypeTy = pair.first->getCanonicalType();
1814+
auto substTy = pair.second.subst(subs);
1815+
auto contextTy = ArchetypeBuilder::mapTypeIntoContext(
1816+
M.getSwiftModule(), genericEnv, substTy);
1817+
thunkSubs.addSubstitution(archetypeTy, contextTy);
18321818
}
18331819

1834-
if (!witnessContextParams.empty())
1835-
return GenericEnvironment::get(M.getASTContext(), genericParamTypes,
1836-
witnessContextParams);
1837-
1838-
return nullptr;
1820+
return reqtSubstTy;
18391821
}
18401822

18411823
SILFunction *
@@ -1846,7 +1828,6 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
18461828
IsFreeFunctionWitness_t isFree,
18471829
ArrayRef<Substitution> witnessSubs) {
18481830
auto requirementInfo = Types.getConstantInfo(requirement);
1849-
auto witnessInfo = Types.getConstantInfo(witness);
18501831
unsigned witnessUncurryLevel = witness.uncurryLevel;
18511832

18521833
// If the witness is a free function, consider the self argument
@@ -1860,11 +1841,37 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
18601841
assert(requirement.uncurryLevel == witnessUncurryLevel &&
18611842
"uncurry level of requirement and witness do not match");
18621843

1844+
GenericEnvironment *genericEnv = nullptr;
1845+
18631846
// Work out the lowered function type of the SIL witness thunk.
18641847
auto reqtOrigTy
18651848
= cast<GenericFunctionType>(requirementInfo.LoweredInterfaceType);
1866-
auto reqtSubstTy
1867-
= substSelfTypeIntoProtocolRequirementType(M, reqtOrigTy, conformance);
1849+
CanAnyFunctionType reqtSubstTy;
1850+
if (conformance == nullptr) {
1851+
reqtSubstTy = reqtOrigTy;
1852+
genericEnv = requirementInfo.GenericEnv;
1853+
} else {
1854+
SubstitutionMap thunkSubs;
1855+
reqtSubstTy
1856+
= substSelfTypeIntoProtocolRequirementType(M, requirementInfo.GenericEnv,
1857+
reqtOrigTy, conformance,
1858+
genericEnv, thunkSubs);
1859+
1860+
// Remap witness substitutions to use the correct archetypes.
1861+
// Sema produces witness substitutions using a mix of archetypes
1862+
// from the requirement and the witness. To solve downstream
1863+
// issues in the SIL optimizer, we build all-new archetypes
1864+
// using the correct generic signature here.
1865+
//
1866+
// FIXME: Once Sema records witness substitutions in terms of
1867+
// interface types, this code as well as the code that builds
1868+
// thunkSubs in substSelfTypeIntoProtocolRequirementType() can
1869+
// be removed.
1870+
auto newWitnessSubs = getASTContext().AllocateCopy(witnessSubs);
1871+
for (unsigned i = 0, e = witnessSubs.size(); i < e; i++)
1872+
newWitnessSubs[i] = witnessSubs[i].subst(M.getSwiftModule(), thunkSubs);
1873+
witnessSubs = newWitnessSubs;
1874+
}
18681875

18691876
// Lower the witness thunk type with the requirement's abstraction level.
18701877
auto witnessSILFnType = getNativeSILFunctionType(M,
@@ -1900,16 +1907,6 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
19001907
nameBuffer = mangler.finalize();
19011908
}
19021909

1903-
CanGenericSignature witnessSig;
1904-
if (auto gft = dyn_cast<GenericFunctionType>(
1905-
witnessInfo.LoweredInterfaceType))
1906-
witnessSig = gft.getGenericSignature();
1907-
1908-
// Collect the generic environment for the witness.
1909-
GenericEnvironment *requirementEnv = requirementInfo.GenericEnv;
1910-
GenericEnvironment *witnessEnv = getSubstitutedGenericEnvironment(
1911-
M, requirementEnv, witnessSig, conformance);
1912-
19131910
// If the thunked-to function is set to be always inlined, do the
19141911
// same with the witness, on the theory that the user wants all
19151912
// calls removed if possible, e.g. when we're able to devirtualize
@@ -1928,7 +1925,7 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
19281925

19291926
auto *f = M.createFunction(
19301927
linkage, nameBuffer, witnessSILFnType,
1931-
witnessEnv, SILLocation(witness.getDecl()),
1928+
genericEnv, SILLocation(witness.getDecl()),
19321929
IsNotBare, IsTransparent, isFragile, IsThunk,
19331930
SILFunction::NotRelevant, InlineStrategy);
19341931

@@ -1942,16 +1939,15 @@ SILGenModule::emitProtocolWitness(ProtocolConformance *conformance,
19421939

19431940
// If the witness is a free function, there is no Self type.
19441941
if (!isFree) {
1945-
// If we are emitting a witness thunk for a concrete conformance, Self is
1946-
// just the conforming type.
19471942
if (conformance) {
1948-
selfType = conformance->getType();
1949-
1950-
// For default implementations, Self is the protocol archetype.
1943+
selfType = conformance->getInterfaceType();
19511944
} else {
19521945
auto *proto = cast<ProtocolDecl>(requirement.getDecl()->getDeclContext());
1953-
selfType = proto->getSelfTypeInContext();
1946+
selfType = proto->getSelfInterfaceType();
19541947
}
1948+
1949+
selfType = ArchetypeBuilder::mapTypeIntoContext(
1950+
M.getSwiftModule(), genericEnv, selfType);
19551951
}
19561952

19571953
SILGenFunction gen(*this, *f);

0 commit comments

Comments
 (0)