Skip to content

[Diagnostics] Extend single parameter tuple splat to support generic parameters #27584

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -3493,6 +3493,8 @@ ERROR(single_tuple_parameter_mismatch_special,none,
ERROR(single_tuple_parameter_mismatch_normal,none,
"%0 %1 expects a single parameter of type %2%3",
(DescriptiveDeclKind, DeclBaseName, Type, StringRef))
NOTE(note_maybe_forgot_to_form_tuple,none,
"did you mean to pass a tuple?", ())
ERROR(unknown_single_tuple_parameter_mismatch,none,
"single parameter of type %0 is expected in call", (Type))
ERROR(cannot_convert_single_tuple_into_multiple_arguments,none,
Expand Down
48 changes: 42 additions & 6 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4880,13 +4880,49 @@ bool InvalidTupleSplatWithSingleParameterFailure::diagnoseAsError() {
? emitDiagnostic(argExpr->getLoc(),
diag::single_tuple_parameter_mismatch_special,
choice->getDescriptiveKind(), paramTy, subsStr)
: emitDiagnostic(
argExpr->getLoc(), diag::single_tuple_parameter_mismatch_normal,
choice->getDescriptiveKind(), name, paramTy, subsStr);
: emitDiagnostic(argExpr->getLoc(),
diag::single_tuple_parameter_mismatch_normal,
choice->getDescriptiveKind(), name, paramTy, subsStr);


auto newLeftParenLoc = argExpr->getStartLoc();
if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {
auto firstArgLabel = TE->getElementName(0);
// Cover situations like:
//
// func foo(x: (Int, Int)) {}
// foo(x: 0, 1)
//
// Where left paren should be suggested after the label,
// since the label belongs to the parameter itself.
if (!firstArgLabel.empty()) {
auto paramTuple = resolveType(ParamType)->castTo<TupleType>();
// If the label of the first argument matches the one required
// by the parameter it would be omitted from the fixed parameter type.
if (!paramTuple->getElement(0).hasName())
newLeftParenLoc = Lexer::getLocForEndOfToken(getASTContext().SourceMgr,
TE->getElementNameLoc(0));
}
}

// If the parameter is a generic parameter, it's hard to say
// whether use of a tuple is really intended here, so let's
// attach a fix-it to a note instead of the diagnostic message
// to indicate that it's not the only right solution possible.
if (auto *typeVar = ParamType->getAs<TypeVariableType>()) {
if (typeVar->getImpl().getGenericParameter()) {
diagnostic.flush();

emitDiagnostic(argExpr->getLoc(), diag::note_maybe_forgot_to_form_tuple)
.fixItInsertAfter(newLeftParenLoc, "(")
.fixItInsert(argExpr->getEndLoc(), ")");
}
} else {
diagnostic.highlight(argExpr->getSourceRange())
.fixItInsertAfter(newLeftParenLoc, "(")
.fixItInsert(argExpr->getEndLoc(), ")");
}

diagnostic.highlight(argExpr->getSourceRange())
.fixItInsertAfter(argExpr->getStartLoc(), "(")
.fixItInsert(argExpr->getEndLoc(), ")");
return true;
}

Expand Down
38 changes: 33 additions & 5 deletions lib/Sema/CSFix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,14 +707,42 @@ bool AllowTupleSplatForSingleParameter::attempt(

const auto &param = params.front();

auto *paramTy = param.getOldType()->getAs<TupleType>();
if (!paramTy || paramTy->getNumElements() != args.size())
if (param.isInOut() || param.isVariadic() || param.isAutoClosure())
return true;

auto paramTy = param.getOldType();

// Parameter type has to be either a tuple (with the same arity as
// argument list), or a type variable.
if (!(paramTy->is<TupleType>() &&
paramTy->castTo<TupleType>()->getNumElements() == args.size()) &&
!paramTy->is<TypeVariableType>())
return true;

SmallVector<TupleTypeElt, 4> argElts;
for (const auto &arg : args) {
argElts.push_back(
{arg.getPlainType(), arg.getLabel(), arg.getParameterFlags()});

for (unsigned index : indices(args)) {
const auto &arg = args[index];

auto label = arg.getLabel();
auto flags = arg.getParameterFlags();

// In situations where there is a single labeled parameter
// we need to form a tuple with omits first label e.g.
//
// func foo<T>(x: T) {}
// foo(x: 0, 1)
//
// We'd want to suggest argument list to be `x: (0, 1)` instead
// of `(x: 0, 1)` which would be incorrect.
if (index == 0 && param.getLabel() == label)
label = Identifier();

// Tuple can't have `inout` elements.
if (flags.isInOut())
return true;

argElts.push_back({arg.getPlainType(), label});
}

bindings[0].clear();
Expand Down
3 changes: 2 additions & 1 deletion test/Constraints/enum_cases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ enum E_32551313<L, R> {

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

Expand Down
54 changes: 27 additions & 27 deletions test/Constraints/tuple_arguments.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ func genericTuple<T, U>(_ x: (T, U)) {}

do {
generic(3)
generic(3, 4) // expected-error {{extra argument in call}}
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=)}}
generic((3))
generic((3, 4))

genericLabeled(x: 3)
genericLabeled(x: 3, 4) // expected-error {{extra argument in call}}
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=)}}
genericLabeled(x: (3))
genericLabeled(x: (3, 4))

