Skip to content

Commit 9550d10

Browse files
committed
[Diagnostics] Add a diagnostic for single parameter tuple splat
Diagnose situation when a single "tuple" parameter is given N arguments e.g. ```swift func foo<T>(_ x: (T, Bool)) {} foo(1, false) // foo exptects a single argument of tuple type `(1, false)` ```
1 parent eb62708 commit 9550d10

File tree

7 files changed

+106
-42
lines changed

7 files changed

+106
-42
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3388,9 +3388,12 @@ ERROR(closure_tuple_parameter_destructuring_implicit,none,
33883388
ERROR(nested_tuple_parameter_destructuring,none,
33893389
"nested tuple parameter %0 of function %1 "
33903390
"does not support destructuring", (Type, Type))
3391-
ERROR(single_tuple_parameter_mismatch,none,
3392-
"%0 %select{|%1 }3expects a single parameter of type %2",
3393-
(DescriptiveDeclKind, Identifier, Type, bool))
3391+
ERROR(single_tuple_parameter_mismatch_special,none,
3392+
"%0 expects a single parameter of type %1",
3393+
(DescriptiveDeclKind, Type))
3394+
ERROR(single_tuple_parameter_mismatch_normal,none,
3395+
"%0 %1 expects a single parameter of type %2",
3396+
(DescriptiveDeclKind, DeclBaseName, Type))
33943397
ERROR(unknown_single_tuple_parameter_mismatch,none,
33953398
"single parameter of type %0 is expected in call", (Type))
33963399

lib/Sema/CSDiag.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,17 +3113,17 @@ static bool diagnoseTupleParameterMismatch(CalleeCandidateInfo &CCI,
31133113
auto &TC = CCI.CS.TC;
31143114
if (isTopLevel) {
31153115
if (auto *decl = CCI[0].getDecl()) {
3116-
Identifier name;
3117-
auto kind = decl->getDescriptiveKind();
3118-
// Constructors/descructors and subscripts don't really have names.
3119-
if (!(isa<ConstructorDecl>(decl) || isa<DestructorDecl>(decl) ||
3120-
isa<SubscriptDecl>(decl))) {
3121-
name = decl->getBaseName().getIdentifier();
3122-
}
3123-
3124-
TC.diagnose(argExpr->getLoc(), diag::single_tuple_parameter_mismatch,
3125-
kind, name, paramTupleTy, !name.empty())
3126-
.highlight(argExpr->getSourceRange())
3116+
auto name = decl->getBaseName();
3117+
auto diagnostic =
3118+
name.isSpecial()
3119+
? TC.diagnose(argExpr->getLoc(),
3120+
diag::single_tuple_parameter_mismatch_special,
3121+
decl->getDescriptiveKind(), paramType)
3122+
: TC.diagnose(argExpr->getLoc(),
3123+
diag::single_tuple_parameter_mismatch_normal,
3124+
decl->getDescriptiveKind(), name, paramType);
3125+
3126+
diagnostic.highlight(argExpr->getSourceRange())
31273127
.fixItInsertAfter(argExpr->getStartLoc(), "(")
31283128
.fixItInsert(argExpr->getEndLoc(), ")");
31293129
} else {

lib/Sema/CSDiagnostics.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3493,3 +3493,42 @@ bool MutatingMemberRefOnImmutableBase::diagnoseAsError() {
34933493
diagIDmember);
34943494
return failure.diagnoseAsError();
34953495
}
3496+
3497+
bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() {
3498+
auto *anchor = getRawAnchor();
3499+
3500+
auto selectedOverload = getChoiceFor(anchor);
3501+
if (!selectedOverload || !selectedOverload->choice.isDecl())
3502+
return false;
3503+
3504+
auto *choice = selectedOverload->choice.getDecl();
3505+
3506+
auto *argExpr = getArgumentExprFor(anchor);
3507+
if (!argExpr)
3508+
return false;
3509+
3510+
auto paramTy = ParamType.transform([&](Type type) -> Type {
3511+
if (auto *typeVar = type->getAs<TypeVariableType>()) {
3512+
auto *GP = typeVar->getImpl().getGenericParameter();
3513+
return GP ? GP : resolveType(typeVar);
3514+
}
3515+
3516+
return type;
3517+
});
3518+
3519+
DeclBaseName name = choice->getBaseName();
3520+
3521+
auto diagnostic =
3522+
name.isSpecial()
3523+
? emitDiagnostic(argExpr->getLoc(),
3524+
diag::single_tuple_parameter_mismatch_special,
3525+
choice->getDescriptiveKind(), paramTy)
3526+
: emitDiagnostic(argExpr->getLoc(),
3527+
diag::single_tuple_parameter_mismatch_normal,
3528+
choice->getDescriptiveKind(), name, paramTy);
3529+
3530+
diagnostic.highlight(argExpr->getSourceRange())
3531+
.fixItInsertAfter(argExpr->getStartLoc(), "(")
3532+
.fixItInsert(argExpr->getEndLoc(), ")");
3533+
return true;
3534+
}

lib/Sema/CSDiagnostics.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,6 +1457,25 @@ class SkipUnhandledConstructInFunctionBuilderFailure final
14571457
bool diagnoseAsNote() override;
14581458
};
14591459

1460+
/// Diagnose situation when a single "tuple" parameter is given N arguments e.g.
1461+
///
1462+
/// ```swift
1463+
/// func foo<T>(_ x: (T, Bool)) {}
1464+
/// foo(1, false) // foo exptects a single argument of tuple type `(1, false)`
1465+
/// ```
1466+
class InvalidTupleSplatWithSingleParameterFailure final
1467+
: public FailureDiagnostic {
1468+
Type ParamType;
1469+
1470+
public:
1471+
InvalidTupleSplatWithSingleParameterFailure(Expr *root, ConstraintSystem &cs,
1472+
Type paramTy,
1473+
ConstraintLocator *locator)
1474+
: FailureDiagnostic(root, cs, locator), ParamType(paramTy) {}
1475+
1476+
bool diagnoseAsError() override;
1477+
};
1478+
14601479
/// Provides information about the application of a function argument to a
14611480
/// parameter.
14621481
class FunctionArgApplyInfo {

lib/Sema/CSFix.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,10 @@ AllowMutatingMemberOnRValueBase::create(ConstraintSystem &cs, Type baseType,
659659
}
660660

661661
bool AllowTupleSplatForSingleParameter::diagnose(Expr *root, bool asNote) const {
662-
return false;
662+
auto &cs = getConstraintSystem();
663+
InvalidTupleSplatWithSingleParameterFailure failure(root, cs, ParamType,
664+
getLocator());
665+
return failure.diagnose(asNote);
663666
}
664667

665668
bool AllowTupleSplatForSingleParameter::attempt(

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ ConstraintLocator *ConstraintSystem::getCalleeLocator(Expr *expr) {
433433
ConstraintLocator::ConstructorMember);
434434
}
435435
// Otherwise fall through and look for locators anchored on the fn expr.
436-
expr = fnExpr;
436+
expr = fnExpr->getSemanticsProvidingExpr();
437437
}
438438

439439
auto *locator = getConstraintLocator(expr);

test/Constraints/tuple_arguments.swift

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ do {
466466
s.functionTwo(3, 4)
467467
s.functionTwo((3, 4)) // expected-error {{missing argument for parameter #2 in call}}
468468

469-
s.functionTuple(3, 4) // expected-error {{single parameter of type '(Int, Int)' is expected in call}} {{19-19=(}} {{23-23=)}}
469+
s.functionTuple(3, 4) // expected-error {{property 'functionTuple' expects a single parameter of type '(Int, Int)'}} {{19-19=(}} {{23-23=)}}
470470
s.functionTuple((3, 4))
471471
}
472472

@@ -487,7 +487,7 @@ do {
487487
s.functionTwo(d) // expected-error {{missing argument for parameter #2 in call}}
488488

489489

490-
s.functionTuple(a, b) // expected-error {{single parameter of type '(Int, Int)' is expected in call}} {{19-19=(}} {{23-23=)}}
490+
s.functionTuple(a, b) // expected-error {{property 'functionTuple' expects a single parameter of type '(Int, Int)'}} {{19-19=(}} {{23-23=)}}
491491
s.functionTuple((a, b))
492492
s.functionTuple(d)
493493
}
@@ -508,7 +508,7 @@ do {
508508
s.functionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
509509
s.functionTwo(d) // expected-error {{missing argument for parameter #2 in call}}
510510

511-
s.functionTuple(a, b) // expected-error {{single parameter of type '(Int, Int)' is expected in call}} {{19-19=(}} {{23-23=)}}
511+
s.functionTuple(a, b) // expected-error {{property 'functionTuple' expects a single parameter of type '(Int, Int)'}} {{19-19=(}} {{23-23=)}}
512512
s.functionTuple((a, b))
513513
s.functionTuple(d)
514514
}
@@ -848,12 +848,12 @@ do {
848848
s.genericFunctionTwo(3.0, 4.0)
849849
s.genericFunctionTwo((3.0, 4.0)) // expected-error {{missing argument for parameter #2 in call}}
850850

851-
s.genericFunctionTuple(3.0, 4.0) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{26-26=(}} {{34-34=)}}
851+
s.genericFunctionTuple(3.0, 4.0) // expected-error {{property 'genericFunctionTuple' expects a single parameter of type '(Double, Double)'}} {{26-26=(}} {{34-34=)}}
852852
s.genericFunctionTuple((3.0, 4.0))
853853

854854
let sTwo = Generic<(Double, Double)>()
855855

856-
sTwo.genericFunction(3.0, 4.0) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{32-32=)}}
856+
sTwo.genericFunction(3.0, 4.0) // expected-error {{property 'genericFunction' expects a single parameter of type '(Double, Double)'}} {{24-24=(}} {{32-32=)}}
857857
sTwo.genericFunction((3.0, 4.0))
858858
}
859859

