Skip to content

Commit b463f52

Browse files
authored
Merge pull request #21343 from slavapestov/one-element-tuple
Ban one element tuples harder
2 parents eb13640 + 8cfe737 commit b463f52

File tree

6 files changed

+60
-22
lines changed

6 files changed

+60
-22
lines changed

lib/Sema/CSApply.cpp

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

385387
// Build a tuple so that the argument has a label.
386388
Expr *tuple = TupleExpr::create(ctx, loc, nameExpr, ctx.Id_dynamicMember,
387389
loc, loc, /*hasTrailingClosure*/false,
388390
/*implicit*/true);
389-
(void)cs.TC.typeCheckExpression(tuple, dc, TypeLoc::withoutLoc(ty),
390-
CTP_CallArgument);
391-
cs.cacheExprTypes(tuple);
391+
cs.setType(tuple, ty);
392+
tuple->setType(ty);
392393
return tuple;
393394
}
394395

@@ -4410,13 +4411,17 @@ namespace {
44104411
auto loc = origComponent.getLoc();
44114412
auto fieldName =
44124413
foundDecl->choice.getName().getBaseIdentifier().str();
4413-
auto index = buildDynamicMemberLookupIndexExpr(fieldName, indexType,
4414-
loc, dc, cs);
4415-
4414+
4415+
Expr *nameExpr = new (ctx) StringLiteralExpr(fieldName, loc,
4416+
/*implicit*/true);
4417+
(void)cs.TC.typeCheckExpression(nameExpr, dc);
4418+
cs.cacheExprTypes(nameExpr);
4419+
44164420
origComponent = KeyPathExpr::Component::
4417-
forUnresolvedSubscript(ctx, loc, index, {}, loc, loc,
4418-
/*trailingClosure*/nullptr);
4419-
cs.setType(origComponent.getIndexExpr(), index->getType());
4421+
forUnresolvedSubscript(ctx, loc,
4422+
{nameExpr}, {ctx.Id_dynamicMember}, {loc},
4423+
loc, /*trailingClosure*/nullptr);
4424+
cs.setType(origComponent.getIndexExpr(), indexType);
44204425
}
44214426

44224427
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

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -710,11 +710,11 @@ GenericEnvironment *TypeChecker::checkGenericEnvironment(
710710
if (recursivelyVisitGenericParams) {
711711
visitOuterToInner(genericParams,
712712
[&](GenericParamList *gpList) {
713-
auto genericParamsDC = gpList->begin()[0]->getDeclContext();
714-
TypeResolution structuralResolution =
715-
TypeResolution::forStructural(genericParamsDC);
716-
checkGenericParamList(*this, &builder, gpList, nullptr,
717-
structuralResolution);
713+
auto genericParamsDC = gpList->begin()[0]->getDeclContext();
714+
TypeResolution structuralResolution =
715+
TypeResolution::forStructural(genericParamsDC);
716+
checkGenericParamList(*this, &builder, gpList, nullptr,
717+
structuralResolution);
718718
});
719719
} else {
720720
auto genericParamsDC = genericParams->begin()[0]->getDeclContext();

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)