Skip to content

Commit 8263f4e

Browse files
authored
Merge pull request #21349 from slavapestov/one-element-tuple-5.0
Ban one-element tuples harder [5.0]
2 parents df4b9f4 + 8b6505e commit 8263f4e

File tree

5 files changed

+55
-17
lines changed

5 files changed

+55
-17
lines changed

lib/Sema/CSApply.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -403,14 +403,15 @@ static Expr *buildDynamicMemberLookupIndexExpr(StringRef name, Type ty,
403403
// Build and type check the string literal index value to the specific
404404
// string type expected by the subscript.
405405
Expr *nameExpr = new (ctx) StringLiteralExpr(name, loc, /*implicit*/true);
406+
(void)cs.TC.typeCheckExpression(nameExpr, dc);
407+
cs.cacheExprTypes(nameExpr);
406408

407409
// Build a tuple so that the argument has a label.
408410
Expr *tuple = TupleExpr::create(ctx, loc, nameExpr, ctx.Id_dynamicMember,
409411
loc, loc, /*hasTrailingClosure*/false,
410412
/*implicit*/true);
411-
(void)cs.TC.typeCheckExpression(tuple, dc, TypeLoc::withoutLoc(ty),
412-
CTP_CallArgument);
413-
cs.cacheExprTypes(tuple);
413+
cs.setType(tuple, ty);
414+
tuple->setType(ty);
414415
return tuple;
415416
}
416417

@@ -4430,13 +4431,17 @@ namespace {
44304431
auto loc = origComponent.getLoc();
44314432
auto fieldName =
44324433
foundDecl->choice.getName().getBaseIdentifier().str();
4433-
auto index = buildDynamicMemberLookupIndexExpr(fieldName, indexType,
4434-
loc, dc, cs);
4435-
4434+
4435+
Expr *nameExpr = new (ctx) StringLiteralExpr(fieldName, loc,
4436+
/*implicit*/true);
4437+
(void)cs.TC.typeCheckExpression(nameExpr, dc);
4438+
cs.cacheExprTypes(nameExpr);
4439+
44364440
origComponent = KeyPathExpr::Component::
4437-
forUnresolvedSubscript(ctx, loc, index, {}, loc, loc,
4438-
/*trailingClosure*/nullptr);
4439-
cs.setType(origComponent.getIndexExpr(), index->getType());
4441+
forUnresolvedSubscript(ctx, loc,
4442+
{nameExpr}, {ctx.Id_dynamicMember}, {loc},
4443+
loc, /*trailingClosure*/nullptr);
4444+
cs.setType(origComponent.getIndexExpr(), indexType);
44404445
}
44414446

44424447
auto subscriptType =

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

validation-test/Sema/type_checker_perf/fast/rdar21720888.swift.gyb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
_ = [
66
%for i in range(0, N):
7-
(label: "string"),
7+
(label: "string", another: 123),
88
%end
99
]

0 commit comments

Comments
 (0)