Skip to content

Commit b9ef570

Browse files
committed
Sema: Simplify representation of vararg forwarding
VarargExpansionExpr shows up in call argument lists in synthesized initializers and modify accessors when we need to forward arguments to a call taking varargs. Previously we would say that the type of VarargExpansionExpr is $T when its subexpression type is [$T]. matchCallArguments() would then 'collect' the single VarargExpansionExpr into a variadic argument list with a single element, and build an ArgumentShuffleExpr for the argument list. In turn, SILGen would peephole vararg emission of a variadic argument list with a single entry that happens to be a VarargExpansionExpr, by returning the subexpression's value, which happened to be an array of the right element type, instead of building a new array containing the elements of the variadic argument list. This was all too complicated. Instead, let's say that the type of a VarargExpansionExpr is [$T], except that when it appears in a TupleExpr, the variadic bit of the corresponding element is set. Then, matchCallArguments() needs to support a case where both the parameter and argument list have a matching vararg element. In this case, instead of collecting multiple arguments into a single variadic argument list, we treat the variadic argument like an ordinary parameter, bypassing construction of the ArgumentShuffleExpr altogether. Finally, SILGen now needs to be able to emit a VarargExpansionExpr in ordinary rvalue position, since it now appears as a child of a TupleExpr; it can do this by simply emitting the sub-expression to produce an array value.
1 parent 8e773ab commit b9ef570

File tree

8 files changed

+29
-95
lines changed

8 files changed

+29
-95
lines changed

lib/SILGen/ASTVisitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ class ASTVisitor : public swift::ASTVisitor<ImplClass,
5757
}
5858

5959
ExprRetTy visitVarargExpansionExpr(VarargExpansionExpr *E, Args... AA) {
60-
llvm_unreachable("vararg expansion should not appear in this position");
60+
return static_cast<ImplClass*>(this)->visit(E->getSubExpr(),
61+
std::forward<Args>(AA)...);
6162
}
6263

