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

Implement SE-0112: Improved NSError bridging #3459

Merged
merged 18 commits into from Jul 12, 2016
Merged

Conversation

DougGregor
Copy link
Member

What's in this pull request?

This pull request implements SE-0112

Resolved bug number: (rdar://problem/27174964)

It looks like this PR might address several other open issues on bugs.swift.org. I'll scrub those as well.


Before merging this pull request to apple/swift repository:

  • Test pull request on Swift continuous integration.

Triggering Swift CI

The swift-ci is triggered by writing a comment on this PR addressed to the GitHub user @swift-ci. Different tests will run depending on the specific comment that you use. The currently available comments are:

Smoke Testing

Platform Comment
All supported platforms @swift-ci Please smoke test
All supported platforms @swift-ci Please smoke test and merge
OS X platform @swift-ci Please smoke test OS X platform
Linux platform @swift-ci Please smoke test Linux platform

Validation Testing

Platform Comment
All supported platforms @swift-ci Please test
All supported platforms @swift-ci Please test and merge
OS X platform @swift-ci Please test OS X platform
OS X platform @swift-ci Please benchmark
Linux platform @swift-ci Please test Linux platform

Lint Testing

Language Comment
Python @swift-ci Please Python lint

Note: Only members of the Apple organization can trigger swift-ci.

@DougGregor
Copy link
Member Author

@swift-ci please test and merge

2 similar comments
@DougGregor
Copy link
Member Author

@swift-ci please test and merge

@DougGregor
Copy link
Member Author

@swift-ci please test and merge

Introduce bridging of NSError to ErrorProtocol, so an Objective-C API
expressed via an "NSError *" will be imported using ErrorProtocol in
the Swift. For example, the Objective-C method:

  - (void)handleError:(NSError *)error userInteractionPermitted:(BOOL)userInteractionPermitted;

will now be imported as:

  func handleError(_ error: ErrorProtocol, userInteractionPermitted: Bool)

This is bullet (3) under the proposed solution of SE-0112. Note that
we made one semantic change here: instead of removing the conformance
of NSError to ErrorProtocol, which caused numerous problems both
theoretical and actual because the model expects that an NSError
conforms to ErrorProtocol without requiring wrapping, we instead limit
the ErrorProtocol -> NSError conversion that would be implied by
bridging. This is defensible in the short term because it also
eliminates the implicit conversion, and aligns with SE-0072, which
eliminates implicit bridging conversions altogether.
…subscript decls.

For historical reasons, the "name shadowing" computation is only
looking at the type---not even the interface type!---of
declarations. For variables and subscripts, this means that the
context (e.g., a constrained extension) wasn't been considered at all,
leading to declarations from other imported modules being
ignored. Patch up a little bit of this by using the overload
signature's type for variables and subscripts, because I need it for
ErrorProtocol's default implementations.

Longer-term, we should be using the overload signature (or something
very like it) for shadowing, consistently.
…mNSError

An error type can conform to one or more of these new protocols to
customize its behavior and representation. From an implementation
standpoint, the protocol conformances are used to fill in the
user-info dictionary in NSError to interoperate with the Cocoa
error-handling system.

There are a few outstanding problems with this implementation,
although it is fully functional:
  * Population of the userInfo dictionary is currently eager; we
  should use user info providers on platforms where they are
  available.
  * At present, the Swift dynamic casting machinery is unable to unbox a
  _SwiftNativeNSError when trying to cast from it to (e.g.) an
  existential, which makes it impossible to retrieve the
  RecoverableError from the NSError. Instead, just capture the original
  error---hey, they're supposed to be value types anyway!---and use that
  to implement the entry points for the informal
  NSErrorRecoveryAttempting protocol.

This is part (1) of the proposal solution.
Provides a localized description for an error, using Cocoa's
error-handling logic. The first part of item (4) in SE-0112's proposed
solution.
This is part of loosening _BridgedNSError up a bit, so it can work
with error types that directly embed an NSError instance.
NSCocoaError was capturing only the code of a Cocoa error, making it
basically useless. Instead, capture the entire NSError, the code of
which is tracked by an nested, RawRepresentable type Code. Provide
typed accessors for the common keys in the Cocoa error domain, e.g.,
NSFilePathErrorKey, NSStringEncodingErrorKey, NSUnderlyingErrorKey,
and NSURLErrorKey, to make this type easier to use.

This is specifically an implementation of part (4) of the proposed
solution to SE-0112, which makes NSCocoaError more usable. It also
adds localizedDescription to ErrorProtocol.

However, it also introduces the infrastructure needed for importing
error enumeration types more smoothly, e.g., ErrorCodeProtocol
(underscored for now), the ~= operator for matching error codes, and
so on. In essence, NSCocoaError is the pattern that the importer will
follow.
This ensures that we don't lose information about the NSError when it
is bridged to NSError. Use this to expose information for common keys
in the NSURLError domain (NSURLErrorFailingURLErrorKey,
NSURLErrorFailingURLStringErrorKey,
NSURLErrorFailingURLPeerTrustErrorKey).

This is effectively part of bullet (4) in the proposed solution of
SE-0112, applied to NSURLError. There are a handful of other domains
that need this treatment as well.
The error domain is meant to identify the type; it cannot meaningfully vary.
This will get clearer when SE-0104 gets implemented and we can use the
Integer protocol.
The error code is now specified by POSIXErrorCode.
The error code is now specified by MachErrorCode.
A given Objective-C error enum, which is effectively an NS_ENUM that
specifies its corresponding error domain, will now be mapped to an
ErrorProtocol-conforming struct that wraps an NSError, much like
NSCocoaError does. The actual enum is mapped to a nested "Code"
enum. For example, CoreLocation's CLError becomes:

  struct CLError : ErrorProtocol {
    let _nsError: NSError
    // ...
   @objc enum Code : Int {
     case ...
   }
  }

This implements bullet (2) in the proposed solution of SE-0112, so
that Cocoa error types are mapped into structures that maintain the
underlying NSError to allow more information to be extracted from it.
This is bullet (5) of the proposed solution in SE-0112, and the last
major piece to be implemented.
@DougGregor DougGregor merged commit edd389a into master Jul 12, 2016
@DougGregor DougGregor deleted the nserror-bridging branch July 12, 2016 17:54
kateinoigakukun pushed a commit that referenced this pull request Aug 31, 2022
Resolve conflicts with upstream `main`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant