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

Currently single parameter tuple splat fix/diagnostic supports only
cases where parameter is a concrete tuple type, let's enhance that to
support generic parameters as well e.g.:

```swift
func foo<T>(_: T) {}
foo(0, 1, 2) // `T` expects arguments to form a tuple e.g. `foo((0, 1, 2))`
```
This commit is contained in:
Pavel Yaskevich
2019-10-08 16:37:21 -07:00
parent 2b0444713a
commit 7e6b4e4d57
4 changed files with 61 additions and 33 deletions

View File

@@ -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();