Skip to content

Commit 8b6505e

Browse files
committed
Sema: Ban single-element tuple expressions
Fixes <rdar://problem/30384023>, <rdar://problem/41474370>, and <https://bugs.swift.org/browse/SR-8109>.
1 parent ff9e2b1 commit 8b6505e

File tree

3 files changed

+40
-7
lines changed

3 files changed

+40
-7
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,6 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
203203
while (auto Conv = dyn_cast<ImplicitConversionExpr>(Base))
204204
Base = Conv->getSubExpr();
205205

206-
// Record call arguments.
207-
if (auto Call = dyn_cast<CallExpr>(Base))
208-
CallArgs.insert(Call->getArg());
209-
210206
if (auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
211207
// Verify metatype uses.
212208
if (isa<TypeDecl>(DRE->getDecl())) {
@@ -235,7 +231,14 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
235231
if (isa<TypeExpr>(Base))
236232
checkUseOfMetaTypeName(Base);
237233

234+
if (auto *TSE = dyn_cast<TupleShuffleExpr>(E)) {
235+
if (CallArgs.count(TSE))
236+
CallArgs.insert(TSE->getSubExpr());
237+
}
238+
238239
if (auto *SE = dyn_cast<SubscriptExpr>(E)) {
240+
CallArgs.insert(SE->getIndex());
241+
239242
// Implicit InOutExpr's are allowed in the base of a subscript expr.
240243
if (auto *IOE = dyn_cast<InOutExpr>(SE->getBase()))
241244
if (IOE->isImplicit())
@@ -248,6 +251,13 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
248251
});
249252
}
250253

254+
if (auto *KPE = dyn_cast<KeyPathExpr>(E)) {
255+
for (auto Comp : KPE->getComponents()) {
256+
if (auto *Arg = Comp.getIndexExpr())
257+
CallArgs.insert(Arg);
258+
}
259+
}
260+
251261
if (auto *AE = dyn_cast<CollectionExpr>(E)) {
252262
visitCollectionElements(AE, [&](unsigned argIndex, Expr *arg) {
253263
arg = lookThroughArgument(arg);
@@ -266,6 +276,9 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
266276
// Check function calls, looking through implicit conversions on the
267277
// function and inspecting the arguments directly.
268278
if (auto *Call = dyn_cast<ApplyExpr>(E)) {
279+
// Record call arguments.
280+
CallArgs.insert(Call->getArg());
281+
269282
// Warn about surprising implicit optional promotions.
270283
checkOptionalPromotions(Call);
271284

@@ -381,6 +394,18 @@ static void diagSyntacticUseRestrictions(TypeChecker &TC, const Expr *E,
381394
}
382395
}
383396

397+
// Diagnose single-element tuple expressions.
398+
if (auto *tupleExpr = dyn_cast<TupleExpr>(E)) {
399+
if (!CallArgs.count(tupleExpr)) {
400+
if (tupleExpr->getNumElements() == 1) {
401+
TC.diagnose(tupleExpr->getElementNameLoc(0),
402+
diag::tuple_single_element)
403+
.fixItRemoveChars(tupleExpr->getElementNameLoc(0),
404+
tupleExpr->getElement(0)->getStartLoc());
405+
}
406+
}
407+
}
408+
384409
return { true, E };
385410
}
386411

test/Constraints/tuple.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ f5((1,1))
5656
// Tuples with existentials
5757
var any : Any = ()
5858
any = (1, 2)
59-
any = (label: 4)
59+
any = (label: 4) // expected-error {{cannot create a single-element tuple with an element label}}
6060

6161
// Scalars don't have .0/.1/etc
6262
i = j.0 // expected-error{{value of type 'Int' has no member '0'}}
@@ -252,3 +252,11 @@ func f(b: Bool) -> (a: Int, b: String)? {
252252
let y = ""
253253
return b ? (x, y) : nil
254254
}
255+
256+
// Single element tuple expressions
257+
func singleElementTuple() {
258+
let _ = (label: 123) // expected-error {{cannot create a single-element tuple with an element label}} {{12-19=}}
259+
let _ = (label: 123).label // expected-error {{cannot create a single-element tuple with an element label}} {{12-19=}}
260+
let _ = ((label: 123)) // expected-error {{cannot create a single-element tuple with an element label}} {{13-20=}}
261+
let _ = ((label: 123)).label // expected-error {{cannot create a single-element tuple with an element label}} {{13-20=}}
262+
}

test/decl/enum/enumtest.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,9 @@ func test5(_ myorigin: CGPoint) {
164164
// Dot syntax.
165165
_ = x2.origin.x
166166
_ = x1.size.area()
167-
_ = (r : x1.size).r.area()
167+
_ = (r : x1.size).r.area() // expected-error {{cannot create a single-element tuple with an element label}}
168168
_ = x1.size.area()
169-
_ = (r : x1.size).r.area()
169+
_ = (r : x1.size).r.area() // expected-error {{cannot create a single-element tuple with an element label}}
170170

171171
_ = x1.area
172172

0 commit comments

Comments
 (0)