Disallow value-to-optional conversions between argument and parameter types when resolving overloads for operators applied to nil literal operands.

This is a targeted fix to address rdar://problem/16848110 ("Disallow non-optionals to be compared to nil") and its associated dupes.

Swift SVN r20716
This commit is contained in:
Joe Pamer
2014-07-29 23:24:36 +00:00
parent e2f243b349
commit 1fec0afbd0
5 changed files with 86 additions and 6 deletions

View File

@@ -655,6 +655,49 @@ matchCallArguments(ConstraintSystem &cs, TypeMatchKind kind,
auto haveOneNonUserConversion =
(subKind != TypeMatchKind::OperatorArgumentConversion);
auto haveNilArgument = false;
auto nilLiteralProto = cs.TC.getProtocol(SourceLoc(),
KnownProtocolKind::
NilLiteralConvertible);
auto isNilLiteral = [&](Type t) -> bool {
if (auto tyvar = t->getAs<TypeVariableType>()) {
return tyvar->getImpl().literalConformanceProto == nilLiteralProto;
}
return false;
};
// If we're applying an operator function to a nil literal operand, we
// disallow value-to-optional conversions from taking place so as not to
// select an overly permissive overload.
auto allowOptionalConversion = [&](Type t) -> bool {
if (t->isLValueType())
t = t->getLValueOrInOutObjectType();
if (!t->getAnyOptionalObjectType().isNull())
return true;
if (isNilLiteral(t))
return true;
if (auto nt = t->getNominalOrBoundGenericNominal()) {
return nt->getName() == cs.TC.Context.Id_OptionalNilComparisonType;
}
return false;
};
// Pre-scan operator arguments for nil literals.
if (subKind == TypeMatchKind::OperatorArgumentConversion) {
for (auto arg : argTuple) {
if (isNilLiteral(arg.getType())) {
haveNilArgument = true;
break;
}
}
}
for (unsigned paramIdx = 0, numParams = parameterBindings.size();
paramIdx != numParams; ++paramIdx){
// Skip unfulfilled parameters. There's nothing to do for them.
@@ -673,6 +716,9 @@ matchCallArguments(ConstraintSystem &cs, TypeMatchKind kind,
paramIdx));
auto argTy = argTuple[argIdx].getType();
if (haveNilArgument && !allowOptionalConversion(argTy)) {
subflags |= ConstraintSystem::TMF_ApplyingOperatorWithNil;
}
if (!haveOneNonUserConversion) {
subflags |= ConstraintSystem::TMF_ApplyingOperatorParameter;
@@ -1893,8 +1939,12 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
}
}
conversionsOrFixes.push_back(
ConversionRestrictionKind::ValueToOptional);
// Do not attempt a value-to-optional conversion when resolving the
// applicable overloads for an operator application with nil operands.
if (!(subFlags & TMF_ApplyingOperatorWithNil)) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::ValueToOptional);
}
}
}
}