Skip to content

Commit e2c9c52

Browse files
committed
AST/Sema/SILGen: Implement tuple conversions
TupleShuffleExpr could not express the full range of tuple conversions that were accepted by the constraint solver; in particular, while it could re-order elements or introduce and eliminate labels, it could not convert the tuple element types to their supertypes. This was the source of the annoying "cannot express tuple conversion" diagnostic. Replace TupleShuffleExpr with DestructureTupleExpr, which evaluates a source expression of tuple type and binds its elements to OpaqueValueExprs. The DestructureTupleExpr's result expression can then produce an arbitrary value written in terms of these OpaqueValueExprs, as long as each OpaqueValueExpr is used exactly once. This is sufficient to express conversions such as (Int, Float) => (Int?, Any), as well as the various cases that were already supported, such as (x: Int, y: Float) => (y: Float, x: Int). https://bugs.swift.org/browse/SR-2672, rdar://problem/12340004
1 parent ab81406 commit e2c9c52

File tree

15 files changed

+295
-357
lines changed

15 files changed

+295
-357
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -815,13 +815,6 @@ ERROR(precedence_group_redeclared,none,
815815
NOTE(previous_precedence_group_decl,none,
816816
"previous precedence group declaration here", ())
817817

818-
//------------------------------------------------------------------------------
819-
// MARK: Type Check Coercions
820-
//------------------------------------------------------------------------------
821-
822-
ERROR(tuple_conversion_not_expressible,none,
823-
"cannot express tuple conversion %0 to %1", (Type, Type))
824-
825818
//------------------------------------------------------------------------------
826819
// MARK: Expression Type Checking Errors
827820
//------------------------------------------------------------------------------

include/swift/AST/Expr.h

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,9 @@ class alignas(8) Expr {
290290

291291
SWIFT_INLINE_BITFIELD_EMPTY(ImplicitConversionExpr, Expr);
292292

293-
SWIFT_INLINE_BITFIELD_FULL(TupleShuffleExpr, ImplicitConversionExpr, 16,
294-
/// This contains an entry for each element in the Expr type. Each element
295-
/// specifies which index from the SubExpr that the destination element gets.
296-
NumElementMappings : 16
293+
SWIFT_INLINE_BITFIELD_FULL(DestructureTupleExpr, ImplicitConversionExpr, 16,
294+
/// The number of elements in the tuple type being destructured.
295+
NumElements : 16
297296
);
298297

299298
SWIFT_INLINE_BITFIELD_FULL(ArgumentShuffleExpr, ImplicitConversionExpr, 2+16+16+16,
@@ -2960,37 +2959,53 @@ class UnevaluatedInstanceExpr : public ImplicitConversionExpr {
29602959
}
29612960
};
29622961

2963-
/// TupleShuffleExpr - This represents a permutation of a tuple value to a new
2964-
/// tuple type.
2965-
class TupleShuffleExpr final : public ImplicitConversionExpr,
2966-
private llvm::TrailingObjects<TupleShuffleExpr, unsigned> {
2962+
/// DestructureTupleExpr - Destructure a tuple value produced by a source
2963+
/// expression, binding the elements to OpaqueValueExprs, then evaluate the
2964+
/// result expression written in terms of the OpaqueValueExprs.
2965+
class DestructureTupleExpr final : public ImplicitConversionExpr,
2966+
private llvm::TrailingObjects<DestructureTupleExpr, OpaqueValueExpr *> {
29672967
friend TrailingObjects;
29682968

2969-
size_t numTrailingObjects(OverloadToken<unsigned>) const {
2970-
return Bits.TupleShuffleExpr.NumElementMappings;
2969+
size_t numTrailingObjects(OverloadToken<OpaqueValueExpr *>) const {
2970+
return Bits.DestructureTupleExpr.NumElements;
29712971
}
29722972

29732973
private:
2974-
TupleShuffleExpr(Expr *subExpr, ArrayRef<unsigned> elementMapping,
2975-
Type ty)
2976-
: ImplicitConversionExpr(ExprKind::TupleShuffle, subExpr, ty) {
2977-
Bits.TupleShuffleExpr.NumElementMappings = elementMapping.size();
2978-
std::uninitialized_copy(elementMapping.begin(), elementMapping.end(),
2979-
getTrailingObjects<unsigned>());
2974+
Expr *DstExpr;
2975+
2976+
DestructureTupleExpr(ArrayRef<OpaqueValueExpr *> destructuredElements,
2977+
Expr *srcExpr, Expr *dstExpr, Type ty)
2978+
: ImplicitConversionExpr(ExprKind::DestructureTuple, srcExpr, ty),
2979+
DstExpr(dstExpr) {
2980+
Bits.DestructureTupleExpr.NumElements = destructuredElements.size();
2981+
std::uninitialized_copy(destructuredElements.begin(),
2982+
destructuredElements.end(),
2983+
getTrailingObjects<OpaqueValueExpr *>());
29802984
}
29812985

29822986
public:
2983-
static TupleShuffleExpr *create(ASTContext &ctx, Expr *subExpr,
2984-
ArrayRef<unsigned> elementMapping,
2985-
Type ty);
2987+
/// Create a tuple destructuring. The type of srcExpr must be a tuple type,
2988+
/// and the number of elements must equal the size of destructureElements.
2989+
static DestructureTupleExpr *
2990+
create(ASTContext &ctx,
2991+
ArrayRef<OpaqueValueExpr *> destructuredElements,
2992+
Expr *srcExpr, Expr *dstExpr, Type ty);
29862993

2987-
ArrayRef<unsigned> getElementMapping() const {
2988-
return {getTrailingObjects<unsigned>(),
2989-
static_cast<size_t>(Bits.TupleShuffleExpr.NumElementMappings)};
2994+
ArrayRef<OpaqueValueExpr *> getDestructuredElements() const {
2995+
return {getTrailingObjects<OpaqueValueExpr *>(),
2996+
static_cast<size_t>(Bits.DestructureTupleExpr.NumElements)};
2997+
}
2998+
2999+
Expr *getResultExpr() const {
3000+
return DstExpr;
3001+
}
3002+
3003+
void setResultExpr(Expr *dstExpr) {
3004+
DstExpr = dstExpr;
29903005
}
29913006

29923007
static bool classof(const Expr *E) {
2993-
return E->getKind() == ExprKind::TupleShuffle;
3008+
return E->getKind() == ExprKind::DestructureTuple;
29943009
}
29953010
};
29963011

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ ABSTRACT_EXPR(Apply, Expr)
143143
EXPR_RANGE(Apply, Call, ConstructorRefCall)
144144
ABSTRACT_EXPR(ImplicitConversion, Expr)
145145
EXPR(Load, ImplicitConversionExpr)
146-
EXPR(TupleShuffle, ImplicitConversionExpr)
146+
EXPR(DestructureTuple, ImplicitConversionExpr)
147147
EXPR(ArgumentShuffle, ImplicitConversionExpr)
148148
EXPR(UnresolvedTypeConversion, ImplicitConversionExpr)
149149
EXPR(FunctionConversion, ImplicitConversionExpr)

lib/AST/ASTDumper.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,15 +2138,20 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
21382138
printRec(E->getBase());
21392139
PrintWithColorRAII(OS, ParenthesisColor) << ')';
21402140
}
2141-
void visitTupleShuffleExpr(TupleShuffleExpr *E) {
2142-
printCommon(E, "tuple_shuffle_expr");
2143-
OS << " elements=[";
2144-
for (unsigned i = 0, e = E->getElementMapping().size(); i != e; ++i) {
2145-
if (i) OS << ", ";
2146-
OS << E->getElementMapping()[i];
2141+
void visitDestructureTupleExpr(DestructureTupleExpr *E) {
2142+
printCommon(E, "destructure_tuple_expr");
2143+
OS << " destructured=";
2144+
PrintWithColorRAII(OS, ParenthesisColor) << '(';
2145+
Indent += 2;
2146+
for (auto *elt : E->getDestructuredElements()) {
2147+
OS << "\n";
2148+
printRec(elt);
21472149
}
2148-
OS << "]\n";
2150+
Indent -= 2;
2151+
PrintWithColorRAII(OS, ParenthesisColor) << ")\n";
21492152
printRec(E->getSubExpr());
2153+
OS << "\n";
2154+
printRec(E->getResultExpr());
21502155
PrintWithColorRAII(OS, ParenthesisColor) << ')';
21512156
}
21522157
void visitArgumentShuffleExpr(ArgumentShuffleExpr *E) {

lib/AST/ASTVerifier.cpp

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -820,6 +820,26 @@ class Verifier : public ASTWalker {
820820
OpaqueValues.erase(expr->getOpaqueValue());
821821
}
822822

823+
// Register the OVEs in a DestructureTupleExpr.
824+
bool shouldVerify(DestructureTupleExpr *expr) {
825+
if (!shouldVerify(cast<Expr>(expr)))
826+
return false;
827+
828+
for (auto *opaqueElt : expr->getDestructuredElements()) {
829+
assert(!OpaqueValues.count(opaqueElt));
830+
OpaqueValues[opaqueElt] = 0;
831+
}
832+
833+
return true;
834+
}
835+
836+
void cleanup(DestructureTupleExpr *expr) {
837+
for (auto *opaqueElt : expr->getDestructuredElements()) {
838+
assert(OpaqueValues.count(opaqueElt));
839+
OpaqueValues.erase(opaqueElt);
840+
}
841+
}
842+
823843
// Keep a stack of the currently-live optional evaluations.
824844
bool shouldVerify(OptionalEvaluationExpr *expr) {
825845
if (!shouldVerify(cast<Expr>(expr)))
@@ -1988,27 +2008,35 @@ class Verifier : public ASTWalker {
19882008
verifyCheckedBase(E);
19892009
}
19902010

1991-
void verifyChecked(TupleShuffleExpr *E) {
1992-
PrettyStackTraceExpr debugStack(Ctx, "verifying TupleShuffleExpr", E);
2011+
void verifyChecked(DestructureTupleExpr *E) {
2012+
PrettyStackTraceExpr debugStack(Ctx, "verifying DestructureTupleExpr", E);
19932013

1994-
auto getSubElementType = [&](unsigned i) {
2014+
auto getInputElementType = [&](unsigned i) {
19952015
return (E->getSubExpr()->getType()->castTo<TupleType>()
19962016
->getElementType(i));
19972017
};
19982018

1999-
/// Retrieve the ith element type from the resulting tuple type.
2000-
auto getOuterElementType = [&](unsigned i) -> Type {
2001-
return E->getType()->castTo<TupleType>()->getElementType(i);
2019+
auto getOpaqueElementType = [&](unsigned i) -> Type {
2020+
return E->getDestructuredElements()[i]->getType();
20022021
};
20032022

2004-
for (unsigned i = 0, e = E->getElementMapping().size(); i != e; ++i) {
2005-
int subElem = E->getElementMapping()[i];
2006-
if (!getOuterElementType(i)->isEqual(getSubElementType(subElem))) {
2007-
Out << "Type mismatch in TupleShuffleExpr\n";
2023+
for (unsigned i = 0, e = E->getDestructuredElements().size(); i != e; ++i) {
2024+
Type inputType = getInputElementType(i);
2025+
Type opaqueType = getOpaqueElementType(i);
2026+
if (!inputType->isEqual(opaqueType)) {
2027+
Out << "Input type mismatch in DestructureTupleExpr\n";
2028+
inputType->dump(Out);
2029+
opaqueType->dump(Out);
20082030
abort();
20092031
}
20102032
}
20112033

2034+
if (!E->getResultExpr()->getType()->isEqual(E->getType())) {
2035+
Out << "Result type mismatch in DestructureTupleExpr\n";
2036+
E->getResultExpr()->getType()->dump(Out);
2037+
E->getType()->dump(Out);
2038+
}
2039+
20122040
verifyCheckedBase(E);
20132041
}
20142042

lib/AST/ASTWalker.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
// Note that semantic components will generally preserve the
3838
// syntactic order of their children because doing something else
3939
// could illegally change order of evaluation. This is why, for
40-
// example, shuffling a TupleExpr creates a TupleShuffleExpr
40+
// example, shuffling a TupleExpr creates a DestructureTupleExpr
4141
// instead of just making a new TupleExpr with the elements in
4242
// different order.
4343
//
@@ -639,9 +639,15 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
639639
return E;
640640
}
641641

642-
Expr *visitTupleShuffleExpr(TupleShuffleExpr *E) {
643-
if (Expr *E2 = doIt(E->getSubExpr())) {
644-
E->setSubExpr(E2);
642+
Expr *visitDestructureTupleExpr(DestructureTupleExpr *E) {
643+
if (auto *src = doIt(E->getSubExpr())) {
644+
E->setSubExpr(src);
645+
} else {
646+
return nullptr;
647+
}
648+
649+
if (auto *dst = doIt(E->getResultExpr())) {
650+
E->setResultExpr(dst);
645651
} else {
646652
return nullptr;
647653
}

lib/AST/Expr.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ ConcreteDeclRef Expr::getReferencedDecl() const {
322322

323323
PASS_THROUGH_REFERENCE(ConstructorRefCall, getFn);
324324
PASS_THROUGH_REFERENCE(Load, getSubExpr);
325-
NO_REFERENCE(TupleShuffle);
325+
NO_REFERENCE(DestructureTuple);
326326
NO_REFERENCE(ArgumentShuffle);
327327
NO_REFERENCE(UnresolvedTypeConversion);
328328
PASS_THROUGH_REFERENCE(FunctionConversion, getSubExpr);
@@ -637,7 +637,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
637637
return false;
638638

639639
case ExprKind::Load:
640-
case ExprKind::TupleShuffle:
640+
case ExprKind::DestructureTuple:
641641
case ExprKind::ArgumentShuffle:
642642
case ExprKind::UnresolvedTypeConversion:
643643
case ExprKind::FunctionConversion:
@@ -1333,13 +1333,14 @@ CaptureListExpr *CaptureListExpr::create(ASTContext &ctx,
13331333
return ::new(mem) CaptureListExpr(captureList, closureBody);
13341334
}
13351335

1336-
TupleShuffleExpr *TupleShuffleExpr::create(ASTContext &ctx,
1337-
Expr *subExpr,
1338-
ArrayRef<unsigned> elementMapping,
1339-
Type ty) {
1340-
auto size = totalSizeToAlloc<unsigned>(elementMapping.size());
1341-
auto mem = ctx.Allocate(size, alignof(TupleShuffleExpr));
1342-
return ::new(mem) TupleShuffleExpr(subExpr, elementMapping, ty);
1336+
DestructureTupleExpr *
1337+
DestructureTupleExpr::create(ASTContext &ctx,
1338+
ArrayRef<OpaqueValueExpr *> destructuredElements,
1339+
Expr *srcExpr, Expr *dstExpr, Type ty) {
1340+
auto size = totalSizeToAlloc<OpaqueValueExpr *>(destructuredElements.size());
1341+
auto mem = ctx.Allocate(size, alignof(DestructureTupleExpr));
1342+
return ::new(mem) DestructureTupleExpr(destructuredElements,
1343+
srcExpr, dstExpr, ty);
13431344
}
13441345

13451346
ArgumentShuffleExpr *ArgumentShuffleExpr::create(ASTContext &ctx,

lib/SILGen/SILGenExpr.cpp

Lines changed: 22 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ namespace {
449449
RValue visitKeyPathApplicationExpr(KeyPathApplicationExpr *E, SGFContext C);
450450
RValue visitDynamicSubscriptExpr(DynamicSubscriptExpr *E,
451451
SGFContext C);
452-
RValue visitTupleShuffleExpr(TupleShuffleExpr *E, SGFContext C);
452+
RValue visitDestructureTupleExpr(DestructureTupleExpr *E, SGFContext C);
453453
RValue visitArgumentShuffleExpr(ArgumentShuffleExpr *E, SGFContext C);
454454
RValue visitDynamicTypeExpr(DynamicTypeExpr *E, SGFContext C);
455455
RValue visitCaptureListExpr(CaptureListExpr *E, SGFContext C);
@@ -2151,81 +2151,34 @@ RValue SILGenFunction::emitApplyOfStoredPropertyInitializer(
21512151
subs, {}, calleeTypeInfo, ApplyOptions::None, C);
21522152
}
21532153

2154-
static void emitTupleShuffleExprInto(RValueEmitter &emitter,
2155-
TupleShuffleExpr *E,
2156-
Initialization *outerTupleInit) {
2157-
CanTupleType outerTuple = cast<TupleType>(E->getType()->getCanonicalType());
2158-
auto outerFields = outerTuple->getElements();
2159-
(void) outerFields;
2160-
2161-
// Decompose the initialization.
2162-
SmallVector<InitializationPtr, 4> outerInitsBuffer;
2163-
auto outerInits =
2164-
outerTupleInit->splitIntoTupleElements(emitter.SGF, RegularLocation(E),
2165-
outerTuple, outerInitsBuffer);
2166-
assert(outerInits.size() == outerFields.size() &&
2167-
"initialization size does not match tuple size?!");
2168-
2169-
// Map outer initializations into a tuple of inner initializations:
2170-
// - fill out the initialization elements with null
2171-
TupleInitialization innerTupleInit;
2172-
2173-
CanTupleType innerTuple =
2174-
cast<TupleType>(E->getSubExpr()->getType()->getCanonicalType());
2175-
innerTupleInit.SubInitializations.resize(innerTuple->getNumElements());
2154+
RValue RValueEmitter::visitDestructureTupleExpr(DestructureTupleExpr *E,
2155+
SGFContext C) {
2156+
// Emit the sub-expression tuple and destructure it into elements.
2157+
SmallVector<RValue, 4> elements;
2158+
visit(E->getSubExpr()).extractElements(elements);
21762159

2177-
// Map all the outer initializations to their appropriate targets.
2178-
for (unsigned outerIndex = 0; outerIndex != outerInits.size(); outerIndex++) {
2179-
auto innerMapping = E->getElementMapping()[outerIndex];
2180-
innerTupleInit.SubInitializations[innerMapping] =
2181-
std::move(outerInits[outerIndex]);
2182-
}
2160+
// Bind each element of the input tuple to its corresponding
2161+
// opaque value.
2162+
for (unsigned i = 0, e = E->getDestructuredElements().size();
2163+
i != e; ++i) {
2164+
auto *opaqueElt = E->getDestructuredElements()[i];
2165+
assert(!SGF.OpaqueValues.count(opaqueElt));
21832166

2184-
#ifndef NDEBUG
2185-
for (auto &innerInit : innerTupleInit.SubInitializations) {
2186-
assert(innerInit != nullptr && "didn't map all inner elements");
2167+
auto opaqueMV = std::move(elements[i]).getAsSingleValue(SGF, E);
2168+
SGF.OpaqueValues[opaqueElt] = opaqueMV;
21872169
}
2188-
#endif
2189-
2190-
// Emit the sub-expression into the tuple initialization we just built.
2191-
emitter.SGF.emitExprInto(E->getSubExpr(), &innerTupleInit);
21922170

2193-
outerTupleInit->finishInitialization(emitter.SGF);
2194-
}
2171+
// Emit the result expression written in terms of the above
2172+
// opaque values.
2173+
auto result = visit(E->getResultExpr(), C);
21952174

2196-
RValue RValueEmitter::visitTupleShuffleExpr(TupleShuffleExpr *E,
2197-
SGFContext C) {
2198-
// If we're emitting into an initialization, we can try shuffling the
2199-
// elements of the initialization.
2200-
if (Initialization *I = C.getEmitInto()) {
2201-
if (I->canSplitIntoTupleElements()) {
2202-
emitTupleShuffleExprInto(*this, E, I);
2203-
return RValue::forInContext();
2204-
}
2175+
// Clean up.
2176+
for (unsigned i = 0, e = E->getDestructuredElements().size();
2177+
i != e; ++i) {
2178+
auto *opaqueElt = E->getDestructuredElements()[i];
2179+
SGF.OpaqueValues.erase(opaqueElt);
22052180
}
22062181

2207-
// Emit the sub-expression tuple and destructure it into elements.
2208-
SmallVector<RValue, 4> elements;
2209-
visit(E->getSubExpr()).extractElements(elements);
2210-
2211-
// Prepare a new tuple to hold the shuffled result.
2212-
RValue result(E->getType()->getCanonicalType());
2213-
2214-
auto outerFields = E->getType()->castTo<TupleType>()->getElements();
2215-
auto shuffleIndexIterator = E->getElementMapping().begin();
2216-
auto shuffleIndexEnd = E->getElementMapping().end();
2217-
(void)shuffleIndexEnd;
2218-
for (auto &field : outerFields) {
2219-
(void) field;
2220-
assert(shuffleIndexIterator != shuffleIndexEnd &&
2221-
"ran out of shuffle indexes before running out of fields?!");
2222-
int shuffleIndex = *shuffleIndexIterator++;
2223-
2224-
// Map from a different tuple element.
2225-
result.addElement(
2226-
std::move(elements[shuffleIndex]).ensurePlusOne(SGF, E));
2227-
}
2228-
22292182
return result;
22302183
}
22312184

0 commit comments

Comments
 (0)