Skip to content

Commit 07f03bd

Browse files
committed
Use pattern substitutions to consistently abstract yields.
The design implemented in this patch is that we lower the types of accessors with pattern substitutions when lowering them against a different accessor, which happens with class overrides and protocol witnesses, and that we introduce pattern substitutions when substituting into a non-patterned coroutine type. This seems to achieve consistent abstraction without introduce a ton of new complexity. An earlier version of this patch tried to define witness thunks (conservatively, just for accessors) by simply applying the requirement substitutions directly to the requirement. Conceptually that should work, but I ran into a lot of trouble with things that assumed that pattern substitutions didn't conceal significant substitution work. for example, resolving a dependent member in a component type could find a new use of an opaque archetype when the code assumed that such types had already been substituted away. So while I think that is definiteely a promising direction, I had to back that out in order to make the number of changes manageable for a single PR. As part of this, I had to fix a number of little bugs here and there, some of which I just introduced. One of these bugfixes is a place where the substitution code was trying to improperly abstract function types when substituting them in for a type parameter, and it's been in the code for a really long time, and I'm really not sure how it's never blown up before. I'm increasingly of the opinion that invocation substitutions are not actually necessary, but that --- after we've solved the substitution issues above --- we may want the ability to build multiple levels of pattern substitution so that we can guarantee that e.g. witness thunks always have the exact component structure of the requirement before a certain level of substitution, thus allowing the witness substitutions to be easily extracted.
1 parent bac7e6b commit 07f03bd

17 files changed

+793
-124
lines changed

include/swift/AST/TypeDifferenceVisitor.h

Lines changed: 391 additions & 0 deletions
Large diffs are not rendered by default.

include/swift/AST/Types.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4883,6 +4883,17 @@ class SILFunctionType final : public TypeBase, public llvm::FoldingSetNode,
48834883
CanSILFunctionType
48844884
withPatternSubstitutions(SubstitutionMap subs) const;
48854885

4886+
/// Create a SILFunctionType with the same structure as this one,
4887+
/// but replacing the invocation generic signature and pattern
4888+
/// substitutions. This type must either be polymorphic or have
4889+
/// pattern substitutions, and the substitution signature must
4890+
/// match `getSubstGenericSignature()`.
4891+
CanSILFunctionType
4892+
withPatternSpecialization(CanGenericSignature sign,
4893+
SubstitutionMap subs,
4894+
ProtocolConformanceRef witnessConformance =
4895+
ProtocolConformanceRef()) const;
4896+
48864897
class ABICompatibilityCheckResult {
48874898
friend class SILFunctionType;
48884899

include/swift/SIL/SILFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,11 @@ class SILFunction
354354
return SILFunctionConventions(LoweredType, getModule());
355355
}
356356

357+
SILFunctionConventions getConventionsInContext() const {
358+
auto fnType = getLoweredFunctionTypeInContext(getTypeExpansionContext());
359+
return SILFunctionConventions(fnType, getModule());
360+
}
361+
357362
SILProfiler *getProfiler() const { return Profiler; }
358363

