[Concurrency] Implicitly strip optionals for return type of translated "async throws".

Review over a large number of APIs has found that most of the time, the
result type of an Objective-C completion handler method that becomes
"async throws" should be optional. Change the default behavior to
match this, and replace _Nullable_on_error with _Nullable_result to
capture the case where the result should be optional.
This commit is contained in:
Doug Gregor
2020-10-29 23:59:35 -07:00
parent 540455ae7d
commit 4bcccecfda
5 changed files with 18 additions and 10 deletions

View File

@@ -2065,7 +2065,13 @@ static Type decomposeCompletionHandlerType(
paramIdx == *info.completionHandlerErrorParamIndex()) paramIdx == *info.completionHandlerErrorParamIndex())
continue; continue;
resultTypeElts.push_back(param.getPlainType()); // If there is an error parameter, remove nullability.
Type paramType = param.getPlainType();
// TODO: Clang should gain a nullability form that overrides this.
if (info.completionHandlerErrorParamIndex())
paramType = paramType->lookThroughAllOptionalTypes();
resultTypeElts.push_back(paramType);
} }
switch (resultTypeElts.size()) { switch (resultTypeElts.size()) {

View File

@@ -1946,8 +1946,10 @@ bool swift::fixDeclarationName(InFlightDiagnostic &diag, const ValueDecl *decl,
} }
// Fix the argument names that need fixing. // Fix the argument names that need fixing.
assert(name.getArgumentNames().size() if (name.getArgumentNames().size()
== targetName.getArgumentNames().size()); != targetName.getArgumentNames().size())
return false;
auto params = func->getParameters(); auto params = func->getParameters();
for (unsigned i = 0, n = name.getArgumentNames().size(); i != n; ++i) { for (unsigned i = 0, n = name.getArgumentNames().size(); i != n; ++i) {
auto origArg = name.getArgumentNames()[i]; auto origArg = name.getArgumentNames()[i];

View File

@@ -8,8 +8,8 @@ import ObjCConcurrency
func testSlowServer(slowServer: SlowServer) async throws { func testSlowServer(slowServer: SlowServer) async throws {
let _: Int = await slowServer.doSomethingSlow("mail") let _: Int = await slowServer.doSomethingSlow("mail")
let _: Bool = await slowServer.checkAvailability() let _: Bool = await slowServer.checkAvailability()
let _: String = try await slowServer.findAnswer() ?? "nope" let _: String = try await slowServer.findAnswer()
let _: String = await try slowServer.findAnswerFailingly() ?? "nope" let _: String = await try slowServer.findAnswerFailingly()
let _: Void = await slowServer.doSomethingFun("jump") let _: Void = await slowServer.doSomethingFun("jump")
let _: (Int) -> Void = slowServer.completionHandler let _: (Int) -> Void = slowServer.completionHandler

View File

@@ -10,13 +10,13 @@
// CHECK-DAG: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void) // CHECK-DAG: func doSomethingSlow(_ operation: String, completionHandler handler: @escaping (Int) -> Void)
// CHECK-DAG: func doSomethingSlow(_ operation: String) async -> Int // CHECK-DAG: func doSomethingSlow(_ operation: String) async -> Int
// CHECK-DAG: func doSomethingDangerous(_ operation: String, completionHandler handler: ((String?, Error?) -> Void)? = nil) // CHECK-DAG: func doSomethingDangerous(_ operation: String, completionHandler handler: ((String?, Error?) -> Void)? = nil)
// CHECK-DAG: func doSomethingDangerous(_ operation: String) async throws -> String? // CHECK-DAG: func doSomethingDangerous(_ operation: String) async throws -> String
// CHECK-DAG: func checkAvailability(completionHandler: @escaping (Bool) -> Void) // CHECK-DAG: func checkAvailability(completionHandler: @escaping (Bool) -> Void)
// CHECK-DAG: func checkAvailability() async -> Bool // CHECK-DAG: func checkAvailability() async -> Bool
// CHECK-DAG: func findAnswer(completionHandler handler: @escaping (String?, Error?) -> Void) // CHECK-DAG: func findAnswer(completionHandler handler: @escaping (String?, Error?) -> Void)
// CHECK-DAG: func findAnswer() async throws -> String? // CHECK-DAG: func findAnswer() async throws -> String
// CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws // CHECK-DAG: func findAnswerFailingly(completionHandler handler: @escaping (String?, Error?) -> Void) throws
// CHECK-DAG: func findAnswerFailingly() async throws -> String? // CHECK-DAG: func findAnswerFailingly() async throws -> String
// CHECK-DAG: func doSomethingFun(_ operation: String) async // CHECK-DAG: func doSomethingFun(_ operation: String) async
// CHECK: {{^[}]$}} // CHECK: {{^[}]$}}

View File

@@ -7,7 +7,7 @@ import ObjCConcurrency
// Conform via async method // Conform via async method
class C1: ConcurrentProtocol { class C1: ConcurrentProtocol {
func askUser(toSolvePuzzle puzzle: String) async throws -> String? { nil } func askUser(toSolvePuzzle puzzle: String) async throws -> String { "" }
func askUser(toJumpThroughHoop hoop: String) async -> String { "hello" } func askUser(toJumpThroughHoop hoop: String) async -> String { "hello" }
} }
@@ -26,7 +26,7 @@ class C2: ConcurrentProtocol {
// Conform via both; this is an error // Conform via both; this is an error
class C3: ConcurrentProtocol { class C3: ConcurrentProtocol {
// expected-note@+1{{method 'askUser(toSolvePuzzle:)' declared here}} // expected-note@+1{{method 'askUser(toSolvePuzzle:)' declared here}}
func askUser(toSolvePuzzle puzzle: String) async throws -> String? { nil } func askUser(toSolvePuzzle puzzle: String) async throws -> String { "" }
// expected-error@+1{{'askUser(toSolvePuzzle:completionHandler:)' with Objective-C selector 'askUserToSolvePuzzle:completionHandler:' conflicts with method 'askUser(toSolvePuzzle:)' with the same Objective-C selector}} // expected-error@+1{{'askUser(toSolvePuzzle:completionHandler:)' with Objective-C selector 'askUserToSolvePuzzle:completionHandler:' conflicts with method 'askUser(toSolvePuzzle:)' with the same Objective-C selector}}
func askUser(toSolvePuzzle puzzle: String, completionHandler: ((String?, Error?) -> Void)?) { func askUser(toSolvePuzzle puzzle: String, completionHandler: ((String?, Error?) -> Void)?) {