Skip to content

Commit 4efcb82

Browse files
committed
Unlock Opaque Types in Parameterized Protocols
Represent this in much the same way that collections do by creating an opaque value representing the source argument, and a conversion expression representing the destination argument.
1 parent e2ed202 commit 4efcb82

File tree

9 files changed

+297
-82
lines changed

9 files changed

+297
-82
lines changed

include/swift/AST/Expr.h

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,10 @@ class alignas(8) Expr : public ASTAllocated<Expr> {
297297
IsNonAccessing : 1
298298
);
299299

300-
SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32,
300+
SWIFT_INLINE_BITFIELD_FULL(ErasureExpr, ImplicitConversionExpr, 32+20,
301301
: NumPadBits,
302-
NumConformances : 32
302+
NumConformances : 32,
303+
NumArgumentConversions : 20
303304
);
304305

305306
SWIFT_INLINE_BITFIELD_FULL(UnresolvedSpecializeExpr, Expr, 32,
@@ -3244,20 +3245,35 @@ class CollectionUpcastConversionExpr : public ImplicitConversionExpr {
32443245
/// "Appropriate kind" means e.g. a concrete/existential metatype if the
32453246
/// result is an existential metatype.
32463247
class ErasureExpr final : public ImplicitConversionExpr,
3247-
private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef> {
3248+
private llvm::TrailingObjects<ErasureExpr, ProtocolConformanceRef,
3249+
CollectionUpcastConversionExpr::ConversionPair> {
32483250
friend TrailingObjects;
3251+
using ConversionPair = CollectionUpcastConversionExpr::ConversionPair;
32493252

32503253
ErasureExpr(Expr *subExpr, Type type,
3251-
ArrayRef<ProtocolConformanceRef> conformances)
3254+
ArrayRef<ProtocolConformanceRef> conformances,
3255+
ArrayRef<ConversionPair> argConversions)
32523256
: ImplicitConversionExpr(ExprKind::Erasure, subExpr, type) {
32533257
Bits.ErasureExpr.NumConformances = conformances.size();
32543258
std::uninitialized_copy(conformances.begin(), conformances.end(),
32553259
getTrailingObjects<ProtocolConformanceRef>());
3260+
3261+
Bits.ErasureExpr.NumArgumentConversions = argConversions.size();
3262+
std::uninitialized_copy(argConversions.begin(), argConversions.end(),
3263+
getTrailingObjects<ConversionPair>());
32563264
}
32573265

32583266
public:
32593267
static ErasureExpr *create(ASTContext &ctx, Expr *subExpr, Type type,
3260-
ArrayRef<ProtocolConformanceRef> conformances);
3268+
ArrayRef<ProtocolConformanceRef> conformances,
3269+
ArrayRef<ConversionPair> argConversions);
3270+
3271+
size_t numTrailingObjects(OverloadToken<ProtocolConformanceRef>) const {
3272+
return Bits.ErasureExpr.NumConformances;
3273+
}
3274+
size_t numTrailingObjects(OverloadToken<ConversionPair>) const {
3275+
return Bits.ErasureExpr.NumArgumentConversions;
3276+
}
32613277

32623278
/// Retrieve the mapping specifying how the type of the subexpression
32633279
/// maps to the resulting existential type. If the resulting existential
@@ -3274,6 +3290,30 @@ class ErasureExpr final : public ImplicitConversionExpr,
32743290
Bits.ErasureExpr.NumConformances };
32753291
}
32763292

3293+
/// Retrieve the conversion expressions mapping requirements from any
3294+
/// parameterized existentials involved in this erasure.
3295+
///
3296+
/// If the destination type is not a parameterized protocol type,
3297+
/// this array will be empty
3298+
ArrayRef<ConversionPair> getArgumentConversions() const {
3299+
return {getTrailingObjects<ConversionPair>(),
3300+
Bits.ErasureExpr.NumArgumentConversions };
3301+
}
3302+
3303+
/// Retrieve the conversion expressions mapping requirements from any
3304+
/// parameterized existentials involved in this erasure.
3305+
///
3306+
/// If the destination type is not a parameterized protocol type,
3307+
/// this array will be empty
3308+
MutableArrayRef<ConversionPair> getArgumentConversions() {
3309+
return {getTrailingObjects<ConversionPair>(),
3310+
Bits.ErasureExpr.NumArgumentConversions };
3311+
}
3312+
3313+
void setArgumentConversion(unsigned i, const ConversionPair &p) {
3314+
getArgumentConversions()[i] = p;
3315+
}
3316+
32773317
static bool classof(const Expr *E) {
32783318
return E->getKind() == ExprKind::Erasure;
32793319
}

lib/AST/ASTVerifier.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,6 +1469,25 @@ class Verifier : public ASTWalker {
14691469
verifyCheckedBase(E);
14701470
}
14711471