@@ -872,12 +872,12 @@ do {
872872
s.genericFunctionTwo(a, b)
873873
s.genericFunctionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
874874

875-
s.genericFunctionTuple(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{26-26=(}} {{30-30=)}}
875+
s.genericFunctionTuple(a, b) // expected-error {{property 'genericFunctionTuple' expects a single parameter of type '(Double, Double)'}} {{26-26=(}} {{30-30=)}}
876876
s.genericFunctionTuple((a, b))
877877

878878
let sTwo = Generic<(Double, Double)>()
879879

880-
sTwo.genericFunction(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{28-28=)}}
880+
sTwo.genericFunction(a, b) // expected-error {{property 'genericFunction' expects a single parameter of type '(Double, Double)'}} {{24-24=(}} {{28-28=)}}
881881
sTwo.genericFunction((a, b))
882882
sTwo.genericFunction(d)
883883
}
@@ -897,12 +897,12 @@ do {
897897
s.genericFunctionTwo(a, b)
898898
s.genericFunctionTwo((a, b)) // expected-error {{missing argument for parameter #2 in call}}
899899

900-
s.genericFunctionTuple(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{26-26=(}} {{30-30=)}}
900+
s.genericFunctionTuple(a, b) // expected-error {{property 'genericFunctionTuple' expects a single parameter of type '(Double, Double)'}} {{26-26=(}} {{30-30=)}}
901901
s.genericFunctionTuple((a, b))
902902

903903
var sTwo = Generic<(Double, Double)>()
904904

905-
sTwo.genericFunction(a, b) // expected-error {{single parameter of type '(Double, Double)' is expected in call}} {{24-24=(}} {{28-28=)}}
905+
sTwo.genericFunction(a, b) // expected-error {{property 'genericFunction' expects a single parameter of type '(Double, Double)'}} {{24-24=(}} {{28-28=)}}
906906
sTwo.genericFunction((a, b))
907907
sTwo.genericFunction(d)
908908
}
@@ -945,19 +945,19 @@ do {
945945
}
946946

