Merge pull request #7233 from rudkx/fix-rdar30311052-3.1
[Sema] Penalize conversions to Any.
diff --git a/lib/Sema/CSRanking.cpp b/lib/Sema/CSRanking.cpp
index d981565..9e14831 100644
--- a/lib/Sema/CSRanking.cpp
+++ b/lib/Sema/CSRanking.cpp
@@ -74,6 +74,9 @@
case SK_ScalarPointerConversion:
log << "scalar-to-pointer conversion";
break;
+ case SK_EmptyExistentialConversion:
+ log << "empty-existential conversion";
+ break;
}
log << ")\n";
}
diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp
index 48dba0c..a5a38c0 100644
--- a/lib/Sema/CSSimplify.cpp
+++ b/lib/Sema/CSSimplify.cpp
@@ -1558,8 +1558,10 @@
break;
case TypeKind::Tuple: {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
// Try the tuple-to-tuple conversion.
- conversionsOrFixes.push_back(ConversionRestrictionKind::TupleToTuple);
+ if (!type1->is<LValueType>())
+ conversionsOrFixes.push_back(ConversionRestrictionKind::TupleToTuple);
break;
}
@@ -1568,7 +1570,9 @@
case TypeKind::Class: {
auto nominal1 = cast<NominalType>(desugar1);
auto nominal2 = cast<NominalType>(desugar2);
- if (nominal1->getDecl() == nominal2->getDecl()) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
+ if (!type1->is<LValueType>() &&
+ nominal1->getDecl() == nominal2->getDecl()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}
@@ -1579,7 +1583,9 @@
auto class2 = cast<ClassDecl>(nominal2->getDecl());
// CF -> Objective-C via toll-free bridging.
- if (class1->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
+ if (!type1->is<LValueType>() &&
+ class1->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
class2->getForeignClassKind() != ClassDecl::ForeignKind::CFType &&
class1->getAttrs().hasAttribute<ObjCBridgedAttr>()) {
conversionsOrFixes.push_back(
@@ -1587,7 +1593,9 @@
}
// Objective-C -> CF via toll-free bridging.
- if (class2->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
+ if (!type1->is<LValueType>() &&
+ class2->getForeignClassKind() == ClassDecl::ForeignKind::CFType &&
class1->getForeignClassKind() != ClassDecl::ForeignKind::CFType &&
class2->getAttrs().hasAttribute<ObjCBridgedAttr>()) {
conversionsOrFixes.push_back(
@@ -1678,7 +1686,8 @@
auto bound1 = cast<BoundGenericType>(desugar1);
auto bound2 = cast<BoundGenericType>(desugar2);
- if (bound1->getDecl() == bound2->getDecl()) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
+ if (!type1->is<LValueType>() && bound1->getDecl() == bound2->getDecl()) {
conversionsOrFixes.push_back(ConversionRestrictionKind::DeepEquality);
}
break;
@@ -1713,12 +1722,13 @@
// there is at most one non-defaulted element.
// For non-argument tuples, we can do the same conversion but not
// to a tuple with varargs.
- if ((tuple2->getNumElements() == 1 &&
- !tuple2->getElement(0).isVararg()) ||
- (kind >= ConstraintKind::Conversion &&
- tuple2->getElementForScalarInit() >= 0 &&
- (isArgumentTupleConversion ||
- !tuple2->getVarArgsBaseType()))) {
+ if (!type1->is<LValueType>() &&
+ ((tuple2->getNumElements() == 1 &&
+ !tuple2->getElement(0).isVararg()) ||
+ (kind >= ConstraintKind::Conversion &&
+ tuple2->getElementForScalarInit() >= 0 &&
+ (isArgumentTupleConversion ||
+ !tuple2->getVarArgsBaseType())))) {
conversionsOrFixes.push_back(
ConversionRestrictionKind::ScalarToTuple);
@@ -1732,6 +1742,7 @@
type2->getClassOrBoundGenericClass() &&
type1->getClassOrBoundGenericClass()
!= type2->getClassOrBoundGenericClass()) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
conversionsOrFixes.push_back(ConversionRestrictionKind::Superclass);
}
@@ -1740,7 +1751,9 @@
// Don't allow this in operator contexts or we'll end up allowing
// 'T() == U()' for unrelated T and U that just happen to be Hashable.
// We can remove this special case when we implement operator hiding.
- if (kind != ConstraintKind::OperatorArgumentConversion) {
+ if (!type1->is<LValueType>() &&
+ kind != ConstraintKind::OperatorArgumentConversion) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
conversionsOrFixes.push_back(
ConversionRestrictionKind::HashableToAnyHashable);
}
@@ -1800,16 +1813,20 @@
}
// Special implicit nominal conversions.
- if (kind >= ConstraintKind::Conversion) {
+ if (!type1->is<LValueType>() &&
+ kind >= ConstraintKind::Conversion) {
// Array -> Array.
if (isArrayType(desugar1) && isArrayType(desugar2)) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
conversionsOrFixes.push_back(ConversionRestrictionKind::ArrayUpcast);
// Dictionary -> Dictionary.
} else if (isDictionaryType(desugar1) && isDictionaryType(desugar2)) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
conversionsOrFixes.push_back(
ConversionRestrictionKind::DictionaryUpcast);
// Set -> Set.
} else if (isSetType(desugar1) && isSetType(desugar2)) {
+ assert(!type2->is<LValueType>() && "Unexpected lvalue type!");
conversionsOrFixes.push_back(
ConversionRestrictionKind::SetUpcast);
}
@@ -1981,7 +1998,13 @@
// we hit commit_to_conversions below, but we have to add a token restriction
// to ensure we wrap the metatype value in a metatype erasure.
if (concrete && type2->isExistentialType() &&
+ !type1->is<LValueType>() &&
kind >= ConstraintKind::Subtype) {
+
+ // Penalize conversions to Any.
+ if (kind >= ConstraintKind::Conversion && type2->isAny())
+ increaseScore(ScoreKind::SK_EmptyExistentialConversion);
+
conversionsOrFixes.push_back(ConversionRestrictionKind::Existential);
}
@@ -1992,7 +2015,8 @@
{
BoundGenericType *boundGenericType2;
- if (concrete && kind >= ConstraintKind::Subtype &&
+ if (concrete && !type1->is<LValueType>() &&
+ kind >= ConstraintKind::Subtype &&
(boundGenericType2 = type2->getAs<BoundGenericType>())) {
auto decl2 = boundGenericType2->getDecl();
if (auto optionalKind2 = decl2->classifyAsOptionalType()) {
@@ -2025,6 +2049,7 @@
ConversionRestrictionKind::ValueToOptional);
}
}
+
}
// A value of type T! can be (unsafely) forced to U if T
diff --git a/lib/Sema/ConstraintSystem.h b/lib/Sema/ConstraintSystem.h
index 4af6d62..978d0f7 100644
--- a/lib/Sema/ConstraintSystem.h
+++ b/lib/Sema/ConstraintSystem.h
@@ -406,8 +406,10 @@
SK_ScalarPointerConversion,
/// A conversion from an array to a pointer of matching element type.
SK_ArrayPointerConversion,
+ /// A conversion to an empty existential type ('Any' or '{}').
+ SK_EmptyExistentialConversion,
- SK_LastScoreKind = SK_ArrayPointerConversion,
+ SK_LastScoreKind = SK_EmptyExistentialConversion,
};
/// The number of score kinds.
diff --git a/test/Constraints/array_literal.swift b/test/Constraints/array_literal.swift
index 902f106..fe64443 100644
--- a/test/Constraints/array_literal.swift
+++ b/test/Constraints/array_literal.swift
@@ -227,3 +227,10 @@
}
]
)
+
+// Infer [[Int]] for SR3786aa.
+// FIXME: As noted in SR-3786, this was the behavior in Swift 3, but
+// it seems like the wrong choice and is less by design than by
+// accident.
+let SR3786a: [Int] = [1, 2, 3]
+let SR3786aa = [SR3786a.reversed(), SR3786a]
diff --git a/test/Constraints/diag_ambiguities.swift b/test/Constraints/diag_ambiguities.swift
index 7e7a9ec..04dbf66 100644
--- a/test/Constraints/diag_ambiguities.swift
+++ b/test/Constraints/diag_ambiguities.swift
@@ -36,13 +36,9 @@
return rdar29691909_callee(o) // expected-error{{ambiguous use of 'rdar29691909_callee'}}
}
-// FIXME: The fix for this broke other things. We want to get this
-// test case running again, though.
-// Ensure that we decay Any! to Any? rather than allowing Any!-to-Any
-// conversion directly and ending up with an ambiguity here.
-//func rdar29907555(_ value: Any!) -> String {
-// return "\(value)" // no error
-//}
+func rdar29907555(_ value: Any!) -> String {
+ return "\(value)" // no error
+}
struct SR3715 {
var overloaded: Int!
diff --git a/test/Constraints/overload.swift b/test/Constraints/overload.swift
index 9cb3a20..264bac6 100644
--- a/test/Constraints/overload.swift
+++ b/test/Constraints/overload.swift
@@ -186,3 +186,12 @@
overloadedMethod()
// expected-error@-1 {{missing argument for parameter 'n' in call}}
+
+// Ensure we select the overload of '??' returning T? rather than T.
+func SR3817(_ d: [String : Any], _ s: String, _ t: String) -> Any {
+ if let r = d[s] ?? d[t] {
+ return r
+ } else {
+ return 0
+ }
+}