Skip to content

Commit 9e90512

Browse files
committed
Perform function conversions when converting between autoclosures.
This is correct because it's the apparent rule used by CSSimplify: value-to-autoclosure conversion is considered if and only if the input type is not an autoclosure function type. The real solution to this problem is that @autoclosure should be tracked as a bit on the parameter type instead of as a bit on function types. Slava has a PR leading towards that (#10094), but it causes a source-compatibility problem when forwarding autoclosures. You really shouldn't be able to forward autoclosures, but that's an issue for the core team to resolve, and in the meantime there's this bug. Fixes rdar://41219750.
1 parent 7321b10 commit 9e90512

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

lib/Sema/CSApply.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6865,10 +6865,18 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
68656865
isInDefaultArgumentContext = (initalizerCtx->getInitializerKind() ==
68666866
InitializerKind::DefaultArgument);
68676867
auto toEI = toFunc->getExtInfo();
6868+
6869+
auto fromFunc = fromType->getAs<FunctionType>();
6870+
68686871
// Coercion to an autoclosure type produces an implicit closure.
6872+
// The constraint solver only performs this conversion when the source
6873+
// type is not an autoclosure function type. That's a weird rule in
6874+
// some rules, but it's easy to follow here. Really we just shouldn't
6875+
// represent autoclosures as a bit on function types.
68696876
// FIXME: The type checker is more lenient, and allows @autoclosures to
68706877
// be subtypes of non-@autoclosures, which is bogus.
6871-
if (toFunc->isAutoClosure()) {
6878+
if (toFunc->isAutoClosure() &&
6879+
(!fromFunc || !fromFunc->isAutoClosure())) {
68726880
// The function type without @noescape if we are in the default argument
68736881
// context.
68746882
auto newToFuncType = toFunc;
@@ -6909,7 +6917,7 @@ Expr *ExprRewriter::coerceToType(Expr *expr, Type toType,
69096917

69106918
// Coercion from one function type to another, this produces a
69116919
// FunctionConversionExpr in its full generality.
6912-
if (auto fromFunc = fromType->getAs<FunctionType>()) {
6920+
if (fromFunc) {
69136921
// If we have a ClosureExpr, then we can safely propagate the 'no escape'
69146922
// bit to the closure without invalidating prior analysis.
69156923
auto fromEI = fromFunc->getExtInfo();

test/attr/attr_autoclosure.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func migrateAC(@autoclosure _: () -> ()) { }
146146
func migrateACE(@autoclosure(escaping) _: () -> ()) { }
147147

148148
func takesAutoclosure(_ fn: @autoclosure () -> Int) {}
149+
func takesThrowingAutoclosure(_: @autoclosure () throws -> Int) {}
149150

150151
func callAutoclosureWithNoEscape(_ fn: () -> Int) {
151152
takesAutoclosure(1+1) // ok
@@ -161,3 +162,16 @@ func callAutoclosureWithNoEscape_3(_ fn: @autoclosure () -> Int) {
161162
func variadicAutoclosure(_ fn: @autoclosure () -> ()...) {
162163
for _ in fn {}
163164
}
165+
166+
// rdar://41219750
167+
// These are all arguably invalid; the autoclosure should have to be called.
168+
// But as long as we allow them, we shouldn't crash.
169+
func passNonThrowingToNonThrowingAC(_ fn: @autoclosure () -> Int) {
170+
takesAutoclosure(fn)
171+
}
172+
func passNonThrowingToThrowingAC(_ fn: @autoclosure () -> Int) {
173+
takesThrowingAutoclosure(fn)
174+
}
175+
func passThrowingToThrowingAC(_ fn: @autoclosure () throws -> Int) {
176+
takesThrowingAutoclosure(fn)
177+
}

0 commit comments

Comments
 (0)