947947
do {
948-
_ = GenericInit<(Int, Int)>(3, 4) // expected-error {{extra argument in call}}
948+
_ = GenericInit<(Int, Int)>(3, 4) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}}
949949
_ = GenericInit<(Int, Int)>((3, 4))
950950

951-
_ = GenericInitLabeled<(Int, Int)>(x: 3, 4) // expected-error {{extra argument in call}}
951+
_ = GenericInitLabeled<(Int, Int)>(x: 3, 4) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}}
952952
_ = GenericInitLabeled<(Int, Int)>(x: (3, 4))
953953

954954
_ = GenericInitTwo<Int>(3, 4)
955955
_ = GenericInitTwo<Int>((3, 4)) // expected-error {{missing argument for parameter #2 in call}}
956956

957-
_ = GenericInitTuple<Int>(3, 4) // expected-error {{initializer expects a single parameter of type '(T, T)'}} {{29-29=(}} {{33-33=)}}
957+
_ = GenericInitTuple<Int>(3, 4) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}} {{29-29=(}} {{33-33=)}}
958958
_ = GenericInitTuple<Int>((3, 4))
959959

960-
_ = GenericInitLabeledTuple<Int>(x: 3, 4) // expected-error {{initializer expects a single parameter of type '(T, T)'}}
960+
_ = GenericInitLabeledTuple<Int>(x: 3, 4) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}}
961961
_ = GenericInitLabeledTuple<Int>(x: (3, 4))
962962
}
963963

