Skip to content

Commit feba36c

Browse files
committed
---
yaml --- r: 349177 b: refs/heads/master-next c: ee8c78e h: refs/heads/master i: 349175: d08625e
1 parent 56cec98 commit feba36c

File tree

8 files changed

+203
-107
lines changed

8 files changed

+203
-107
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3574c513bbc5578dd9346b4ea9ab5995c5927bb5
3-
refs/heads/master-next: b8528cd5750a95779411863747f4babbc8072164
3+
refs/heads/master-next: ee8c78eef532c3802301fdd01142c5aa66e65834
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3493,6 +3493,10 @@ ERROR(single_tuple_parameter_mismatch_normal,none,
34933493
(DescriptiveDeclKind, DeclBaseName, Type, StringRef))
34943494
ERROR(unknown_single_tuple_parameter_mismatch,none,
34953495
"single parameter of type %0 is expected in call", (Type))
3496+
ERROR(cannot_convert_single_tuple_into_multiple_arguments,none,
3497+
"%0 %select{%1 |}2expects %3 separate arguments"
3498+
"%select{|; remove extra parentheses to change tuple into separate arguments}4",
3499+
(DescriptiveDeclKind, DeclName, bool, unsigned, bool))
34963500

34973501
ERROR(enum_element_pattern_assoc_values_mismatch,none,
34983502
"pattern with associated values does not match enum case %0",

branches/master-next/lib/Sema/CSDiagnostics.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3522,6 +3522,9 @@ bool AllowTypeOrInstanceMemberFailure::diagnoseAsError() {
35223522
return true;
35233523
}
35243524

3525+
if (diagnoseInvalidTupleDestructuring())
3526+
return true;
3527+
35253528
return false;
35263529
}
35273530

@@ -3585,7 +3588,8 @@ bool MissingArgumentsFailure::diagnoseAsError() {
35853588
// TODO: Currently this is only intended to diagnose contextual failures.
35863589
if (path.empty() ||
35873590
!(path.back().getKind() == ConstraintLocator::ApplyArgToParam ||
3588-
path.back().getKind() == ConstraintLocator::ContextualType))
3591+
path.back().getKind() == ConstraintLocator::ContextualType ||
3592+
path.back().getKind() == ConstraintLocator::ApplyArgument))
35893593
return false;
35903594

35913595
auto *anchor = getAnchor();
@@ -3694,6 +3698,55 @@ bool MissingArgumentsFailure::diagnoseClosure(ClosureExpr *closure) {
36943698
return true;
36953699
}
36963700

