[Type checker] Use call argument matching even with type variables on the left-hand side.

Rather than using a specialized matching rule in the type checker that
depends on having default arguments in types, use call argument
matching consistently.

Note #1: This (correctly) breaks some existing code that depends on
inferring a parameter type of () for a single-argument parameter from
a no-argument function type().

Note #2: This pessimizes a code completion test, where the code
completion engine seems to depend on some quirks of argument
matching. The "type relationship" matching needs non-trivial work.
This commit is contained in:
Doug Gregor
2016-06-17 00:10:04 -07:00
parent 8fe85c3368
commit 423c1f09da
6 changed files with 26 additions and 63 deletions

View File

@@ -1246,24 +1246,6 @@ static bool allowsBridgingFromObjC(TypeChecker &tc, DeclContext *dc,
return true;
}
/// Given that 'tupleTy' is the argument type of a function that's being
/// invoked with a single unlabeled argument, return the type of the parameter
/// that matches that argument, or the null type if such a match is impossible.
static Type getTupleElementTypeForSingleArgument(TupleType *tupleTy) {
Type result;
for (auto &param : tupleTy->getElements()) {
bool mustClaimArg = !param.isVararg() &&
param.getDefaultArgKind() == DefaultArgumentKind::None;
bool canClaimArg = !param.hasName();
if (!result && canClaimArg) {
result = param.isVararg() ? param.getVarargBaseTy() : param.getType();
} else if (mustClaimArg) {
return Type();
}
}
return result;
}
ConstraintSystem::SolutionKind
ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
unsigned flags,
@@ -1415,34 +1397,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
return SolutionKind::Unsolved;
}
// We need to be careful about mapping 'raw' argument type variables to
// parameter tuples containing default args, or varargs in the first
// position. If we naively bind the type variable to the parameter tuple,
// we'll later end up looking to whatever expression created the type
// variable to find the declarations for default arguments. This can
// obviously be problematic if the expression in question is not an
// application. (For example, We don't want to introspect an 'if' expression
// to see if it has default arguments.) Instead, we should bind the type
// variable to the first element type of the tuple.
case TypeMatchKind::ArgumentTupleConversion:
if (typeVar1 &&
!typeVar1->getImpl().literalConformanceProto &&
(flags & TMF_GenerateConstraints) &&
isa<ParenType>(type1.getPointer())) {
if (auto tupleTy = type2->getAs<TupleType>()) {
if (auto tupleEltTy = getTupleElementTypeForSingleArgument(tupleTy)) {
addConstraint(getConstraintKind(kind),
typeVar1,
tupleEltTy,
getConstraintLocator(locator));
return SolutionKind::Solved;
}
}
}
SWIFT_FALLTHROUGH;
case TypeMatchKind::Conversion:
if (typeVar1 && typeVar2) {
auto rep1 = getRepresentative(typeVar1);
@@ -1489,7 +1444,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
// different from normal conversions.
if (kind == TypeMatchKind::ArgumentTupleConversion ||
kind == TypeMatchKind::OperatorArgumentTupleConversion) {
if (concrete) {
if (!typeVar2) {
return ::matchCallArguments(*this, kind, type1, type2, locator);
}