Skip to content

Commit 2eed537

Browse files
committed
Only generate domains for PrintAsObjC-able types
Otherwise we generate a call to String(reflecting:), which correctly handles many things we may not be able to (like private types), and which matches the default implementation of Error._domain.
1 parent 1a6ca82 commit 2eed537

File tree

4 files changed

+68
-6
lines changed

4 files changed

+68
-6
lines changed

include/swift/AST/AccessScope.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class AccessScope {
4747
bool isPublic() const { return !Value.getPointer(); }
4848
bool isPrivate() const { return Value.getInt(); }
4949
bool isFileScope() const;
50+
bool isInternal() const;
5051

5152
/// Returns true if this is a child scope of the specified other access scope.
5253
///

lib/AST/DeclContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,11 @@ bool AccessScope::isFileScope() const {
839839
return DC && isa<FileUnit>(DC);
840840
}
841841

842+
bool AccessScope::isInternal() const {
843+
auto DC = getDeclContext();
844+
return DC && isa<ModuleDecl>(DC);
845+
}
846+
842847
AccessLevel AccessScope::accessLevelForDiagnostics() const {
843848
if (isPublic())
844849
return AccessLevel::Public;

lib/Sema/DerivedConformanceError.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,34 @@ using namespace swift;
2828
using namespace swift::objc_translation;
2929

3030
static void deriveBodyBridgedNSError_enum_nsErrorDomain(
31-
AbstractFunctionDecl *domainDecl, void *) {
31+
AbstractFunctionDecl *domainDecl, void *) {
32+
// enum SomeEnum {
33+
// @derived
34+
// static var _nsErrorDomain: String {
35+
// return _typeName(self, qualified: true)
36+
// }
37+
// }
38+
39+
auto M = domainDecl->getParentModule();
40+
auto &C = M->getASTContext();
41+
auto self = domainDecl->getImplicitSelfDecl();
42+
43+
auto selfRef = new (C) DeclRefExpr(self, DeclNameLoc(), /*implicit*/ true);
44+
auto stringType = TypeExpr::createForDecl(SourceLoc(), C.getStringDecl(),
45+
domainDecl, /*implicit*/ true);
46+
auto initReflectingCall =
47+
CallExpr::createImplicit(C, stringType,
48+
{ selfRef }, { C.getIdentifier("reflecting") });
49+
auto ret =
50+
new (C) ReturnStmt(SourceLoc(), initReflectingCall, /*implicit*/ true);
51+
52+
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(ret), SourceLoc());
53+
54+
domainDecl->setBody(body);
55+
}
56+
57+
static void deriveBodyBridgedNSError_printAsObjCEnum_nsErrorDomain(
58+
AbstractFunctionDecl *domainDecl, void *) {
3259
// enum SomeEnum {
3360
// @derived
3461
// static var _nsErrorDomain: String {
@@ -52,11 +79,12 @@ static void deriveBodyBridgedNSError_enum_nsErrorDomain(
5279
}
5380

5481
static ValueDecl *
55-
deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived) {
82+
deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived,
83+
void (*synthesizer)(AbstractFunctionDecl *, void*)) {
5684
// enum SomeEnum {
5785
// @derived
5886
// static var _nsErrorDomain: String {
59-
// return "ModuleName.SomeEnum"
87+
// ...
6088
// }
6189
// }
6290

@@ -74,7 +102,7 @@ deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived) {
74102
// Define the getter.
75103
auto getterDecl = derived.addGetterToReadOnlyDerivedProperty(
76104
derived.TC, propDecl, stringTy);
77-
getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_nsErrorDomain);
105+
getterDecl->setBodySynthesizer(synthesizer);
78106

79107
derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
80108

@@ -85,8 +113,17 @@ ValueDecl *DerivedConformance::deriveBridgedNSError(ValueDecl *requirement) {
85113
if (!isa<EnumDecl>(Nominal))
86114
return nullptr;
87115

88-
if (requirement->getBaseName() == TC.Context.Id_nsErrorDomain)
89-
return deriveBridgedNSError_enum_nsErrorDomain(*this);
116+
if (requirement->getBaseName() == TC.Context.Id_nsErrorDomain) {
117+
auto synthesizer = deriveBodyBridgedNSError_enum_nsErrorDomain;
118+
119+
auto scope = Nominal->getFormalAccessScope(Nominal->getModuleScopeContext());
120+
if (scope.isPublic() || scope.isInternal())
121+
// PrintAsObjC may print this domain, so we should make sure we use the
122+
// same string it will.
123+
synthesizer = deriveBodyBridgedNSError_printAsObjCEnum_nsErrorDomain;
124+
125+
return deriveBridgedNSError_enum_nsErrorDomain(*this, synthesizer);
126+
}
90127

91128
TC.diagnose(requirement->getLoc(), diag::broken_errortype_requirement);
92129
return nullptr;

test/stdlib/ErrorBridged.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,4 +722,23 @@ ErrorBridgingTests.test("Error archetype identity") {
722722
=== nsError)
723723
}
724724

725+
private class NonPrintAsObjCClass: NSObject {
726+
@objc enum Error: Int, Swift.Error {
727+
case foo
728+
}
729+
}
730+
@objc private enum NonPrintAsObjCError: Int, Error {
731+
case bar
732+
}
733+
734+
ErrorBridgingTests.test("@objc enum error domains") {
735+
// If an @objc enum error is not eligible for PrintAsObjC, we should treat it
736+
// as though it inherited the default implementation, which calls
737+
// String(reflecting:).
738+
expectEqual(NonPrintAsObjCClass.Error.foo._domain,
739+
String(reflecting: NonPrintAsObjCClass.Error.self))
740+
expectEqual(NonPrintAsObjCError.bar._domain,
741+
String(reflecting: NonPrintAsObjCError.self))
742+
}
743+
725744
runAllTests()

0 commit comments

Comments
 (0)