diff --git a/lib/PrintAsObjC/PrintAsObjC.cpp b/lib/PrintAsObjC/PrintAsObjC.cpp index f16eaed03baca..4f5dd5080c8a8 100644 --- a/lib/PrintAsObjC/PrintAsObjC.cpp +++ b/lib/PrintAsObjC/PrintAsObjC.cpp @@ -1243,9 +1243,16 @@ class ObjCPrinter : private DeclVisitor, void visitProtocolType(ProtocolType *PT, Optional optionalKind, bool isMetatype = false) { + auto proto = PT->getDecl(); + if (proto->isSpecificProtocol(KnownProtocolKind::Error)) { + if (isMetatype) os << "Class"; + else os << "NSError *"; + printNullability(optionalKind); + return; + } + os << (isMetatype ? "Class" : "id"); - auto proto = PT->getDecl(); assert(proto->isObjC()); if (auto knownKind = proto->getKnownProtocolKind()) { if (*knownKind == KnownProtocolKind::AnyObject) { @@ -1266,15 +1273,27 @@ class ObjCPrinter : private DeclVisitor, return visitProtocolType(singleProto, optionalKind, isMetatype); PCT = cast(canonicalComposition); - os << (isMetatype ? "Class" : "id"); - + // Dig out the protocols. If we see 'Error', record that we saw it. + bool hasError = false; SmallVector protos; - std::transform(PCT->getProtocols().begin(), PCT->getProtocols().end(), - std::back_inserter(protos), - [] (Type ty) -> ProtocolDecl * { - return ty->castTo()->getDecl(); - }); + for (auto protoTy : PCT->getProtocols()) { + auto proto = protoTy->castTo()->getDecl(); + if (proto->isSpecificProtocol(KnownProtocolKind::Error)) { + hasError = true; + continue; + } + + protos.push_back(proto); + } + + os << (isMetatype ? "Class" + : hasError ? "NSError" + : "id"); printProtocols(protos); + + if (hasError && !isMetatype) + os << " *"; + printNullability(optionalKind); } @@ -1630,7 +1649,8 @@ class ModuleWriter { void forwardDeclare(const ProtocolDecl *PD) { assert(PD->isObjC() || - *PD->getKnownProtocolKind() == KnownProtocolKind::AnyObject); + *PD->getKnownProtocolKind() == KnownProtocolKind::AnyObject || + *PD->getKnownProtocolKind() == KnownProtocolKind::Error); forwardDeclare(PD, [&]{ os << "@protocol " << getNameForObjC(PD) << ";\n"; }); diff --git a/test/PrintAsObjC/Inputs/error-delegate.h b/test/PrintAsObjC/Inputs/error-delegate.h new file mode 100644 index 0000000000000..b1589cbd19407 --- /dev/null +++ b/test/PrintAsObjC/Inputs/error-delegate.h @@ -0,0 +1,9 @@ +// This file is meant to be used with the mock SDK, not the real one. +#import + +@protocol ABCErrorProtocol + +- (void)didFail:(NSError * _Nonnull)error; +- (void)didFailOptional:(NSError * _Nullable)error; + +@end diff --git a/test/PrintAsObjC/error-delegate.swift b/test/PrintAsObjC/error-delegate.swift new file mode 100644 index 0000000000000..295aea18d53ac --- /dev/null +++ b/test/PrintAsObjC/error-delegate.swift @@ -0,0 +1,37 @@ +// Please keep this file in alphabetical order! + +// REQUIRES: objc_interop + +// RUN: rm -rf %t && mkdir %t + +// FIXME: BEGIN -enable-source-import hackaround +// 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 +// 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 +// 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 +// FIXME: END -enable-source-import hackaround + +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -import-objc-header %S/Inputs/error-delegate.h -emit-module -o %t %s +// RUN: %target-swift-frontend(mock-sdk: -sdk %S/../Inputs/clang-importer-sdk -I %t) -import-objc-header %S/Inputs/error-delegate.h -parse-as-library %t/error-delegate.swiftmodule -parse -emit-objc-header-path %t/error-delegate.h + +// RUN: FileCheck %s < %t/error-delegate.h +// RUN: %check-in-clang %t/error-delegate.h + +import Foundation + +@objc protocol MySwiftProtocol { } + +// CHECK-LABEL: @interface Test : NSObject +// CHECK-NEXT: - (void)didFail:(NSError * _Nonnull)error; +// CHECK-NEXT: - (void)didFailOptional:(NSError * _Nullable)error; +// CHECK-NEXT-FIXME: - (void)composition:(NSError * _Nonnull)error; +// CHECK-NEXT-FIXME: - (void)compositionOptional:(NSError * _Nullable)error; +// CHECK-NEXT: - (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER; +// CHECK-NEXT: @end +class Test : NSObject, ABCErrorProtocol { + func didFail(_ error: Swift.Error) {} + func didFailOptional(_ error: Swift.Error?) {} + + // FIXME: SILGenc crashes on this. + // func composition(_ error: MySwiftProtocol & Error) { } + // func compositionOptional(_ error: (MySwiftProtocol & Error)?) { } +}