@@ -984,15 +984,15 @@ do {
984984
let b = 4
985985
let c = (a, b)
986986

987-
_ = GenericInit<(Int, Int)>(a, b) // expected-error {{extra argument in call}}
987+
_ = GenericInit<(Int, Int)>(a, b) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}}
988988
_ = GenericInit<(Int, Int)>((a, b))
989989
_ = GenericInit<(Int, Int)>(c)
990990

991991
_ = GenericInitTwo<Int>(a, b)
992992
_ = GenericInitTwo<Int>((a, b)) // expected-error {{missing argument for parameter #2 in call}}
993993
_ = GenericInitTwo<Int>(c) // expected-error {{missing argument for parameter #2 in call}}
994994

995-
_ = GenericInitTuple<Int>(a, b) // expected-error {{initializer expects a single parameter of type '(T, T)'}} {{29-29=(}} {{33-33=)}}
995+
_ = GenericInitTuple<Int>(a, b) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}} {{29-29=(}} {{33-33=)}}
996996
_ = GenericInitTuple<Int>((a, b))
997997
_ = GenericInitTuple<Int>(c)
998998
}
@@ -1020,15 +1020,15 @@ do {
10201020
var b = 4
10211021
var c = (a, b)
10221022

1023-
_ = GenericInit<(Int, Int)>(a, b) // expected-error {{extra argument in call}}
1023+
_ = GenericInit<(Int, Int)>(a, b) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}}
10241024
_ = GenericInit<(Int, Int)>((a, b))
10251025
_ = GenericInit<(Int, Int)>(c)
10261026

10271027
_ = GenericInitTwo<Int>(a, b)
10281028
_ = GenericInitTwo<Int>((a, b)) // expected-error {{missing argument for parameter #2 in call}}
10291029
_ = GenericInitTwo<Int>(c) // expected-error {{missing argument for parameter #2 in call}}
10301030

