mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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.
This commit is contained in:
@@ -47,6 +47,7 @@ public:
|
||||
bool isPublic() const { return !Value.getPointer(); }
|
||||
bool isPrivate() const { return Value.getInt(); }
|
||||
bool isFileScope() const;
|
||||
bool isInternal() const;
|
||||
|
||||
/// Returns true if this is a child scope of the specified other access scope.
|
||||
///
|
||||
|
||||
@@ -839,6 +839,11 @@ bool AccessScope::isFileScope() const {
|
||||
return DC && isa<FileUnit>(DC);
|
||||
}
|
||||
|
||||
bool AccessScope::isInternal() const {
|
||||
auto DC = getDeclContext();
|
||||
return DC && isa<ModuleDecl>(DC);
|
||||
}
|
||||
|
||||
AccessLevel AccessScope::accessLevelForDiagnostics() const {
|
||||
if (isPublic())
|
||||
return AccessLevel::Public;
|
||||
|
||||
@@ -32,6 +32,33 @@ static void deriveBodyBridgedNSError_enum_nsErrorDomain(
|
||||
// enum SomeEnum {
|
||||
// @derived
|
||||
// static var _nsErrorDomain: String {
|
||||
// return _typeName(self, qualified: true)
|
||||
// }
|
||||
// }
|
||||
|
||||
auto M = domainDecl->getParentModule();
|
||||
auto &C = M->getASTContext();
|
||||
auto self = domainDecl->getImplicitSelfDecl();
|
||||
|
||||
auto selfRef = new (C) DeclRefExpr(self, DeclNameLoc(), /*implicit*/ true);
|
||||
auto stringType = TypeExpr::createForDecl(SourceLoc(), C.getStringDecl(),
|
||||
domainDecl, /*implicit*/ true);
|
||||
auto initReflectingCall =
|
||||
CallExpr::createImplicit(C, stringType,
|
||||
{ selfRef }, { C.getIdentifier("reflecting") });
|
||||
auto ret =
|
||||
new (C) ReturnStmt(SourceLoc(), initReflectingCall, /*implicit*/ true);
|
||||
|
||||
auto body = BraceStmt::create(C, SourceLoc(), ASTNode(ret), SourceLoc());
|
||||
|
||||
domainDecl->setBody(body);
|
||||
}
|
||||
|
||||
static void deriveBodyBridgedNSError_printAsObjCEnum_nsErrorDomain(
|
||||
AbstractFunctionDecl *domainDecl, void *) {
|
||||
// enum SomeEnum {
|
||||
// @derived
|
||||
// static var _nsErrorDomain: String {
|
||||
// return "ModuleName.SomeEnum"
|
||||
// }
|
||||
// }
|
||||
@@ -52,11 +79,12 @@ static void deriveBodyBridgedNSError_enum_nsErrorDomain(
|
||||
}
|
||||
|
||||
static ValueDecl *
|
||||
deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived) {
|
||||
deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived,
|
||||
void (*synthesizer)(AbstractFunctionDecl *, void*)) {
|
||||
// enum SomeEnum {
|
||||
// @derived
|
||||
// static var _nsErrorDomain: String {
|
||||
// return "ModuleName.SomeEnum"
|
||||
// ...
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -74,7 +102,7 @@ deriveBridgedNSError_enum_nsErrorDomain(DerivedConformance &derived) {
|
||||
// Define the getter.
|
||||
auto getterDecl = derived.addGetterToReadOnlyDerivedProperty(
|
||||
derived.TC, propDecl, stringTy);
|
||||
getterDecl->setBodySynthesizer(&deriveBodyBridgedNSError_enum_nsErrorDomain);
|
||||
getterDecl->setBodySynthesizer(synthesizer);
|
||||
|
||||
derived.addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
|
||||
|
||||
@@ -85,8 +113,17 @@ ValueDecl *DerivedConformance::deriveBridgedNSError(ValueDecl *requirement) {
|
||||
if (!isa<EnumDecl>(Nominal))
|
||||
return nullptr;
|
||||
|
||||
if (requirement->getBaseName() == TC.Context.Id_nsErrorDomain)
|
||||
return deriveBridgedNSError_enum_nsErrorDomain(*this);
|
||||
if (requirement->getBaseName() == TC.Context.Id_nsErrorDomain) {
|
||||
auto synthesizer = deriveBodyBridgedNSError_enum_nsErrorDomain;
|
||||
|
||||
auto scope = Nominal->getFormalAccessScope(Nominal->getModuleScopeContext());
|
||||
if (scope.isPublic() || scope.isInternal())
|
||||
// PrintAsObjC may print this domain, so we should make sure we use the
|
||||
// same string it will.
|
||||
synthesizer = deriveBodyBridgedNSError_printAsObjCEnum_nsErrorDomain;
|
||||
|
||||
return deriveBridgedNSError_enum_nsErrorDomain(*this, synthesizer);
|
||||
}
|
||||
|
||||
TC.diagnose(requirement->getLoc(), diag::broken_errortype_requirement);
|
||||
return nullptr;
|
||||
|
||||
@@ -722,4 +722,23 @@ ErrorBridgingTests.test("Error archetype identity") {
|
||||
=== nsError)
|
||||
}
|
||||
|
||||
private class NonPrintAsObjCClass: NSObject {
|
||||
@objc enum Error: Int, Swift.Error {
|
||||
case foo
|
||||
}
|
||||
}
|
||||
@objc private enum NonPrintAsObjCError: Int, Error {
|
||||
case bar
|
||||
}
|
||||
|
||||
ErrorBridgingTests.test("@objc enum error domains") {
|
||||
// If an @objc enum error is not eligible for PrintAsObjC, we should treat it
|
||||
// as though it inherited the default implementation, which calls
|
||||
// String(reflecting:).
|
||||
expectEqual(NonPrintAsObjCClass.Error.foo._domain,
|
||||
String(reflecting: NonPrintAsObjCClass.Error.self))
|
||||
expectEqual(NonPrintAsObjCError.bar._domain,
|
||||
String(reflecting: NonPrintAsObjCError.self))
|
||||
}
|
||||
|
||||
runAllTests()
|
||||
|
||||
Reference in New Issue
Block a user