Skip to content

Commit daf9e2d

Browse files
committed
[Concurrency] Print @objc async declarations as Objective-C declarations.
@objc async declarations are mapping into completion-handler-based methods in Objective-C, so ensure that the result type, parameters, and attributes reflect that.
1 parent 0f18948 commit daf9e2d

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

lib/PrintAsObjC/DeclAndTypePrinter.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/Comment.h"
1919
#include "swift/AST/Decl.h"
2020
#include "swift/AST/ExistentialLayout.h"
21+
#include "swift/AST/ForeignAsyncConvention.h"
2122
#include "swift/AST/ForeignErrorConvention.h"
2223
#include "swift/AST/GenericEnvironment.h"
2324
#include "swift/AST/PrettyStackTrace.h"
@@ -464,6 +465,7 @@ class DeclAndTypePrinter::Implementation
464465

465466
Type getForeignResultType(AbstractFunctionDecl *AFD,
466467
FunctionType *methodTy,
468+
Optional<ForeignAsyncConvention> asyncConvention,
467469
Optional<ForeignErrorConvention> errorConvention) {
468470
// A foreign error convention can affect the result type as seen in
469471
// Objective-C.
@@ -484,6 +486,11 @@ class DeclAndTypePrinter::Implementation
484486
}
485487
}
486488

489+
// Asynchronous methods return their results via completion handler.
490+
if (asyncConvention) {
491+
return getASTContext().TheEmptyTupleType;
492+
}
493+
487494
auto result = methodTy->getResult();
488495
if (result->isUninhabited())
489496
return getASTContext().TheEmptyTupleType;
@@ -513,16 +520,20 @@ class DeclAndTypePrinter::Implementation
513520
}
514521
}
515522

523+
Optional<ForeignAsyncConvention> asyncConvention
524+
= AFD->getForeignAsyncConvention();
516525
Optional<ForeignErrorConvention> errorConvention
517526
= AFD->getForeignErrorConvention();
518527
Type rawMethodTy = AFD->getMethodInterfaceType();
519528
auto methodTy = rawMethodTy->castTo<FunctionType>();
520-
auto resultTy = getForeignResultType(AFD, methodTy, errorConvention);
529+
auto resultTy = getForeignResultType(
530+
AFD, methodTy, asyncConvention, errorConvention);
521531

522532
// Constructors and methods returning DynamicSelf return
523533
// instancetype.
524534
if (isa<ConstructorDecl>(AFD) ||
525-
(isa<FuncDecl>(AFD) && cast<FuncDecl>(AFD)->hasDynamicSelfResult())) {
535+
(isa<FuncDecl>(AFD) && cast<FuncDecl>(AFD)->hasDynamicSelfResult() &&
536+
!AFD->hasAsync())) {
526537
if (errorConvention && errorConvention->stripsResultOptionality()) {
527538
printNullability(OTK_Optional, NullabilityPrintKind::ContextSensitive);
528539
} else if (auto ctor = dyn_cast<ConstructorDecl>(AFD)) {
@@ -578,6 +589,16 @@ class DeclAndTypePrinter::Implementation
578589
StringRef piece = selectorPieces[i].empty() ? StringRef("")
579590
: selectorPieces[i].str();
580591

592+
// If we have an async convention and this is the completion handler
593+
// parameter, print it.
594+
if (asyncConvention &&
595+
i == asyncConvention->completionHandlerParamIndex()) {
596+
os << piece << ":(";
597+
print(asyncConvention->completionHandlerType(), None);
598+
os << ")completionHandler";
599+
continue;
600+
}
601+
581602
// If we have an error convention and this is the error
582603
// parameter, print it.
583604
if (errorConvention && i == errorConvention->getErrorParameterIndex()) {
@@ -660,7 +681,9 @@ class DeclAndTypePrinter::Implementation
660681
if (looksLikeInitMethod(AFD->getObjCSelector())) {
661682
os << " SWIFT_METHOD_FAMILY(none)";
662683
}
663-
if (methodTy->getResult()->isUninhabited()) {
684+
if (asyncConvention) {
685+
// Async methods don't have result types to annotate.
686+
} else if (methodTy->getResult()->isUninhabited()) {
664687
os << " SWIFT_NORETURN";
665688
} else if (!methodTy->getResult()->isVoid() &&
666689
!AFD->getAttrs().hasAttribute<DiscardableResultAttr>()) {
@@ -697,12 +720,15 @@ class DeclAndTypePrinter::Implementation
697720

698721
void printAbstractFunctionAsFunction(FuncDecl *FD) {
699722
printDocumentationComment(FD);
723+
Optional<ForeignAsyncConvention> asyncConvention
724+
= FD->getForeignAsyncConvention();
700725
Optional<ForeignErrorConvention> errorConvention
701726
= FD->getForeignErrorConvention();
702727
assert(!FD->getGenericSignature() &&
703728
"top-level generic functions not supported here");
704729
auto funcTy = FD->getInterfaceType()->castTo<FunctionType>();
705-
auto resultTy = getForeignResultType(FD, funcTy, errorConvention);
730+
auto resultTy = getForeignResultType(
731+
FD, funcTy, asyncConvention, errorConvention);
706732

707733
// The result type may be a partial function type we need to close
708734
// up later.

test/PrintAsObjC/async.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// REQUIRES: objc_interop
2+
3+
// RUN: %empty-directory(%t)
4+
5+
// FIXME: BEGIN -enable-source-import hackaround
6+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/ObjectiveC.swift -disable-objc-attr-requires-foundation-module
7+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/CoreGraphics.swift
8+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/Foundation.swift
9+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -emit-module -o %t %S/../Inputs/clang-importer-sdk/swift-modules/AppKit.swift
10+
// FIXME: END -enable-source-import hackaround
11+
12+
13+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -parse-as-library %s -typecheck -I %S/Inputs/custom-modules -emit-objc-header-path %t/async.h -import-objc-header %S/../Inputs/empty.h -enable-experimental-concurrency -typecheck
14+
// RUN: %FileCheck %s < %t/async.h
15+
// RUN: %check-in-clang -I %S/Inputs/custom-modules/ %t/async.h
16+
17+
import Foundation
18+
19+
// CHECK-LABEL: @interface BarClass : NSObject
20+
@objc @objcMembers class BarClass: NSObject {
21+
// CHECK: (void)doSomethingBigWithCompletionHandler:(void (^)(NSInteger))completionHandler;
22+
func doSomethingBig() async -> Int { 0 }
23+
24+
// CHECK: - (void)longRunningWithString:(NSString * _Nonnull)string completionHandler:(void (^)(BarClass * _Nullable, NSError * _Nullable))completionHandler;
25+
func longRunning(string: String) async throws -> BarClass { return self }
26+
27+
// CHECK: - (void)magicTupleReturnWithCompletionHandler:(void (^)(BarClass * _Nonnull, NSInteger))completionHandler;
28+
func magicTupleReturn() async -> (BarClass, Int) { return (self, 0) }
29+
}
30+
// CHECK: @end

0 commit comments

Comments
 (0)