Skip to content

Commit 4126215

Browse files
authored
Merge pull request swiftlang#26831 from theblixguy/fix/SR-10492
[AST] Paren'd reference to an IUO function crashes the compiler in SILGen
2 parents 9222dfd + fc9fef2 commit 4126215

File tree

4 files changed

+68
-1
lines changed

4 files changed

+68
-1
lines changed

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2272,6 +2272,17 @@ namespace {
22722272
auto *choiceLocator = cs.getConstraintLocator(locator.withPathElement(
22732273
ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice));
22742274

2275+
// We won't have a disjunction choice if we have an IUO function call
2276+
// wrapped in parens (i.e. '(s.foo)()'), because we only create a
2277+
// single constraint to bind to an optional type. So, we can just return
2278+
// false here as there's no need to force unwrap.
2279+
if (!solution.DisjunctionChoices.count(choiceLocator)) {
2280+
auto type = choice.getDecl()->getInterfaceType();
2281+
assert((type && type->is<AnyFunctionType>()) &&
2282+
"expected a function type");
2283+
return false;
2284+
}
2285+
22752286
return solution.getDisjunctionChoice(choiceLocator);
22762287
}
22772288

lib/Sema/ConstraintSystem.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2190,9 +2190,34 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
21902190
openedFullType,
21912191
refType};
21922192

2193+
// If we have something like '(s.foo)()', where 's.foo()' returns an IUO,
2194+
// then we need to only create a single constraint that binds the
2195+
// type to an optional.
2196+
auto isIUOCallWrappedInParens = [&]() {
2197+
auto decl = choice.getDecl();
2198+
auto type = decl ? decl->getInterfaceType() : nullptr;
2199+
if (!type || !type->is<AnyFunctionType>())
2200+
return false;
2201+
2202+
auto expr = locator->getAnchor();
2203+
if (!expr)
2204+
return false;
2205+
2206+
if (isa<CallExpr>(expr)) {
2207+
return false;
2208+
}
2209+
2210+
auto parentExpr = getParentExpr(expr);
2211+
if (parentExpr && isa<ParenExpr>(parentExpr))
2212+
return true;
2213+
2214+
return false;
2215+
};
2216+
21932217
// In some cases we already created the appropriate bind constraints.
21942218
if (!bindConstraintCreated) {
2195-
if (choice.isImplicitlyUnwrappedValueOrReturnValue()) {
2219+
if (choice.isImplicitlyUnwrappedValueOrReturnValue() &&
2220+
!isIUOCallWrappedInParens()) {
21962221
// Build the disjunction to attempt binding both T? and T (or
21972222
// function returning T? and function returning T).
21982223
buildDisjunctionForImplicitlyUnwrappedOptional(boundType, refType,

test/Constraints/iuo.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,26 @@ var y: Int = 2
223223

224224
let r = sr6988(x: x, y: y)
225225
let _: Int = r
226+
227+
// SR-10492
228+
229+
struct SR_10492_S {
230+
func foo() -> Int! { return 0 }
231+
}
232+
233+
let sr_10492_s = SR_10492_S()
234+
let sr_10492_int1: Int = (sr_10492_s.foo)() // expected-error {{value of optional type 'Int?' must be unwrapped to a value of type 'Int'}}
235+
// expected-note@-1 {{coalesce}}{{44-44= ?? <#default value#>}}
236+
// expected-note@-2 {{force-unwrap}}{{44-44=!}}
237+
let sr_10492_int2: Int? = (sr_10492_s.foo)() // Okay
238+
239+
240+
class SR_10492_C1 {
241+
init!() {}
242+
}
243+
244+
class SR_10492_C2 {
245+
init(_ foo: SR_10492_C1) {}
246+
}
247+
248+
let bar = SR_10492_C2(SR_10492_C1()) // Okay
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: not %target-swift-frontend -emit-silgen %s
2+
3+
struct S {
4+
func foo() -> Int! { return 0 }
5+
}
6+
7+
let s = S()
8+
let x: Int = (s.foo)()

0 commit comments

Comments
 (0)