Skip to content

Commit fd0a82b

Browse files
authored
Merge pull request swiftlang#21360 from slavapestov/fix-tuple-splat-varargs
SE-0110 tuple splatting should not implode argument list with varargs
2 parents 2a1b741 + c5cdd70 commit fd0a82b

File tree

7 files changed

+76
-149
lines changed

7 files changed

+76
-149
lines changed

lib/Sema/CSApply.cpp

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -431,16 +431,12 @@ namespace {
431431
/// \param sources The sources of each of the elements to be used in the
432432
/// resulting tuple, as provided by \c computeTupleShuffle.
433433
///
434-
/// \param variadicArgs The source indices that are mapped to the variadic
435-
/// parameter of the resulting tuple, as provided by \c computeTupleShuffle.
436-
///
437434
/// \param typeFromPattern Optionally, the caller can specify the pattern
438435
/// from where the toType is derived, so that we can deliver better fixit.
439436
Expr *coerceTupleToTuple(Expr *expr, TupleType *fromTuple,
440437
TupleType *toTuple,
441438
ConstraintLocatorBuilder locator,
442-
SmallVectorImpl<int> &sources,
443-
SmallVectorImpl<unsigned> &variadicArgs,
439+
SmallVectorImpl<unsigned> &sources,
444440
Optional<Pattern*> typeFromPattern = None);
445441

446442
/// Coerce a subclass, class-constrained archetype, class-constrained
@@ -2815,11 +2811,7 @@ namespace {
28152811
}
28162812

28172813
Expr *visitParenExpr(ParenExpr *expr) {
2818-
auto &ctx = cs.getASTContext();
2819-
auto pty = cs.getType(expr->getSubExpr());
2820-
cs.setType(expr, ParenType::get(ctx, pty->getInOutObjectType(),
2821-
ParameterTypeFlags().withInOut(pty->is<InOutType>())));
2822-
return expr;
2814+
return simplifyExprType(expr);
28232815
}
28242816

28252817
Expr *visitTupleExpr(TupleExpr *expr) {
@@ -5061,8 +5053,7 @@ static Type rebuildIdentityExprs(ConstraintSystem &cs, Expr *expr, Type type) {
50615053
Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, TupleType *fromTuple,
50625054
TupleType *toTuple,
50635055
ConstraintLocatorBuilder locator,
5064-
SmallVectorImpl<int> &sources,
5065-
SmallVectorImpl<unsigned> &variadicArgs,
5056+
SmallVectorImpl<unsigned> &sources,
50665057
Optional<Pattern*> typeFromPattern){
50675058
auto &tc = cs.getTypeChecker();
50685059

@@ -5077,14 +5068,11 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, TupleType *fromTuple,
50775068
fromTuple->getElements().size());
50785069

50795070
for (unsigned i = 0, n = toTuple->getNumElements(); i != n; ++i) {
5080-
assert(sources[i] != TupleShuffleExpr::DefaultInitialize &&
5081-
sources[i] != TupleShuffleExpr::Variadic);
5082-
50835071
const auto &toElt = toTuple->getElement(i);
50845072
auto toEltType = toElt.getType();
50855073

50865074
// If the source and destination index are different, we'll be shuffling.
5087-
if ((unsigned)sources[i] != i) {
5075+
if (sources[i] != i) {
50885076
anythingShuffled = true;
50895077
}
50905078

@@ -5161,11 +5149,22 @@ Expr *ExprRewriter::coerceTupleToTuple(Expr *expr, TupleType *fromTuple,
51615149

51625150
return expr;
51635151
}
5164-
5152+
5153+
// computeTupleShuffle() produces an array of unsigned (since it can only
5154+
// contain tuple element indices). However TupleShuffleExpr is also used
5155+
// for call argument lists which can contain special things like default
5156+
// arguments and variadics; those are presented by negative integers.
5157+
//
5158+
// FIXME: Design and implement a new AST where argument lists are
5159+
// separate from rvalue tuple conversions.
5160+
ArrayRef<unsigned> sourcesRef = sources;
5161+
ArrayRef<int> sourcesCast((const int *) sourcesRef.data(),
5162+
sourcesRef.size());
5163+
51655164
// Create the tuple shuffle.
51665165
return
51675166
cs.cacheType(TupleShuffleExpr::create(tc.Context,
5168-
expr, sources,
5167+
expr, sourcesCast,
51695168
TupleShuffleExpr::TupleToTuple,
51705169
ConcreteDeclRef(), {}, Type(), {},
51715170
toSugarType));
@@ -5306,15 +5305,12 @@ Expr *ExprRewriter::coerceExistential(Expr *expr, Type toType,
53065305
if (auto tupleType = fromType->getAs<TupleType>()) {
53075306
if (tupleType->hasLValueType()) {
53085307
auto toTuple = tupleType->getRValueType()->castTo<TupleType>();
5309-
SmallVector<int, 4> sources;
5310-
SmallVector<unsigned, 4> variadicArgs;
5311-
bool failed = computeTupleShuffle(tupleType, toTuple,
5312-
sources, variadicArgs);
5308+
SmallVector<unsigned, 4> sources;
5309+
bool failed = computeTupleShuffle(tupleType, toTuple, sources);
53135310
assert(!failed && "Couldn't convert tuple to tuple?");
53145311
(void)failed;
53155312

5316-
coerceTupleToTuple(expr, tupleType, toTuple, locator, sources,
5317-
variadicArgs);
5313+
coerceTupleToTuple(expr, tupleType, toTuple, locator, sources);
53185314
}
53195315
}
53205316

@@ -6543,11 +6539,10 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
65436539
if (auto toTuple = toType->getAs<TupleType>()) {
65446540
// Coerce from a tuple to a tuple.
65456541
if (auto fromTuple = fromType->getAs<TupleType>()) {
6546-
SmallVector<int, 4> sources;
6547-
SmallVector<unsigned, 4> variadicArgs;
6548-
if (!computeTupleShuffle(fromTuple, toTuple, sources, variadicArgs)) {
6542+
SmallVector<unsigned, 4> sources;
6543+
if (!computeTupleShuffle(fromTuple, toTuple, sources)) {
65496544
return coerceTupleToTuple(expr, fromTuple, toTuple,
6550-
locator, sources, variadicArgs);
6545+
locator, sources);
65516546
}
65526547
}
65536548
}

lib/Sema/CSDiag.cpp

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1528,13 +1528,12 @@ bool FailureDiagnosis::diagnoseGeneralConversionFailure(Constraint *constraint){
15281528
FromElts.push_back({ voidTy, fromTT->getElement(i).getName() });
15291529
auto TEType = TupleType::get(FromElts, CS.getASTContext());
15301530

1531-
SmallVector<int, 4> sources;
1532-
SmallVector<unsigned, 4> variadicArgs;
1531+
SmallVector<unsigned, 4> sources;
15331532

15341533
// If the shuffle conversion is invalid (e.g. incorrect element labels),
15351534
// then we have a type error.
15361535
if (computeTupleShuffle(TEType->castTo<TupleType>()->getElements(),
1537-
toTT->getElements(), sources, variadicArgs)) {
1536+
toTT->getElements(), sources)) {
15381537
diagnose(anchor->getLoc(), diag::tuple_types_not_convertible,
15391538
fromTT, toTT)
15401539
.highlight(anchor->getSourceRange());
@@ -7610,27 +7609,18 @@ bool FailureDiagnosis::visitTupleExpr(TupleExpr *TE) {
76107609
if (!TEType->is<TupleType>())
76117610
return visitExpr(TE);
76127611

7613-
SmallVector<int, 4> sources;
7614-
SmallVector<unsigned, 4> variadicArgs;
7612+
SmallVector<unsigned, 4> sources;
76157613

76167614
// If the shuffle is invalid, then there is a type error. We could diagnose
76177615
// it specifically here, but the general logic does a fine job so we let it
76187616
// do it.
76197617
if (computeTupleShuffle(TEType->castTo<TupleType>()->getElements(),
7620-
contextualTT->getElements(), sources, variadicArgs))
7618+
contextualTT->getElements(), sources))
76217619
return visitExpr(TE);
76227620

76237621
// If we got a correct shuffle, we can perform the analysis of all of
76247622
// the input elements, with their expected types.
76257623
for (unsigned i = 0, e = sources.size(); i != e; ++i) {
7626-
// If the value is taken from a default argument, ignore it.
7627-
if (sources[i] == TupleShuffleExpr::DefaultInitialize ||
7628-
sources[i] == TupleShuffleExpr::Variadic ||
7629-
sources[i] == TupleShuffleExpr::CallerDefaultInitialize)
7630-
continue;
7631-
7632-
assert(sources[i] >= 0 && "Unknown sources index");
7633-
76347624
// Otherwise, it must match the corresponding expected argument type.
76357625
unsigned inArgNo = sources[i];
76367626

@@ -7659,27 +7649,6 @@ bool FailureDiagnosis::visitTupleExpr(TupleExpr *TE) {
76597649
}
76607650
}
76617651

7662-
if (!variadicArgs.empty()) {
7663-
Type varargsTy;
7664-
for (auto &elt : contextualTT->getElements()) {
7665-
if (elt.isVararg()) {
7666-
varargsTy = elt.getVarargBaseTy();
7667-
break;
7668-
}
7669-
}
7670-
7671-
assert(varargsTy);
7672-
7673-
for (unsigned i = 0, e = variadicArgs.size(); i != e; ++i) {
7674-
unsigned inArgNo = variadicArgs[i];
7675-
7676-
auto expr = typeCheckChildIndependently(
7677-
TE->getElement(inArgNo), varargsTy, CS.getContextualTypePurpose());
7678-
// If there was an error type checking this argument, then we're done.
7679-
if (!expr) return true;
7680-
}
7681-
}
7682-
76837652
return false;
76847653
}
76857654

lib/Sema/CSSimplify.cpp

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -997,29 +997,12 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
997997
}
998998

999999
// Compute the element shuffles for conversions.
1000-
SmallVector<int, 16> sources;
1001-
SmallVector<unsigned, 4> variadicArguments;
1002-
if (computeTupleShuffle(tuple1, tuple2, sources, variadicArguments))
1000+
SmallVector<unsigned, 16> sources;
1001+
if (computeTupleShuffle(tuple1, tuple2, sources))
10031002
return getTypeMatchFailure(locator);
10041003

10051004
// Check each of the elements.
1006-
bool hasVariadic = false;
1007-
unsigned variadicIdx = sources.size();
10081005
for (unsigned idx2 = 0, n = sources.size(); idx2 != n; ++idx2) {
1009-
// Default-initialization always allowed for conversions.
1010-
if (sources[idx2] == TupleShuffleExpr::DefaultInitialize) {
1011-
continue;
1012-
}
1013-
1014-
// Variadic arguments handled below.
1015-
if (sources[idx2] == TupleShuffleExpr::Variadic) {
1016-
assert(!hasVariadic && "Multiple variadic parameters");
1017-
hasVariadic = true;
1018-
variadicIdx = idx2;
1019-
continue;
1020-
}
1021-
1022-
assert(sources[idx2] >= 0);
10231006
unsigned idx1 = sources[idx2];
10241007

10251008
// Match up the types.
@@ -1032,21 +1015,6 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
10321015
return result;
10331016
}
10341017

1035-
// If we have variadic arguments to check, do so now.
1036-
if (hasVariadic) {
1037-
const auto &elt2 = tuple2->getElements()[variadicIdx];
1038-
auto eltType2 = elt2.getVarargBaseTy();
1039-
1040-
for (unsigned idx1 : variadicArguments) {
1041-
auto result = matchTypes(tuple1->getElementType(idx1), eltType2, subKind,
1042-
subflags,
1043-
locator.withPathElement(
1044-
LocatorPathElt::getTupleElement(idx1)));
1045-
if (result.isFailure())
1046-
return result;
1047-
}
1048-
}
1049-
10501018
return getTypeMatchSuccess();
10511019
}
10521020

@@ -1173,6 +1141,17 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
11731141
!params[0].isVariadic());
11741142
};
11751143