1472+
bool shouldVerify(ErasureExpr *expr) {
1473+
if (!shouldVerify(cast<Expr>(expr)))
1474+
return false;
1475+
1476+
for (auto &elt : expr->getArgumentConversions()) {
1477+
assert(!OpaqueValues.count(elt.OrigValue));
1478+
OpaqueValues[elt.OrigValue] = 0;
1479+
}
1480+
1481+
return true;
1482+
}
1483+
1484+
void cleanup(ErasureExpr *expr) {
1485+
for (auto &elt : expr->getArgumentConversions()) {
1486+
assert(OpaqueValues.count(elt.OrigValue));
1487+
OpaqueValues.erase(elt.OrigValue);
1488+
}
1489+
}
1490+
14721491
void verifyChecked(ErasureExpr *E) {
14731492
PrettyStackTraceExpr debugStack(Ctx, "verifying ErasureExpr", E);
14741493

lib/AST/ASTWalker.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,29 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
695695
}
696696
return nullptr;
697697
}
698-
698+
699+
Expr *visitErasureExpr(ErasureExpr *E) {
700+
if (Expr *E2 = doIt(E->getSubExpr())) {
701+
E->setSubExpr(E2);
702+
} else {
703+
return nullptr;
704+
}
705+
706+
for (unsigned i = 0; i < E->getArgumentConversions().size(); ++i) {
707+
const auto &conv = E->getArgumentConversions()[i];
708+
auto kConv = conv.Conversion;
709+
if (!kConv) {
710+
return nullptr;
711+
} else if (Expr *E2 = doIt(kConv)) {
712+
E->setArgumentConversion(i, {conv.OrigValue, E2});
713+
} else {
714+
return nullptr;
715+
}
716+
}
717+
718+
return E;
719+
}
720+
699721
Expr *visitCollectionUpcastConversionExpr(CollectionUpcastConversionExpr *E) {
700722
if (Expr *E2 = doIt(E->getSubExpr())) {
701723
E->setSubExpr(E2);

lib/AST/Expr.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,14 +1178,16 @@ SequenceExpr *SequenceExpr::create(ASTContext &ctx, ArrayRef<Expr*> elements) {
11781178
assert(elements.size() & 1 && "even number of elements in sequence");
11791179
size_t bytes = totalSizeToAlloc<Expr *>(elements.size());
11801180
void *Buffer = ctx.Allocate(bytes, alignof(SequenceExpr));
1181-
return ::new(Buffer) SequenceExpr(elements);
1181+
return ::new (Buffer) SequenceExpr(elements);
11821182
}
11831183

11841184
ErasureExpr *ErasureExpr::create(ASTContext &ctx, Expr *subExpr, Type type,
1185-
ArrayRef<ProtocolConformanceRef> conformances){
1186-
auto size = totalSizeToAlloc<ProtocolConformanceRef>(conformances.size());
1185+
ArrayRef<ProtocolConformanceRef> conformances,
1186+
ArrayRef<ConversionPair> argConversions) {
1187+
auto size = totalSizeToAlloc<ProtocolConformanceRef, ConversionPair>(conformances.size(),
1188+
argConversions.size());
11871189
auto mem = ctx.Allocate(size, alignof(ErasureExpr));
1188-
return ::new(mem) ErasureExpr(subExpr, type, conformances);
1190+
return ::new (mem) ErasureExpr(subExpr, type, conformances, argConversions);
11891191
}
11901192

11911193
UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
@@ -1194,8 +1196,8 @@ UnresolvedSpecializeExpr *UnresolvedSpecializeExpr::create(ASTContext &ctx,
11941196
SourceLoc RAngleLoc) {
11951197
auto size = totalSizeToAlloc<TypeRepr *>(UnresolvedParams.size());
11961198
auto mem = ctx.Allocate(size, alignof(UnresolvedSpecializeExpr));
1197-
return ::new(mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
1198-
UnresolvedParams, RAngleLoc);
1199+
return ::new (mem) UnresolvedSpecializeExpr(SubExpr, LAngleLoc,
1200+
UnresolvedParams, RAngleLoc);
11991201
}
12001202

12011203
CaptureListEntry::CaptureListEntry(PatternBindingDecl *PBD) : PBD(PBD) {

lib/IRGen/GenExistential.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1445,7 +1445,7 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
14451445
T = existential->getConstraintType()->getCanonicalType();
14461446
}
14471447
llvm::StructType *type;
1448-
if (isa<ProtocolType>(T))
1448+
if (isa<ProtocolType>(T) || isa<ParameterizedProtocolType>(T))
14491449
type = IGM.createNominalType(T);
14501450
else
14511451
type = IGM.createNominalType(cast<ProtocolCompositionType>(T.getPointer()));

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,9 +1464,10 @@ class SubstFunctionTypePatternVisitor
14641464
if (auto gp = handleTypeParameterInAbstractionPattern(pattern, t))
14651465
return gp;
14661466

1467-
assert(!pattern.getType()->hasTypeParameter()
1467+
assert(pattern.getType()->isExistentialType() ||
1468+
(!pattern.getType()->hasTypeParameter()
14681469
&& !pattern.getType()->hasArchetype()
1469-
&& !pattern.getType()->hasOpaqueArchetype());
1470+
&& !pattern.getType()->hasOpaqueArchetype()));
14701471
return pattern.getType();
14711472
}
14721473

0 commit comments

Comments
 (0)