1031-
_ = GenericInitTuple<Int>(a, b) // expected-error {{initializer expects a single parameter of type '(T, T)'}} {{29-29=(}} {{33-33=)}}
1031+
_ = GenericInitTuple<Int>(a, b) // expected-error {{initializer expects a single parameter of type '(Int, Int)'}} {{29-29=(}} {{33-33=)}}
10321032
_ = GenericInitTuple<Int>((a, b))
10331033
_ = GenericInitTuple<Int>(c)
10341034
}
@@ -1055,23 +1055,23 @@ struct GenericSubscriptTuple<T> {
10551055

10561056
do {
10571057
let s1 = GenericSubscript<(Double, Double)>()
1058-
_ = s1[3.0, 4.0] // expected-error {{extra argument in call}}
1058+
_ = s1[3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{10-10=(}} {{18-18=)}}
10591059
_ = s1[(3.0, 4.0)]
10601060

10611061
let s1a = GenericSubscriptLabeled<(Double, Double)>()
1062-
_ = s1a [x: 3.0, 4.0] // expected-error {{extra argument in call}}
1062+
_ = s1a [x: 3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{12-12=(}} {{23-23=)}}
10631063
_ = s1a [x: (3.0, 4.0)]
10641064

10651065
let s2 = GenericSubscriptTwo<Double>()
10661066
_ = s2[3.0, 4.0]
10671067
_ = s2[(3.0, 4.0)] // expected-error {{missing argument for parameter #2 in call}}
10681068

10691069
let s3 = GenericSubscriptTuple<Double>()
1070-
_ = s3[3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(T, T)'}} {{10-10=(}} {{18-18=)}}
1070+
_ = s3[3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{10-10=(}} {{18-18=)}}
10711071
_ = s3[(3.0, 4.0)]
10721072

10731073
let s3a = GenericSubscriptLabeledTuple<Double>()
1074-
_ = s3a[x: 3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(T, T)'}}
1074+
_ = s3a[x: 3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{11-11=(}} {{22-22=)}}
10751075
_ = s3a[x: (3.0, 4.0)]
10761076
}
10771077

@@ -1081,7 +1081,7 @@ do {
10811081
let d = (a, b)
10821082

10831083
let s1 = GenericSubscript<(Double, Double)>()
1084-
_ = s1[a, b] // expected-error {{extra argument in call}}
1084+
_ = s1[a, b] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{10-10=(}} {{14-14=)}}
10851085
_ = s1[(a, b)]
10861086
_ = s1[d]
10871087

@@ -1091,7 +1091,7 @@ do {
10911091
_ = s2[d] // expected-error {{missing argument for parameter #2 in call}}
10921092

10931093
let s3 = GenericSubscriptTuple<Double>()
1094-
_ = s3[a, b] // expected-error {{subscript expects a single parameter of type '(T, T)'}} {{10-10=(}} {{14-14=)}}
1094+
_ = s3[a, b] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{10-10=(}} {{14-14=)}}
10951095
_ = s3[(a, b)]
10961096
_ = s3[d]
10971097
}
@@ -1103,7 +1103,7 @@ do {
11031103
var d = (a, b) // e/xpected-warning {{variable 'd' was never mutated; consider changing to 'let' constant}}
11041104

11051105
var s1 = GenericSubscript<(Double, Double)>()
1106-
_ = s1[a, b] // expected-error {{extra argument in call}}
1106+
_ = s1[a, b] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{10-10=(}} {{14-14=)}}
11071107
_ = s1[(a, b)]
11081108
_ = s1[d]
11091109

@@ -1113,7 +1113,7 @@ do {
11131113
_ = s2[d] // expected-error {{missing argument for parameter #2 in call}}
11141114

11151115
var s3 = GenericSubscriptTuple<Double>()
1116-
_ = s3[a, b] // expected-error {{subscript expects a single parameter of type '(T, T)'}} {{10-10=(}} {{14-14=)}}
1116+
_ = s3[a, b] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{10-10=(}} {{14-14=)}}
11171117
_ = s3[(a, b)]
11181118
_ = s3[d]
11191119
}
@@ -1754,4 +1754,4 @@ func noescapeSplat() {
17541754
// expected-error@-1 {{converting non-escaping value to 'T' may allow it to escape}}
17551755
takesEscaping(t.0)
17561756
}
1757-
}
1757+
}

0 commit comments

Comments
 (0)