Skip to content

Commit bc1a3ea

Browse files
authored
Merge pull request #27584 from xedin/extend-use-of-single-param-splat-fix
[Diagnostics] Extend single parameter tuple splat to support generic parameters
2 parents 0587470 + 51476cd commit bc1a3ea

File tree

6 files changed

+109
-41
lines changed

6 files changed

+109
-41
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3493,6 +3493,8 @@ ERROR(single_tuple_parameter_mismatch_special,none,
34933493
ERROR(single_tuple_parameter_mismatch_normal,none,
34943494
"%0 %1 expects a single parameter of type %2%3",
34953495
(DescriptiveDeclKind, DeclBaseName, Type, StringRef))
3496+
NOTE(note_maybe_forgot_to_form_tuple,none,
3497+
"did you mean to pass a tuple?", ())
34963498
ERROR(unknown_single_tuple_parameter_mismatch,none,
34973499
"single parameter of type %0 is expected in call", (Type))
34983500
ERROR(cannot_convert_single_tuple_into_multiple_arguments,none,

lib/Sema/CSDiagnostics.cpp

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4880,13 +4880,49 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() {
48804880
? emitDiagnostic(argExpr->getLoc(),
48814881
diag::single_tuple_parameter_mismatch_special,
48824882
choice->getDescriptiveKind(), paramTy, subsStr)
4883-
: emitDiagnostic(
4884-
argExpr->getLoc(), diag::single_tuple_parameter_mismatch_normal,
4885-
choice->getDescriptiveKind(), name, paramTy, subsStr);
4883+
: emitDiagnostic(argExpr->getLoc(),
4884+
diag::single_tuple_parameter_mismatch_normal,
4885+
choice->getDescriptiveKind(), name, paramTy, subsStr);
4886+
4887+
4888+
auto newLeftParenLoc = argExpr->getStartLoc();
4889+
if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {
4890+
auto firstArgLabel = TE->getElementName(0);
4891+
// Cover situations like:
4892+
//
4893+
// func foo(x: (Int, Int)) {}
4894+
// foo(x: 0, 1)
4895+
//
4896+
// Where left paren should be suggested after the label,
4897+
// since the label belongs to the parameter itself.
4898+
if (!firstArgLabel.empty()) {
4899+
auto paramTuple = resolveType(ParamType)->castTo<TupleType>();
4900+
// If the label of the first argument matches the one required
4901+
// by the parameter it would be omitted from the fixed parameter type.
4902+
if (!paramTuple->getElement(0).hasName())
4903+
newLeftParenLoc = Lexer::getLocForEndOfToken(getASTContext().SourceMgr,
4904+
TE->getElementNameLoc(0));
4905+
}
4906+
}
4907+
4908+
// If the parameter is a generic parameter, it's hard to say
4909+
// whether use of a tuple is really intended here, so let's
4910+
// attach a fix-it to a note instead of the diagnostic message
4911+
// to indicate that it's not the only right solution possible.
4912+
if (auto *typeVar = ParamType->getAs<TypeVariableType>()) {
4913+
if (typeVar->getImpl().getGenericParameter()) {
4914+
diagnostic.flush();
4915+
4916+
emitDiagnostic(argExpr->getLoc(), diag::note_maybe_forgot_to_form_tuple)
4917+
.fixItInsertAfter(newLeftParenLoc, "(")
4918+
.fixItInsert(argExpr->getEndLoc(), ")");
4919+
}
4920+
} else {
4921+
diagnostic.highlight(argExpr->getSourceRange())
4922+
.fixItInsertAfter(newLeftParenLoc, "(")
4923+
.fixItInsert(argExpr->getEndLoc(), ")");
4924+
}
48864925

4887-
diagnostic.highlight(argExpr->getSourceRange())
4888-
.fixItInsertAfter(argExpr->getStartLoc(), "(")
4889-
.fixItInsert(argExpr->getEndLoc(), ")");
48904926
return true;
48914927
}
48924928

lib/Sema/CSFix.cpp

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -707,14 +707,42 @@ bool AllowTupleSplatForSingleParameter::attempt(
707707

708708
const auto &param = params.front();
709709

710-
auto *paramTy = param.getOldType()->getAs<TupleType>();
711-
if (!paramTy || paramTy->getNumElements() != args.size())
710+
if (param.isInOut() || param.isVariadic() || param.isAutoClosure())
711+
return true;
712+
713+
auto paramTy = param.getOldType();
714+
715+
// Parameter type has to be either a tuple (with the same arity as
716+
// argument list), or a type variable.
717+
if (!(paramTy->is<TupleType>() &&
718+
paramTy->castTo<TupleType>()->getNumElements() == args.size()) &&
719+
!paramTy->is<TypeVariableType>())
712720
return true;
713721

714722
SmallVector<TupleTypeElt, 4> argElts;
715-
for (const auto &arg : args) {
716-
argElts.push_back(
717-
{arg.getPlainType(), arg.getLabel(), arg.getParameterFlags()});
723+
724+
for (unsigned index : indices(args)) {
725+
const auto &arg = args[index];
726+
727+
auto label = arg.getLabel();
728+
auto flags = arg.getParameterFlags();
729+
730+
// In situations where there is a single labeled parameter
731+
// we need to form a tuple with omits first label e.g.
732+
//
733+
// func foo<T>(x: T) {}
734+
// foo(x: 0, 1)
735+
//
736+
// We'd want to suggest argument list to be `x: (0, 1)` instead
737+
// of `(x: 0, 1)` which would be incorrect.
738+
if (index == 0 && param.getLabel() == label)
739+
label = Identifier();
740+
741+
// Tuple can't have `inout` elements.
742+
if (flags.isInOut())
743+
return true;
744+
745+
argElts.push_back({arg.getPlainType(), label});
718746
}
719747

720748
bindings[0].clear();

test/Constraints/enum_cases.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ enum E_32551313<L, R> {
104104

105105
struct Foo_32551313 {
106106
static func bar() -> E_32551313<(String, Foo_32551313?), (String, String)>? {
107-
return E_32551313.Left("", Foo_32551313()) // expected-error {{extra argument in call}}
107+
return E_32551313.Left("", Foo_32551313()) // expected-error {{enum case 'Left' expects a single parameter of type 'L' [with L = (String, Foo_32551313?)]}}
108+
// expected-note@-1 {{did you mean to pass a tuple?}} {{28-28=(}} {{46-46=)}}
108109
}
109110
}
110111

test/Constraints/tuple_arguments.swift

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ func genericTuple<T, U>(_ x: (T, U)) {}
6969

7070
do {
7171
generic(3)
72-
generic(3, 4) // expected-error {{extra argument in call}}
72+
generic(3, 4) // expected-error {{global function 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{11-11=(}} {{15-15=)}}
7373
generic((3))
7474
generic((3, 4))
7575

7676
genericLabeled(x: 3)
77-
genericLabeled(x: 3, 4) // expected-error {{extra argument in call}}
77+
genericLabeled(x: 3, 4) // expected-error {{global function 'genericLabeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{20-20=(}} {{25-25=)}}
7878
genericLabeled(x: (3))
7979
genericLabeled(x: (3, 4))
8080

@@ -92,7 +92,7 @@ do {
9292
let d = (a, b)
9393

9494
generic(a)
95-
generic(a, b) // expected-error {{extra argument in call}}
95+
generic(a, b) // expected-error {{global function 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{11-11=(}} {{15-15=)}}
9696
generic((a))
9797
generic(c)
9898
generic((a, b))
@@ -114,7 +114,7 @@ do {
114114
var d = (a, b)
115115

116116
generic(a)
117-
generic(a, b) // expected-error {{extra argument in call}}
117+
generic(a, b) // expected-error {{global function 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{11-11=(}} {{15-15=)}}
118118
generic((a))
119119
generic(c)
120120
generic((a, b))
@@ -256,12 +256,12 @@ do {
256256
let s = Concrete()
257257

258258
s.generic(3)
259-
s.generic(3, 4) // expected-error {{extra argument in call}}
259+
s.generic(3, 4) // expected-error {{instance method 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{13-13=(}} {{17-17=)}}
260260
s.generic((3))
261261
s.generic((3, 4))
262262

263263
s.genericLabeled(x: 3)
264-
s.genericLabeled(x: 3, 4) // expected-error {{extra argument in call}}
264+
s.genericLabeled(x: 3, 4) // expected-error {{instance method 'genericLabeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{22-22=(}} {{27-27=)}}
265265
s.genericLabeled(x: (3))
266266
s.genericLabeled(x: (3, 4))
267267

@@ -281,7 +281,7 @@ do {
281281
let d = (a, b)
282282

283283
s.generic(a)
284-
s.generic(a, b) // expected-error {{extra argument in call}}
284+
s.generic(a, b) // expected-error {{instance method 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{13-13=(}} {{17-17=)}}
285285
s.generic((a))
286286
s.generic((a, b))
287287
s.generic(d)
@@ -304,7 +304,7 @@ do {
304304
var d = (a, b)
305305

306306
s.generic(a)
307-
s.generic(a, b) // expected-error {{extra argument in call}}
307+
s.generic(a, b) // expected-error {{instance method 'generic' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{13-13=(}} {{17-17=)}}
308308
s.generic((a))
309309
s.generic((a, b))
310310
s.generic(d)
@@ -390,12 +390,12 @@ do {
390390
var s = Concrete()
391391

392392
s.mutatingGeneric(3)
393-
s.mutatingGeneric(3, 4) // expected-error {{extra argument in call}}
393+
s.mutatingGeneric(3, 4) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{21-21=(}} {{25-25=)}}
394394
s.mutatingGeneric((3))
395395
s.mutatingGeneric((3, 4))
396396

397397
s.mutatingGenericLabeled(x: 3)
398-
s.mutatingGenericLabeled(x: 3, 4) // expected-error {{extra argument in call}}
398+
s.mutatingGenericLabeled(x: 3, 4) // expected-error {{instance method 'mutatingGenericLabeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{30-30=(}} {{35-35=)}}
399399
s.mutatingGenericLabeled(x: (3))
400400
s.mutatingGenericLabeled(x: (3, 4))
401401

@@ -415,7 +415,7 @@ do {
415415
let d = (a, b)
416416

417417
s.mutatingGeneric(a)
418-
s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
418+
s.mutatingGeneric(a, b) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{21-21=(}} {{25-25=)}}
419419
s.mutatingGeneric((a))
420420
s.mutatingGeneric((a, b))
421421
s.mutatingGeneric(d)
@@ -438,7 +438,7 @@ do {
438438
var d = (a, b)
439439

440440
s.mutatingGeneric(a)
441-
s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
441+
s.mutatingGeneric(a, b) // expected-error {{instance method 'mutatingGeneric' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{21-21=(}} {{25-25=)}}
442442
s.mutatingGeneric((a))
443443
s.mutatingGeneric((a, b))
444444
s.mutatingGeneric(d)
@@ -929,10 +929,10 @@ struct GenericInitLabeledTuple<T> {
929929
}
930930

931931
do {
932-
_ = GenericInit(3, 4) // expected-error {{extra argument in call}}
932+
_ = GenericInit(3, 4) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{19-19=(}} {{23-23=)}}
933933
_ = GenericInit((3, 4))
934934

935-
_ = GenericInitLabeled(x: 3, 4) // expected-error {{extra argument in call}}
935+
_ = GenericInitLabeled(x: 3, 4) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{28-28=(}} {{33-33=)}}
936936
_ = GenericInitLabeled(x: (3, 4))
937937

938938
_ = GenericInitTwo(3, 4)
@@ -967,7 +967,7 @@ do {
967967
let b = 4
968968
let c = (a, b)
969969

970-
_ = GenericInit(a, b) // expected-error {{extra argument in call}}
970+
_ = GenericInit(a, b) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{19-19=(}} {{23-23=)}}
971971
_ = GenericInit((a, b))
972972
_ = GenericInit(c)
973973

@@ -1003,7 +1003,7 @@ do {
10031003
var b = 4
10041004
var c = (a, b)
10051005

1006-
_ = GenericInit(a, b) // expected-error {{extra argument in call}}
1006+
_ = GenericInit(a, b) // expected-error {{initializer expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{19-19=(}} {{23-23=)}}
10071007
_ = GenericInit((a, b))
10081008
_ = GenericInit(c)
10091009

@@ -1060,7 +1060,7 @@ do {
10601060
_ = s1[(3.0, 4.0)]
10611061

10621062
let s1a = GenericSubscriptLabeled<(Double, Double)>()
1063-
_ = s1a [x: 3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{12-12=(}} {{23-23=)}}
1063+
_ = s1a [x: 3.0, 4.0] // expected-error {{subscript expects a single parameter of type '(Double, Double)'}} {{14-14=(}} {{23-23=)}}
10641064
_ = s1a [x: (3.0, 4.0)]
10651065

10661066
let s2 = GenericSubscriptTwo<Double>()
@@ -1072,7 +1072,7 @@ do {
10721072
_ = s3[(3.0, 4.0)]
10731073

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

@@ -1127,12 +1127,12 @@ enum GenericEnum<T> {
11271127
}
11281128

11291129
do {
1130-
_ = GenericEnum.one(3, 4) // expected-error {{extra argument in call}}
1130+
_ = GenericEnum.one(3, 4) // expected-error {{enum case 'one' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{23-23=(}} {{27-27=)}}
11311131
_ = GenericEnum.one((3, 4))
11321132

1133-
_ = GenericEnum.labeled(x: 3, 4) // expected-error {{extra argument in call}}
1133+
_ = GenericEnum.labeled(x: 3, 4) // expected-error {{enum case 'labeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{29-29=(}} {{34-34=)}}
11341134
_ = GenericEnum.labeled(x: (3, 4))
1135-
_ = GenericEnum.labeled(3, 4) // expected-error {{extra argument in call}}
1135+
_ = GenericEnum.labeled(3, 4) // expected-error {{enum case 'labeled' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{27-27=(}} {{31-31=)}}
11361136
_ = GenericEnum.labeled((3, 4)) // expected-error {{missing argument label 'x:' in call}}
11371137

11381138
_ = GenericEnum.two(3, 4)
@@ -1163,7 +1163,7 @@ do {
11631163
let b = 4
11641164
let c = (a, b)
11651165

1166-
_ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
1166+
_ = GenericEnum.one(a, b) // expected-error {{enum case 'one' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{23-23=(}} {{27-27=)}}
11671167
_ = GenericEnum.one((a, b))
11681168
_ = GenericEnum.one(c)
11691169

@@ -1199,7 +1199,7 @@ do {
11991199
var b = 4
12001200
var c = (a, b)
12011201

1202-
_ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
1202+
_ = GenericEnum.one(a, b) // expected-error {{enum case 'one' expects a single parameter of type 'T' [with T = (Int, Int)]}} expected-note {{did you mean to pass a tuple?}} {{23-23=(}} {{27-27=)}}
12031203
_ = GenericEnum.one((a, b))
12041204
_ = GenericEnum.one(c)
12051205

@@ -1262,10 +1262,10 @@ do {
12621262

12631263
let sTwo = GenericConforms<(Double, Double)>()
12641264

1265-
sTwo.requirement(3.0, 4.0) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{28-28=)}}
1265+
sTwo.requirement(3.0, 4.0) // expected-error {{instance method 'requirement' expects a single parameter of type 'GenericConforms<(Double, Double)>.Element' (aka '(Double, Double)')}} {{20-20=(}} {{28-28=)}}
12661266
sTwo.requirement((3.0, 4.0))
12671267

1268-
sTwo.requirementLabeled(x: 3.0, 4.0) // expected-error {{instance method 'requirementLabeled' expects a single parameter of type '(Double, Double)'}}
1268+
sTwo.requirementLabeled(x: 3.0, 4.0) // expected-error {{instance method 'requirementLabeled' expects a single parameter of type 'GenericConforms<(Double, Double)>.Element' (aka '(Double, Double)')}} {{29-29=(}} {{38-38=)}}
12691269
sTwo.requirementLabeled(x: (3.0, 4.0))
12701270
}
12711271

@@ -1289,7 +1289,7 @@ do {
12891289

12901290
let sTwo = GenericConforms<(Double, Double)>()
12911291

1292-
sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{24-24=)}}
1292+
sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type 'GenericConforms<(Double, Double)>.Element' (aka '(Double, Double)')}} {{20-20=(}} {{24-24=)}}
12931293
sTwo.requirement((a, b))
12941294
sTwo.requirement(d)
12951295
}
@@ -1314,7 +1314,7 @@ do {
13141314

13151315
var sTwo = GenericConforms<(Double, Double)>()
13161316

1317-
sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{24-24=)}}
1317+
sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type 'GenericConforms<(Double, Double)>.Element' (aka '(Double, Double)')}} {{20-20=(}} {{24-24=)}}
13181318
sTwo.requirement((a, b))
13191319
sTwo.requirement(d)
13201320
}

test/decl/var/property_wrappers.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,9 @@ struct Initialization {
235235
@Wrapper(stored: 17)
236236
var x2: Double
237237

238-
@Wrapper(stored: 17)
239-
var x3 = 42 // expected-error{{extra argument 'wrappedValue' in call}}
238+
@Wrapper(stored: 17) // expected-error {{initializer expects a single parameter of type 'T' [with T = (wrappedValue: Int, stored: Int)]}}
239+
// expected-note@-1 {{did you mean to pass a tuple?}}
240+
var x3 = 42
240241

241242
@Wrapper(stored: 17)
242243
var x4

0 commit comments

Comments
 (0)