3701+
bool MissingArgumentsFailure::diagnoseInvalidTupleDestructuring() const {
3702+
auto *locator = getLocator();
3703+
if (!locator->isLastElement(ConstraintLocator::ApplyArgument))
3704+
return false;
3705+
3706+
if (SynthesizedArgs.size() < 2)
3707+
return false;
3708+
3709+
auto *anchor = getAnchor();
3710+
3711+
Expr *argExpr = nullptr;
3712+
// Something like `foo(x: (1, 2))`
3713+
if (auto *TE = dyn_cast<TupleExpr>(anchor)) {
3714+
if (TE->getNumElements() == 1)
3715+
argExpr = TE->getElement(0);
3716+
} else { // or `foo((1, 2))`
3717+
argExpr = cast<ParenExpr>(anchor)->getSubExpr();
3718+
}
3719+
3720+
if (!(argExpr && getType(argExpr)->getRValueType()->is<TupleType>()))
3721+
return false;
3722+
3723+
auto selectedOverload = getChoiceFor(locator);
3724+
if (!selectedOverload)
3725+
return false;
3726+
3727+
auto *decl = selectedOverload->choice.getDeclOrNull();
3728+
if (!decl)
3729+
return false;
3730+
3731+
auto name = decl->getBaseName();
3732+
auto diagnostic =
3733+
emitDiagnostic(anchor->getLoc(),
3734+
diag::cannot_convert_single_tuple_into_multiple_arguments,
3735+
decl->getDescriptiveKind(), name, name.isSpecial(),
3736+
SynthesizedArgs.size(), isa<TupleExpr>(argExpr));
3737+
3738+
// If argument is a literal tuple, let's suggest removal of parentheses.
3739+
if (auto *TE = dyn_cast<TupleExpr>(argExpr)) {
3740+
diagnostic.fixItRemove(TE->getLParenLoc()).fixItRemove(TE->getRParenLoc());
3741+
}
3742+
3743+
diagnostic.flush();
3744+
3745+
// Add a note which points to the overload choice location.
3746+
emitDiagnostic(decl, diag::decl_declared_here, decl->getFullName());
3747+
return true;
3748+
}
3749+
36973750
bool ClosureParamDestructuringFailure::diagnoseAsError() {
36983751
auto *closure = cast<ClosureExpr>(getAnchor());
36993752
auto params = closure->getParameters();

branches/master-next/lib/Sema/CSDiagnostics.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,10 @@ class MissingArgumentsFailure final : public FailureDiagnostic {
12011201
/// If missing arguments come from a closure,
12021202
/// let's produce tailored diagnostics.
12031203
bool diagnoseClosure(ClosureExpr *closure);
1204+
1205+
/// Diagnose cases when instead of multiple distinct arguments
1206+
/// call got a single tuple argument with expected arity/types.
1207+
bool diagnoseInvalidTupleDestructuring() const;
12041208
};
12051209

12061210
class OutOfOrderArgumentFailure final : public FailureDiagnostic {

branches/master-next/lib/Sema/CSSimplify.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,40 @@ ConstraintSystem::TypeMatchResult constraints::matchCallArguments(
930930
argsWithLabels.append(args.begin(), args.end());
931931
AnyFunctionType::relabelParams(argsWithLabels, argLabels);
932932

933+
// Special case when a single tuple argument if used
934+
// instead of N distinct arguments e.g.:
935+
//
936+
// func foo(_ x: Int, _ y: Int) {}
937+
// foo((1, 2)) // expected 2 arguments, got a single tuple with 2 elements.
938+
if (cs.shouldAttemptFixes() && argsWithLabels.size() == 1 &&
939+
llvm::count_if(indices(params), [&](unsigned paramIdx) {
940+
return !paramInfo.hasDefaultArgument(paramIdx);
941+
}) > 1) {
942+
const auto &arg = argsWithLabels.front();
943+
auto argTuple = arg.getPlainType()->getRValueType()->getAs<TupleType>();
944+
// Don't explode a tuple in cases where first parameter is a tuple as
945+
// well. That is a regular "missing argument case" even if their arity
946+
// is different e.g.
947+
//
948+
// func foo(_: (Int, Int), _: Int) {}
949+
// foo((1, 2)) // call is missing an argument for parameter #1
950+
if (argTuple && argTuple->getNumElements() == params.size() &&
951+
!params.front().getPlainType()->is<TupleType>()) {
952+
argsWithLabels.pop_back();
953+
// Let's make sure that labels associated with tuple elements
954+
// line up with what is expected by argument list.
955+
for (const auto &arg : argTuple->getElements()) {
956+
argsWithLabels.push_back(
957+
AnyFunctionType::Param(arg.getType(), arg.getName()));
958+
}
959+
960+
(void)cs.recordFix(
961+
AddMissingArguments::create(cs, argsWithLabels,
962+
cs.getConstraintLocator(locator)),
963+
/*impact=*/argsWithLabels.size() * 2);
964+
}
965+
}
966+
933967
// Match up the call arguments to the parameters.
934968
SmallVector<ParamBinding, 4> parameterBindings;
935969
{

branches/master-next/lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,11 +2913,12 @@ void constraints::simplifyLocator(Expr *&anchor,
29132913

29142914
// Extract subexpression in parentheses.
29152915
if (auto parenExpr = dyn_cast<ParenExpr>(anchor)) {
2916-
assert(elt.getArgIdx() == 0);
2917-
2918-
anchor = parenExpr->getSubExpr();
2919-
path = path.slice(1);
2920-
continue;
2916+
// This simplication request could be for a synthesized argument.
2917+
if (elt.getArgIdx() == 0) {
2918+
anchor = parenExpr->getSubExpr();
2919+
path = path.slice(1);
2920+
continue;
2921+
}
29212922
}
29222923
break;
29232924
}

0 commit comments

Comments
 (0)