359364
SILFunction *getDynamicallyReplacedFunction() const {

include/swift/SIL/SILType.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,11 @@ class SILType {
380380
bool hasArchetype() const {
381381
return getASTType()->hasArchetype();
382382
}
383+
384+
/// True if the type involves any opaque archetypes.
385+
bool hasOpaqueArchetype() const {
386+
return getASTType()->hasOpaqueArchetype();
387+
}
383388

384389
/// Returns the ASTContext for the referenced Swift type.
385390
ASTContext &getASTContext() const {

lib/AST/ASTMangler.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,9 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
15111511
OpArgs.push_back('G');
15121512
break;
15131513
}
1514+
1515+
auto outerGenericSig = CurGenericSignature;
1516+
CurGenericSignature = fn->getSubstGenericSignature();
15141517

15151518
// Mangle the parameters.
15161519
for (auto param : fn->getParameters()) {
@@ -1538,17 +1541,24 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn) {
15381541
OpArgs.push_back(getResultConvention(error.getConvention()));
15391542
appendType(error.getInterfaceType());
15401543
}
1544+
15411545
if (auto sig = fn->getInvocationGenericSignature()) {
15421546
appendGenericSignature(sig);
1547+
CurGenericSignature = outerGenericSig;
15431548
}
15441549
if (auto subs = fn->getInvocationSubstitutions()) {
15451550
appendFlatGenericArgs(subs);
15461551
appendRetroactiveConformances(subs, Mod);
15471552
}
15481553
if (auto subs = fn->getPatternSubstitutions()) {
15491554
appendGenericSignature(subs.getGenericSignature());
1555+
CurGenericSignature =
1556+
fn->getInvocationGenericSignature()
1557+
? fn->getInvocationGenericSignature()
1558+
: outerGenericSig;
15501559
appendFlatGenericArgs(subs);
15511560
appendRetroactiveConformances(subs, Mod);
1561+
CurGenericSignature = outerGenericSig;
15521562
}
15531563

15541564
OpArgs.push_back('_');

lib/AST/ASTPrinter.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4208,10 +4208,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
42084208
}
42094209
sub->Printer << ") -> ";
42104210

4211-
unsigned totalResults =
4212-
T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult());
4213-
4214-
if (totalResults != 1)
4211+
bool parenthesizeResults = mustParenthesizeResults(T);
4212+
if (parenthesizeResults)
42154213
sub->Printer << "(";
42164214

42174215
first = true;
@@ -4235,7 +4233,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
42354233
T->getErrorResult().getInterfaceType().print(sub->Printer, subOptions);
42364234
}
42374235

4238-
if (totalResults != 1)
4236+
if (parenthesizeResults)
42394237
sub->Printer << ")";
42404238
}();
42414239

@@ -4252,6 +4250,24 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
42524250
}
42534251
}
42544252

4253+
static bool mustParenthesizeResults(SILFunctionType *T) {
4254+
// If we don't have exactly one result, we must parenthesize.
4255+
unsigned totalResults =
4256+
T->getNumYields() + T->getNumResults() + unsigned(T->hasErrorResult());
4257+
if (totalResults != 1)
4258+
return true;
4259+
4260+
// If we have substitutions, we must parenthesize if the single
4261+
// result is a function type.
4262+
if (!T->hasPatternSubstitutions() && !T->hasInvocationSubstitutions())
4263+
return false;
4264+
if (T->getNumResults() == 1)
4265+
return isa<SILFunctionType>(T->getResults()[0].getInterfaceType());
4266+
if (T->getNumYields() == 1)
4267+
return isa<SILFunctionType>(T->getYields()[0].getInterfaceType());
4268+
return isa<SILFunctionType>(T->getErrorResult().getInterfaceType());
4269+
}
4270+
42554271
void visitSILBlockStorageType(SILBlockStorageType *T) {
42564272
Printer << "@block_storage ";
42574273
printWithParensIfNotSimple(T->getCaptureType());

lib/AST/Type.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5254,6 +5254,25 @@ SILFunctionType::withPatternSubstitutions(SubstitutionMap subs) const {
52545254
getWitnessMethodConformanceOrInvalid());
52555255
}
52565256

5257+
CanSILFunctionType
5258+
SILFunctionType::withPatternSpecialization(CanGenericSignature sig,
5259+
SubstitutionMap subs,
5260+
ProtocolConformanceRef
5261+
witnessConformance) const {
5262+
assert(!hasInvocationSubstitutions());
5263+
subs = subs.getCanonical();
5264+
assert(!subs || CanGenericSignature(subs.getGenericSignature())
5265+
== getSubstGenericSignature());
5266+
return SILFunctionType::get(sig,
5267+
getExtInfo(), getCoroutineKind(),
5268+
getCalleeConvention(),
5269+
getParameters(), getYields(), getResults(),
5270+
getOptionalErrorResult(),
5271+
subs, SubstitutionMap(),
5272+
const_cast<SILFunctionType*>(this)->getASTContext(),
5273+
witnessConformance);
5274+
}
5275+
52575276
SourceLoc swift::extractNearestSourceLoc(Type ty) {
52585277
if (auto nominal = ty->getAnyNominal())
52595278
return extractNearestSourceLoc(nominal);

0 commit comments

Comments
 (0)