mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user