1144+
auto canImplodeParams = [&](ArrayRef<AnyFunctionType::Param> params) {
1145+
if (params.size() == 1)
1146+
return false;
1147+
1148+
for (auto param : params)
1149+
if (param.isVariadic() || param.isInOut())
1150+
return false;
1151+
1152+
return true;
1153+
};
1154+
11761155
auto implodeParams = [&](SmallVectorImpl<AnyFunctionType::Param> &params) {
11771156
auto input = AnyFunctionType::composeInput(getASTContext(), params,
11781157
/*canonicalVararg=*/false);
@@ -1193,21 +1172,18 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
11931172

11941173
if (last != path.rend()) {
11951174
if (last->getKind() == ConstraintLocator::ApplyArgToParam) {
1196-
if (isSingleParam(func2Params)) {
1197-
if (!isSingleParam(func1Params)) {
1198-
implodeParams(func1Params);
1199-
}
1200-
} else if (getASTContext().isSwiftVersionAtLeast(4)
1201-
&& !getASTContext().isSwiftVersionAtLeast(5)
1202-
&& !isSingleParam(func2Params)) {
1175+
if (isSingleParam(func2Params) &&
1176+
canImplodeParams(func1Params)) {
1177+
implodeParams(func1Params);
1178+
} else if (!getASTContext().isSwiftVersionAtLeast(5) &&
1179+
isSingleParam(func1Params) &&
1180+
canImplodeParams(func2Params)) {
12031181
auto *simplified = locator.trySimplifyToExpr();
12041182
// We somehow let tuple unsplatting function conversions
12051183
// through in some cases in Swift 4, so let's let that
12061184
// continue to work, but only for Swift 4.
12071185
if (simplified && isa<DeclRefExpr>(simplified)) {
1208-
if (isSingleParam(func1Params)) {
1209-
implodeParams(func2Params);
1210-
}
1186+
implodeParams(func2Params);
12111187
}
12121188
}
12131189
}

lib/Sema/ConstraintSystem.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3309,25 +3309,17 @@ class ConstraintSystem {
33093309
/// \param sources Will be populated with information about the source of each
33103310
/// of the elements for the result tuple. The indices into this array are the
33113311
/// indices of the tuple type we're converting to, while the values are
3312-
/// either one of the \c TupleShuffleExpr constants or are an index into the
3313-
/// source tuple.
3314-
///
3315-
/// \param variadicArgs Will be populated with all of the variadic arguments
3316-
/// that will be placed into the variadic tuple element (i.e., at the index
3317-
/// \c where \c consumed[i] is \c TupleShuffleExpr::Variadic). The values
3318-
/// are indices into the source tuple.
3312+
/// an index into the source tuple.
33193313
///
33203314
/// \returns true if no tuple conversion is possible, false otherwise.
33213315
bool computeTupleShuffle(ArrayRef<TupleTypeElt> fromTuple,
33223316
ArrayRef<TupleTypeElt> toTuple,
3323-
SmallVectorImpl<int> &sources,
3324-
SmallVectorImpl<unsigned> &variadicArgs);
3317+
SmallVectorImpl<unsigned> &sources);
33253318
static inline bool computeTupleShuffle(TupleType *fromTuple,
33263319
TupleType *toTuple,
3327-
SmallVectorImpl<int> &sources,
3328-
SmallVectorImpl<unsigned> &variadicArgs){
3320+
SmallVectorImpl<unsigned> &sources){
33293321
return computeTupleShuffle(fromTuple->getElements(), toTuple->getElements(),
3330-
sources, variadicArgs);
3322+
sources);
33313323
}
33323324

33333325
/// Describes the arguments to which a parameter binds.

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,11 @@ void *operator new(size_t bytes, ConstraintSystem& cs,
100100

101101
bool constraints::computeTupleShuffle(ArrayRef<TupleTypeElt> fromTuple,
102102
ArrayRef<TupleTypeElt> toTuple,
103-
SmallVectorImpl<int> &sources,
104-
SmallVectorImpl<unsigned> &variadicArgs) {
105-
const int unassigned = -3;
103+
SmallVectorImpl<unsigned> &sources) {
104+
const unsigned unassigned = -1;
106105

107106
SmallVector<bool, 4> consumed(fromTuple.size(), false);
108107
sources.clear();
109-
variadicArgs.clear();
110108
sources.assign(toTuple.size(), unassigned);
111109

112110
// Match up any named elements.
@@ -150,35 +148,14 @@ bool constraints::computeTupleShuffle(ArrayRef<TupleTypeElt> fromTuple,
150148
if (sources[i] != unassigned)
151149
continue;
152150

153-
const auto &elt2 = toTuple[i];
154-
155-
// Variadic tuple elements match the rest of the input elements.
156-
if (elt2.isVararg()) {
157-
// Collect the remaining (unnamed) inputs.
158-
while (fromNext != fromLast) {
159-
// Labeled elements can't be adopted into varargs even if
160-
// they're non-mandatory. There isn't a really strong reason
161-
// for this, though.
162-
if (fromTuple[fromNext].hasName())
163-
return true;
164-
165-
variadicArgs.push_back(fromNext);
166-
consumed[fromNext] = true;
167-
skipToNextAvailableInput();
168-
}
169-
sources[i] = TupleShuffleExpr::Variadic;
170-
171-
// Keep looking at subsequent arguments. Non-variadic arguments may
172-
// follow the variadic one.
173-
continue;
174-
}
175-
176151
// If there aren't any more inputs, we are done.
177152
if (fromNext == fromLast) {
178153
return true;
179154
}
180155

181156
// Otherwise, assign this input to the next output element.
157+
const auto &elt2 = toTuple[i];
158+
assert(!elt2.isVararg());
182159

183160
// Fail if the input element is named and we're trying to match it with
184161
// something with a different label.

0 commit comments

Comments
 (0)