6364
ExprRetTy visitIdentityExpr(IdentityExpr *E, Args...AA) {

lib/SILGen/SILGenApply.cpp

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,27 +2599,25 @@ namespace {
25992599
/// arguments are going into a varargs array.
26002600
struct ArgSpecialDest {
26012601
VarargsInfo *SharedInfo;
2602-
unsigned Index : 31;
2603-
unsigned IsExpansion : 1;
2602+
unsigned Index : 32;
26042603
CleanupHandle Cleanup;
26052604

26062605
ArgSpecialDest() : SharedInfo(nullptr) {}
2607-
explicit ArgSpecialDest(VarargsInfo &info, unsigned index, bool isExpansion)
2608-
: SharedInfo(&info), Index(index), IsExpansion(isExpansion) {}
2606+
explicit ArgSpecialDest(VarargsInfo &info, unsigned index)
2607+
: SharedInfo(&info), Index(index) {}
26092608

26102609
// Reference semantics: need to preserve the cleanup handle.
26112610
ArgSpecialDest(const ArgSpecialDest &) = delete;
26122611
ArgSpecialDest &operator=(const ArgSpecialDest &) = delete;
26132612
ArgSpecialDest(ArgSpecialDest &&other)
26142613
: SharedInfo(other.SharedInfo), Index(other.Index),
2615-
IsExpansion(other.IsExpansion), Cleanup(other.Cleanup) {
2614+
Cleanup(other.Cleanup) {
26162615
other.SharedInfo = nullptr;
26172616
}
26182617
ArgSpecialDest &operator=(ArgSpecialDest &&other) {
26192618
assert(!isValid() && "overwriting valid special destination!");
26202619
SharedInfo = other.SharedInfo;
26212620
Index = other.Index;
2622-
IsExpansion = other.IsExpansion;
26232621
Cleanup = other.Cleanup;
26242622
other.SharedInfo = nullptr;
26252623
return *this;
@@ -2638,14 +2636,6 @@ struct ArgSpecialDest {
26382636
SILType loweredSubstParamType) {
26392637
assert(isValid() && "filling an invalid destination");
26402638

2641-
if (IsExpansion) {
2642-
auto expr = std::move(arg).asKnownExpr()->getSemanticsProvidingExpr();
2643-
auto array = cast<VarargExpansionExpr>(expr)->getSubExpr();
2644-
SharedInfo->setExpansion(Index, SGF.emitRValueAsSingleValue(array));
2645-
Cleanup = CleanupHandle::invalid();
2646-
return;
2647-
}
2648-
26492639
SILLocation loc = arg.getLocation();
26502640
auto destAddr = SharedInfo->getBaseAddress();
26512641
if (Index != 0) {
@@ -3473,9 +3463,8 @@ struct ElementExtent {
34733463
ClaimedParamsRef Params;
34743464
/// The destination index, if any.
34753465
/// This is set in the first pass.
3476-
unsigned DestIndex : 29;
3466+
unsigned DestIndex : 30;
34773467
unsigned HasDestIndex : 1;
3478-
unsigned IsVarargExpansion : 1;
34793468
#ifndef NDEBUG
34803469
unsigned Used : 1;
34813470
#endif
@@ -3520,7 +3509,6 @@ class ArgumentShuffleEmitter {
35203509
/// Extents of the inner elements.
35213510
SmallVector<ElementExtent, 8> innerExtents;
35223511
Optional<VarargsInfo> varargsInfo;
3523-
SmallVector<unsigned, 4> varargExpansions;
35243512
SILParameterInfo variadicParamInfo; // innerExtents will point at this
35253513
Optional<SmallVector<ArgSpecialDest, 8>> innerSpecialDests;
35263514

@@ -3575,18 +3563,6 @@ class ArgumentShuffleEmitter {
35753563
assert(!isResultScalar || index == 0);
35763564
return origParamType.getTupleElementType(index);
35773565
}
3578-
3579-
VarargExpansionExpr *getVarargExpansion(unsigned innerIndex) {
3580-
Expr *expr = inner->getSemanticsProvidingExpr();
3581-
if (cast<ArgumentShuffleExpr>(outer)->isSourceScalar()) {
3582-
assert(innerIndex == 0);
3583-
} else {
3584-
auto tuple = dyn_cast<TupleExpr>(expr);
3585-
if (!tuple) return nullptr;
3586-
expr = tuple->getElement(innerIndex)->getSemanticsProvidingExpr();
3587-
}
3588-
return dyn_cast<VarargExpansionExpr>(expr);
3589-
}
35903566
};
35913567

35923568
} // end anonymous namespace
@@ -3635,22 +3611,10 @@ void ArgumentShuffleEmitter::constructInnerTupleTypeInfo(ArgEmitter &parent) {
36353611
unsigned numVarargs = variadicArgs.size();
36363612
assert(canVarargsArrayType == substEltType);
36373613

3638-
// Check for vararg expansions, since their presence changes our
3639-
// emission strategy.
3640-
{
3641-
for (auto i : indices(variadicArgs)) {
3642-
unsigned innerIndex = variadicArgs[i];
3643-
if (getVarargExpansion(innerIndex)) {
3644-
varargExpansions.push_back(i);
3645-
}
3646-
}
3647-
}
3648-
36493614
// If we don't have any vararg expansions, eagerly emit into
36503615
// the array value.
36513616
varargsInfo.emplace(emitBeginVarargs(parent.SGF, outer, varargsEltType,
3652-
canVarargsArrayType, numVarargs,
3653-
varargExpansions));
3617+
canVarargsArrayType, numVarargs));
36543618

36553619
// If we have any varargs, we'll need to actually initialize
36563620
// the array buffer.
@@ -3679,12 +3643,9 @@ void ArgumentShuffleEmitter::constructInnerTupleTypeInfo(ArgEmitter &parent) {
36793643
innerExtents[innerIndex].Used = true;
36803644
#endif
36813645

3682-
auto expansion = getVarargExpansion(innerIndex);
3683-
36843646
// Set the destination index.
36853647
innerExtents[innerIndex].HasDestIndex = true;
36863648
innerExtents[innerIndex].DestIndex = i++;
3687-
innerExtents[innerIndex].IsVarargExpansion = (expansion != nullptr);
36883649

36893650
// Use the singleton param info we prepared before.
36903651
innerExtents[innerIndex].Params =
@@ -3714,8 +3675,7 @@ void ArgumentShuffleEmitter::flattenPatternFromInnerExtendIntoInnerParams(
37143675
if (extent.HasDestIndex) {
37153676
assert(extent.Params.size() == 1);
37163677
innerSpecialDests->push_back(
3717-
ArgSpecialDest(*varargsInfo, extent.DestIndex,
3718-
extent.IsVarargExpansion));
3678+
ArgSpecialDest(*varargsInfo, extent.DestIndex));
37193679

37203680
// Otherwise, fill in with the appropriate number of invalid
37213681
// special dests.

lib/SILGen/SILGenExpr.cpp

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,20 +1916,11 @@ RValue RValueEmitter::visitCoerceExpr(CoerceExpr *E, SGFContext C) {
19161916

19171917
VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
19181918
CanType baseTy, CanType arrayTy,
1919-
unsigned numElements,
1920-
ArrayRef<unsigned> expansionIndices) {
1919+
unsigned numElements) {
19211920
// Reabstract the base type against the array element type.
19221921
auto baseAbstraction = AbstractionPattern::getOpaque();
19231922
auto &baseTL = SGF.getTypeLowering(baseAbstraction, baseTy);
19241923

1925-
if (!expansionIndices.empty()) {
1926-
// An assertion is okay here for now because this is only in generated code.
1927-
assert(numElements == 1 &&
1928-
"expansion that is not the only variadic argument is unsupported");
1929-
return VarargsInfo(ManagedValue(), CleanupHandle::invalid(), SILValue(),
1930-
baseTL, baseAbstraction, /*expansion peephole*/ true);
1931-
}
1932-
19331924
// Allocate the array.
19341925
SILValue numEltsVal = SGF.B.createIntegerLiteral(loc,
19351926
SILType::getBuiltinWordType(SGF.getASTContext()),
@@ -1955,18 +1946,11 @@ VarargsInfo Lowering::emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
19551946
/*isStrict*/ true,
19561947
/*isInvariant*/ false);
19571948

1958-
return VarargsInfo(array, abortCleanup, basePtr, baseTL, baseAbstraction,
1959-
/*expansion peephole*/ false);
1949+
return VarargsInfo(array, abortCleanup, basePtr, baseTL, baseAbstraction);
19601950
}
19611951

19621952
ManagedValue Lowering::emitEndVarargs(SILGenFunction &SGF, SILLocation loc,
19631953
VarargsInfo &&varargs) {
1964-
if (varargs.isExpansionPeephole()) {
1965-
auto result = varargs.getArray();
1966-
assert(result);
1967-
return result;
1968-
}
1969-
19701954
// Kill the abort cleanup.
19711955
SGF.Cleanups.setCleanupState(varargs.getAbortCleanup(), CleanupState::Dead);
19721956

@@ -3610,7 +3594,7 @@ RValue RValueEmitter::visitArrayExpr(ArrayExpr *E, SGFContext C) {
36103594
CanType arrayTy = ArraySliceType::get(elementType)->getCanonicalType();
36113595
VarargsInfo varargsInfo =
36123596
emitBeginVarargs(SGF, loc, elementType, arrayTy,
3613-
E->getNumElements(), {});
3597+
E->getNumElements());
36143598

36153599
// Cleanups for any elements that have been initialized so far.
36163600
SmallVector<CleanupHandle, 8> cleanups;

lib/SILGen/Varargs.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,12 @@ class VarargsInfo {
3535
SILValue BaseAddress;
3636
AbstractionPattern BasePattern;
3737
const TypeLowering &BaseTL;
38-
bool IsExpansionPeephole = false;
3938
public:
4039
VarargsInfo(ManagedValue array, CleanupHandle abortCleanup,
4140
SILValue baseAddress, const TypeLowering &baseTL,
42-
AbstractionPattern basePattern, bool isExpansionPeephole)
41+
AbstractionPattern basePattern)
4342
: Array(array), AbortCleanup(abortCleanup),
44-
BaseAddress(baseAddress), BasePattern(basePattern), BaseTL(baseTL),
45-
IsExpansionPeephole(isExpansionPeephole) {}
46-
47-
void setExpansion(unsigned index, ManagedValue expansion) {
48-
assert(IsExpansionPeephole);
49-
assert(index == 0 && "non-initial index for peephole?");
50-
assert(!Array && "array already filled");
51-
Array = expansion;
52-
}
53-
54-
bool isExpansionPeephole() const { return IsExpansionPeephole; }
43+
BaseAddress(baseAddress), BasePattern(basePattern), BaseTL(baseTL) {}
5544

5645
/// Return the array value. emitEndVarargs() is really the only
5746
/// function that should be accessing this directly.
@@ -75,8 +64,7 @@ class VarargsInfo {
7564
/// Begin a varargs emission sequence.
7665
VarargsInfo emitBeginVarargs(SILGenFunction &SGF, SILLocation loc,
7766
CanType baseTy, CanType arrayTy,
78-
unsigned numElements,
79-
ArrayRef<unsigned> expansions);
67+
unsigned numElements);
8068

8169
/// Successfully end a varargs emission sequence.
8270
ManagedValue emitEndVarargs(SILGenFunction &SGF, SILLocation loc,

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2945,11 +2945,7 @@ namespace {
29452945
Expr *visitVarargExpansionExpr(VarargExpansionExpr *expr) {
29462946
simplifyExprType(expr);
29472947

2948-
auto elementTy = cs.getType(expr);
2949-
auto arrayTy =
2950-
cs.getTypeChecker().getArraySliceType(expr->getLoc(), elementTy);
2951-
if (!arrayTy) return expr;
2952-
2948+
auto arrayTy = cs.getType(expr);
29532949
expr->setSubExpr(coerceToType(expr->getSubExpr(), arrayTy,
29542950
cs.getConstraintLocator(expr)));
29552951
return expr;

lib/Sema/CSGen.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,7 +1718,9 @@ namespace {
17181718
for (unsigned i = 0, n = expr->getNumElements(); i != n; ++i) {
17191719
auto *elt = expr->getElement(i);
17201720
auto ty = CS.getType(elt);
1721-
auto flags = ParameterTypeFlags().withInOut(elt->isSemanticallyInOutExpr());
1721+
auto flags = ParameterTypeFlags()
1722+
.withInOut(elt->isSemanticallyInOutExpr())
1723+
.withVariadic(isa<VarargExpansionExpr>(elt));
17221724
elements.push_back(TupleTypeElt(ty->getInOutObjectType(),
17231725
expr->getElementName(i), flags));
17241726
}
@@ -2438,12 +2440,7 @@ namespace {
24382440
CS.addConstraint(ConstraintKind::Conversion,
24392441
CS.getType(expr->getSubExpr()), array,
24402442
CS.getConstraintLocator(expr));
2441-
2442-
// The apparent type of the expression is the element type, as far as
2443-
// the type-checker is concerned. When this becomes a real feature,
2444-
// we should syntactically restrict these expressions to only appear
2445-
// in specific positions.
2446-
return element;
2443+
return array;
24472444
}
24482445

24492446
Type visitDynamicTypeExpr(DynamicTypeExpr *expr) {

lib/Sema/CSSimplify.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,13 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
390390
// Record the first argument for the variadic.
391391
parameterBindings[paramIdx].push_back(*claimed);
392392

393+
// If the argument is itself variadic, we're forwarding varargs
394+
// with a VarargExpansionExpr; don't collect any more arguments.
395+
if (args[*claimed].isVariadic()) {
396+
skipClaimedArgs();
397+
return;
398+
}
399+
393400
auto currentNextArgIdx = nextArgIdx;
394401
{
395402
nextArgIdx = *claimed;

lib/Sema/CodeSynthesis.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,8 @@ static Expr *buildArgumentForwardingExpr(ArrayRef<ParamDecl*> params,
457457
}
458458

459459
// A single unlabeled value is not a tuple.
460-
if (args.size() == 1 && labels[0].empty()) {
460+
if (args.size() == 1 && labels[0].empty() &&
461+
!isa<VarargExpansionExpr>(args[0])) {
461462
return new (ctx) ParenExpr(SourceLoc(), args[0], SourceLoc(),
462463
/*hasTrailingClosure=*/false);
463464
}

0 commit comments

Comments
 (0)