mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Sema: Implicit conversion for single-expression closures of Never type
This fixes a usability regression with the removal of @noreturn
in Swift 3. Previously, it was legal to write this:
let callback: () -> Int = { fatalError() }
Now that the special @noreturn attribute has been replaced with
a Never type, the above fails to typecheck, because the expression
now has type 'Never', and we expect a value of type 'Int'.
Getting around this behavior requires ugly workarounds to force the
parser to treat the body as a statement rather than an expression;
for example,
let callback: () -> Int = { _ = (); fatalError() }
This patch generalized single-expression closures to allow
the 'Never to T' conversion. Note that this is rather narrow
in scope -- it only applies to closure *literals*, single-expression
ones at that, not arbitrary function *values*.
In fact, it is not really a conversion at all, but more of a
desugaring rule for single-expression closures. They can now be
summarized as follows:
- If the closure literal has contextual return type T and
the expression has Never type, the closure desugars as
{ _ = <expr> }, with no ReturnStmt.
- If the closure literal has contextual return type T for some
non-void type T, the closure desugars as { return <expr> };
the expression type must be convertible to T.
- If the closure literal has contextual return type Void, and
the expression has some non-Void type T, the closure
desugars as { _ = <expr>; return () }.
Fixes <rdar://problem/28269358> and <https://bugs.swift.org/browse/SR-2661>.
This commit is contained in:
@@ -1956,10 +1956,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, TypeMatchKind kind,
|
||||
}
|
||||
}
|
||||
|
||||
// If the types disagree, but we're comparing a non-void, single-expression
|
||||
// closure result type to a void function result type, allow the conversion.
|
||||
// Allow '() -> T' to '() -> ()' and '() -> Never' to '() -> T' for closure
|
||||
// literals.
|
||||
{
|
||||
if (concrete && kind >= TypeMatchKind::Subtype && type2->isVoid()) {
|
||||
if (concrete && kind >= TypeMatchKind::Subtype &&
|
||||
(type1->isUninhabited() || type2->isVoid())) {
|
||||
SmallVector<LocatorPathElt, 2> parts;
|
||||
locator.getLocatorParts(parts);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user