Skip to content

Commit 18938ac

Browse files
committed
Fix single-arg-for-tuple-param check
In matchTypes(), we check whether a type variable representing an argument could potentially be bound to a single param in a TupleType rather than the whole TupleType, but this check has been pretty heuristic and ad hoc so far. Replace with an explicit check to see if it's possible for exactly one of the parameters in the tuple type can be bound to a single unlabeled argument. <rdar://problem/22913570>
1 parent 059bb7c commit 18938ac

File tree

2 files changed

+31
-31
lines changed

2 files changed

+31
-31
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,17 +1145,22 @@ static bool isArrayDictionarySetOrString(const ASTContext &ctx, Type type) {
11451145
return false;
11461146
}
11471147

1148-
/// Return the number of elements of parameter tuple type 'tupleTy' that must
1149-
/// be matched to arguments, as opposed to being varargs or having default
1150-
/// values.
1151-
static unsigned tupleTypeRequiredArgCount(TupleType *tupleTy) {
1152-
auto argIsRequired = [&](const TupleTypeElt &elt) {
1153-
return !elt.isVararg() &&
1154-
elt.getDefaultArgKind() == DefaultArgumentKind::None;
1155-
};
1156-
return std::count_if(
1157-
tupleTy->getElements().begin(), tupleTy->getElements().end(),
1158-
argIsRequired);
1148+
/// Given that 'tupleTy' is the argument type of a function that's being
1149+
/// invoked with a single unlabeled argument, return the type of the parameter
1150+
/// that matches that argument, or the null type if such a match is impossible.
1151+
static Type getTupleElementTypeForSingleArgument(TupleType *tupleTy) {
1152+
Type result;
1153+
for (auto &param : tupleTy->getElements()) {
1154+
bool mustClaimArg = !param.isVararg() &&
1155+
param.getDefaultArgKind() == DefaultArgumentKind::None;
1156+
bool canClaimArg = !param.hasName();
1157+
if (!result && canClaimArg) {
1158+
result = param.isVararg() ? param.getVarargBaseTy() : param.getType();
1159+
} else if (mustClaimArg) {
1160+
return Type();
1161+
}
1162+
}
1163+
return result;
11591164
}
11601165

11611166
ConstraintSystem::SolutionKind
@@ -1332,30 +1337,19 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
13321337
case TypeMatchKind::ArgumentTupleConversion:
13331338
if (typeVar1 &&
13341339
!typeVar1->getImpl().literalConformanceProto &&
1335-
kind == TypeMatchKind::ArgumentTupleConversion &&
13361340
(flags & TMF_GenerateConstraints) &&
13371341
dyn_cast<ParenType>(type1.getPointer())) {
13381342

1339-
auto tupleTy = type2->getAs<TupleType>();
1340-
1341-
if (tupleTy &&
1342-
!tupleTy->getElements().empty() &&
1343-
(tupleTy->hasAnyDefaultValues() ||
1344-
tupleTy->getElement(0).isVararg()) &&
1345-
!tupleTy->getElement(0).hasName() &&
1346-
tupleTypeRequiredArgCount(tupleTy) <= 1) {
1347-
1348-
// Look through vararg types, if necessary.
1349-
auto tupleElt = tupleTy->getElement(0);
1350-
auto tupleEltTy = tupleElt.isVararg() ?
1351-
tupleElt.getVarargBaseTy() : tupleElt.getType();
1352-
1353-
addConstraint(getConstraintKind(kind),
1354-
typeVar1,
1355-
tupleEltTy,
1356-
getConstraintLocator(locator));
1357-
return SolutionKind::Solved;
1343+
if (auto tupleTy = type2->getAs<TupleType>()) {
1344+
if (auto tupleEltTy = getTupleElementTypeForSingleArgument(tupleTy)) {
1345+
addConstraint(getConstraintKind(kind),
1346+
typeVar1,
1347+
tupleEltTy,
1348+
getConstraintLocator(locator));
1349+
return SolutionKind::Solved;
1350+
}
13581351
}
1352+
13591353
}
13601354
SWIFT_FALLTHROUGH;
13611355

test/expr/expressions.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,3 +796,9 @@ protocol P { var y: String? { get } }
796796
func r23185177(x: P?) -> [String] {
797797
return x?.y // expected-error{{cannot convert return expression of type 'String?' to return type '[String]'}}
798798
}
799+
800+
// <rdar://problem/22913570> Miscompile: wrong argument parsing when calling a function in swift2.0
801+
func r22913570() {
802+
func f(from: Int = 0, to: Int) {}
803+
f(1 + 1) // expected-error{{missing argument for parameter 'to' in call}}
804+
}

0 commit comments

Comments
 (0)