Expand All @@ -92,7 +92,7 @@ do {
let d = (a, b)

generic(a)
generic(a, b) // expected-error {{extra argument in call}}
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=)}}
generic((a))
generic(c)
generic((a, b))
Expand All @@ -114,7 +114,7 @@ do {
var d = (a, b)

generic(a)
generic(a, b) // expected-error {{extra argument in call}}
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=)}}
generic((a))
generic(c)
generic((a, b))
Expand Down Expand Up @@ -256,12 +256,12 @@ do {
let s = Concrete()

s.generic(3)
s.generic(3, 4) // expected-error {{extra argument in call}}
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=)}}
s.generic((3))
s.generic((3, 4))

s.genericLabeled(x: 3)
s.genericLabeled(x: 3, 4) // expected-error {{extra argument in call}}
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=)}}
s.genericLabeled(x: (3))
s.genericLabeled(x: (3, 4))

Expand All @@ -281,7 +281,7 @@ do {
let d = (a, b)

s.generic(a)
s.generic(a, b) // expected-error {{extra argument in call}}
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=)}}
s.generic((a))
s.generic((a, b))
s.generic(d)
Expand All @@ -304,7 +304,7 @@ do {
var d = (a, b)

s.generic(a)
s.generic(a, b) // expected-error {{extra argument in call}}
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=)}}
s.generic((a))
s.generic((a, b))
s.generic(d)
Expand Down Expand Up @@ -390,12 +390,12 @@ do {
var s = Concrete()

s.mutatingGeneric(3)
s.mutatingGeneric(3, 4) // expected-error {{extra argument in call}}
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=)}}
s.mutatingGeneric((3))
s.mutatingGeneric((3, 4))

s.mutatingGenericLabeled(x: 3)
s.mutatingGenericLabeled(x: 3, 4) // expected-error {{extra argument in call}}
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=)}}
s.mutatingGenericLabeled(x: (3))
s.mutatingGenericLabeled(x: (3, 4))

Expand All @@ -415,7 +415,7 @@ do {
let d = (a, b)

s.mutatingGeneric(a)
s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
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=)}}
s.mutatingGeneric((a))
s.mutatingGeneric((a, b))
s.mutatingGeneric(d)
Expand All @@ -438,7 +438,7 @@ do {
var d = (a, b)

s.mutatingGeneric(a)
s.mutatingGeneric(a, b) // expected-error {{extra argument in call}}
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=)}}
s.mutatingGeneric((a))
s.mutatingGeneric((a, b))
s.mutatingGeneric(d)
Expand Down Expand Up @@ -929,10 +929,10 @@ struct GenericInitLabeledTuple<T> {
}

do {
_ = GenericInit(3, 4) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericInit((3, 4))

_ = GenericInitLabeled(x: 3, 4) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericInitLabeled(x: (3, 4))

_ = GenericInitTwo(3, 4)
Expand Down Expand Up @@ -967,7 +967,7 @@ do {
let b = 4
let c = (a, b)

_ = GenericInit(a, b) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericInit((a, b))
_ = GenericInit(c)

Expand Down Expand Up @@ -1003,7 +1003,7 @@ do {
var b = 4
var c = (a, b)

_ = GenericInit(a, b) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericInit((a, b))
_ = GenericInit(c)

Expand Down Expand Up @@ -1060,7 +1060,7 @@ do {
_ = s1[(3.0, 4.0)]

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

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

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

Expand Down Expand Up @@ -1127,12 +1127,12 @@ enum GenericEnum<T> {
}

do {
_ = GenericEnum.one(3, 4) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericEnum.one((3, 4))

_ = GenericEnum.labeled(x: 3, 4) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericEnum.labeled(x: (3, 4))
_ = GenericEnum.labeled(3, 4) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericEnum.labeled((3, 4)) // expected-error {{missing argument label 'x:' in call}}

_ = GenericEnum.two(3, 4)
Expand Down Expand Up @@ -1163,7 +1163,7 @@ do {
let b = 4
let c = (a, b)

_ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericEnum.one((a, b))
_ = GenericEnum.one(c)

Expand Down Expand Up @@ -1199,7 +1199,7 @@ do {
var b = 4
var c = (a, b)

_ = GenericEnum.one(a, b) // expected-error {{extra argument in call}}
_ = 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=)}}
_ = GenericEnum.one((a, b))
_ = GenericEnum.one(c)

Expand Down Expand Up @@ -1262,10 +1262,10 @@ do {

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

sTwo.requirement(3.0, 4.0) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{28-28=)}}
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=)}}
sTwo.requirement((3.0, 4.0))

sTwo.requirementLabeled(x: 3.0, 4.0) // expected-error {{instance method 'requirementLabeled' expects a single parameter of type '(Double, Double)'}}
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=)}}
sTwo.requirementLabeled(x: (3.0, 4.0))
}

Expand All @@ -1289,7 +1289,7 @@ do {

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

sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{24-24=)}}
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=)}}
sTwo.requirement((a, b))
sTwo.requirement(d)
}
Expand All @@ -1314,7 +1314,7 @@ do {

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

sTwo.requirement(a, b) // expected-error {{instance method 'requirement' expects a single parameter of type '(Double, Double)'}} {{20-20=(}} {{24-24=)}}
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=)}}
sTwo.requirement((a, b))
sTwo.requirement(d)
}
Expand Down
5 changes: 3 additions & 2 deletions test/decl/var/property_wrappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,9 @@ struct Initialization {
@Wrapper(stored: 17)
var x2: Double

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

@Wrapper(stored: 17)
var x4
Expand Down