Skip to content

Commit 5c6c7ff

Browse files
committed
Disallow conversions from IUOs to extistentials.
Commit 170dc8a removed a penalty that we used to have for conversions to Any. In some unusual circumstances not having that penalty can result in new amiguities where we should have nothing ambiguous about an expression according to our type rules. This change attempts to ensure that we make that less likely or impossible by not allowing direct conversions from IUOs to Any (instead forcing these to first be force-unchecked, leading to more expensive solutions). We never should have allowed these conversions anyway, independent of removing the penalty for conversions to Any. This change is intentionally very narrow to avoid further potential source breakage. Fixes rdar://problem/29907555.
1 parent 99080b4 commit 5c6c7ff

File tree

2 files changed

+22
-3
lines changed

2 files changed

+22
-3
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,9 +2009,22 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
20092009
// Instance type check for the above. We are going to check conformance once
20102010
// we hit commit_to_conversions below, but we have to add a token restriction
20112011
// to ensure we wrap the metatype value in a metatype erasure.
2012-
if (concrete && type2->isExistentialType() &&
2013-
kind >= ConstraintKind::Subtype) {
2014-
conversionsOrFixes.push_back(ConversionRestrictionKind::Existential);
2012+
2013+
// Disallow direct IUO-to-Any conversions. This will allow us to
2014+
// force-unwrap the IUO before attempting to convert, which makes it
2015+
// possible to disambiguate certain cases where we would otherwise
2016+
// consider an IUO or plain optional to be equally desirable choices
2017+
// where we really want the IUO to decay to a plain optional.
2018+
{
2019+
bool disallowExistentialConversion = false;
2020+
if (type2->isAny() &&
2021+
type1->getRValueType()->getImplicitlyUnwrappedOptionalObjectType())
2022+
disallowExistentialConversion = true;
2023+
2024+
if (concrete && !disallowExistentialConversion &&
2025+
type2->isExistentialType() && kind >= ConstraintKind::Subtype) {
2026+
conversionsOrFixes.push_back(ConversionRestrictionKind::Existential);
2027+
}
20152028
}
20162029

20172030
// A value of type T! can be converted to type U if T is convertible

test/Constraints/diag_ambiguities.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,9 @@ func rdar29691909_callee(_ o: AnyObject) -> Any { return o } // expected-note {{
3535
func rdar29691909(o: AnyObject) -> Any? {
3636
return rdar29691909_callee(o) // expected-error{{ambiguous use of 'rdar29691909_callee'}}
3737
}
38+
39+
// Ensure that we decay Any! to Any? rather than allowing Any!-to-Any
40+
// conversion directly and ending up with an ambiguity here.
41+
func rdar29907555(_ value: Any!) -> String {
42+
return "\(value)" // no error
43+
}

0 commit comments

Comments
 (0)