Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-700] Domain of NSErrors created from Swift ErrorTypes sometimes don't match synthesized Domain constant #43315

Closed
lilyball mannequin opened this issue Feb 9, 2016 · 6 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself good first issue Good for newcomers

Comments

@lilyball
Copy link
Mannequin

lilyball mannequin commented Feb 9, 2016

Previous ID SR-700
Radar None
Original Reporter @lilyball
Type Bug
Status Closed
Resolution Done
Environment

Apple Swift version 2.1.1 (swiftlang-700.1.101.15 clang-700.1.81)
Target: x86_64-apple-darwin15.3.0

Apple Swift version 2.2 (swiftlang-703.0.6.5 clang-703.0.21)
Target: x86_64-apple-macosx10.9

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, StarterBug
Assignee @lilyball
Priority

md5: bee4248122994eee9b64fe5c8b938056

Issue Description:

When writing a Swift enum like

@objc enum MyError: Int, ErrorType {
    case A, B
}

Given a module name "Foo", Swift synthesizes the following ObjC declaration:

typedef SWIFT_ENUM(NSInteger, MyError) {
    MyErrorA = 0,
    MyErrorB = 1,
}
static NSString * _Nonnull const MyErrorDomain = @"Foo.MyError";

In an Xcode project, this works perfectly fine. Casting MyError.A to NSError and looking at the domain property yields the string "Foo.MyError".

However, for some reason, when testing this at the command-line with a manual invocation of swiftc, the bridged NSError loses the module name in the domain string, so it just has "MyError". I've tested this both in an executable context (e.g. swiftc -module-name Foo -emit-objc-header foo.swift main.swift where foo.swift defines the error and main.swift prints it out) and in a library context (e.g. compiling foo.swift as a library, and then linking to it from a separate compilation of main.swift that imports the Foo module). I don't know what's different about an Xcode project that causes the error domain to work.


// foo.swift
import Foundation

@objc enum MyError: Int, ErrorType {
    case A, B
}
// main.swift
import Foundation

print("type: \(MyError.self)")
print("debugType: \(String(reflecting: MyError.self))")
print("error.domain: \((MyError.A as NSError).domain)")

Reproduction:

> swiftc -module-name Foo -emit-objc-header foo.swift main.swift
> ./Foo
type: MyError
debugType: Foo.MyError
error.domain: MyError
> grep MyErrorDomain Foo.h
static NSString * _Nonnull const MyErrorDomain = @"Foo.MyError";
@belkadan
Copy link
Contributor

belkadan commented Feb 9, 2016

It looks like we just synthesize this wrong. @objc enums get an extra secret conformance that overrides the default domain, but does so incorrectly. The relevant code is in deriveBodyBridgedNSError_enum_NSErrorDomain in DerivedConformanceErrorType.cpp.

@belkadan
Copy link
Contributor

belkadan commented Feb 9, 2016

(We don't actually need them to override the default domain, but the _BridgedNSError protocol is used for imported enums as well.)

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Mar 1, 2016

The derived implementation here is equivalent to

@derived
static var _NSErrorDomain: String {
    return "\(self)"
}

So what's really going on here is printing the type itself is omitting the module name. Although this code should probably be changed to explicitly do the ModuleName.TypeName format to match PrintObjC.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Mar 1, 2016

Side note: The following code, while a bad idea, is also relevant:

class Foo: NSObject {
    @objc enum Bar: Int, ErrorType {
        case A, B
    }
}

With this type, the enum will still end up in the generated Obj-C header with the domain "ModuleName.Bar" but the qualified name for the type is actually ModuleName.Foo.Bar. Switching the domain generation to always being "ModuleName.UnqualifiedTypeName" instead of relying on the value of "(self)" should fix this case as well.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Mar 1, 2016

Submitted as PR #1495.

@lilyball
Copy link
Mannequin Author

lilyball mannequin commented Mar 5, 2016

Merged in f189f8d.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

1 participant