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-487] Compiler fails to consider @autoclosure when satisfying try requirements #43104

Open
swift-ci opened this issue Jan 7, 2016 · 9 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

swift-ci commented Jan 7, 2016

Previous ID SR-487
Radar rdar://problem/22394263
Original Reporter russ (JIRA User)
Type Bug
Environment

Apple Swift version 2.1.1 (swiftlang-700.1.101.15 clang-700.1.81)
Apple Swift version 3.0-dev (LLVM dffa09ffd8, Clang 9f0d189820, Swift 1c720b8) (May 9, 2016 snapshot)

Additional Detail from JIRA
Votes 10
Component/s Compiler
Labels Bug
Assignee @slavapestov
Priority Medium

md5: 144912dacff217d48a6b1ce1fd642c20

is duplicated by:

  • SR-4500 Wrong compiler error with @autoclosure parameter
  • SR-9731 @autoclosure dealing throws declaration wiredly
  • SR-9815 Swift complains about throwing function that isn't one (through @autoclosure)
  • SR-10814 Incorrect compiler error with try + autoclosure inside another closure
  • SR-11214 Swift compiler incorrectly warns or errors when a try is captured by a throwing @autoclosure parameter to a function which does not itself throw.
  • SR-11669 Calling function with throwing autoclosure parameter in another closure.

Issue Description:

Minimal example shown below. In certain situations the compiler is attempting to promote the outer closure to `throws` when the `try` is automatically promoted to a closure. In other situations it correctly surmises that the auto closure makes any attempt to `catch` pointless.

func fancyThings() throws { }

func withTemporaryFile(filename: String = NSUUID().UUIDString, deleteWhenFinished: Bool = true, @noescape f: (NSURL) -> Void) { }

func AssertNoThrowNoAutoclosure<T>(expression: () throws -> T) {
    do {
        try expression()
    } catch {
        fatalError("Error was thrown when none were expected: \(error)")
    }
}

func AssertNoThrow<T>(@autoclosure expression: () throws -> T) {
    do {
        try expression()
    } catch {
        fatalError("Error was thrown when none were expected: \(error)")
    }
}


withTemporaryFile { tempFile -> Void in
//: Works fine, param is not autoclosure
    AssertNoThrowNoAutoclosure({ try fancyThings() })


/*: 
This triggers a compiler error even though autoclosure
    promotes the `try` into a closure; the `do` form below 
    should be equivalent since `AssertNoThrow` is not a 
    throwing function. Instead it attempts to promote the
    `withTemporaryFile` closure to throwing.
    
**error: invalid conversion from throwing function of type '_ throws -> Void' to non-throwing function type '(NSURL) -> Void'**
*/
    AssertNoThrow(try fancyThings())


/*:
Attempting to pass an explicit closure also confuses the compiler

**error: cannot invoke 'AssertNoThrow' with an argument list of type '(() throws -> ())'**
*/
    AssertNoThrow({ try fancyThings() })


/*: 
An explicit `do` still emits a warning because the compiler
correctly deduces that nothing can throw (the autoclosure 
hides the try)

**warning: 'catch' block is unreachable because no errors are thrown in 'do' block**
*/
    do {
        AssertNoThrow(try fancyThings())
    } catch { }
}
@lilyball
Copy link
Mannequin

lilyball mannequin commented May 12, 2016

This occurs whenever a try expression is used for an @autoclosure parameter for a function call inside a closure. The culprit appears to be the code that infers the type of a closure expression. Here's a reduced sample:

func foo(_ expr: @autoclosure () throws -> Void) {
    do {
        try expr()
    } catch {
        print("error: \(error)")
    }
}

func err() throws -> Void {
    struct Foo: ErrorProtocol {}
    throw Foo()
}

func topLevel() {
    // works
    foo(try err())
    // warning about unreachable catch block
    let _: () -> Void = {
        do {
            foo(try err())
        } catch {}
    }
    // error
    let _: () -> Void = {
        foo(try err())
    }
}

@swift-ci
Copy link
Collaborator Author

Comment by Vaddadi Kartick (JIRA)

This seems to happen even without autoclosure:

func ignoreException<ReturnType>(_ closure: () throws -> ReturnType) -> ReturnType? {
    do {
        return try closure()
    } catch {
        assertionFailure("Proceeding by ignoring exception: \(error)")
        return nil
    }
}

ignoreException{ device.lockForConfiguration() }

This says that the call can throw, but it is not marked with try and the error isn't handled.

This is with Swift 3 on Xcode 8.2.1 (8C1002) as of Feb 2017.

@lilyball
Copy link
Mannequin

lilyball mannequin commented Feb 14, 2017

kart (JIRA User) The error is correct in your case. The correct code is

ignoreException { try device.lockForConfiguration() }

@swift-ci
Copy link
Collaborator Author

Comment by Vaddadi Kartick (JIRA)

Thanks for pointing that out, and excuse my poor understanding of Swift.

@swift-ci
Copy link
Collaborator Author

Comment by Kevin Nattinger (JIRA)

This still occurs as of Xcode 9 (released) and Xcode 9.1 beta 2.

@swift-ci
Copy link
Collaborator Author

Comment by Andrej (JIRA)

This seems to be the case when using `XCTAssertNoThrow` in the context on non-throwing closure in my case. Still an issue on Xcode 9.2.

@swift-ci
Copy link
Collaborator Author

Comment by Gereon Steffens (JIRA)

Still an issue with Swift 4.2 / Xcode 10.1 when using `XCTAssertNoThrow` or `XCTAssertThrowsError` in a closure.

@swift-ci
Copy link
Collaborator Author

Comment by Thijs de Vries (JIRA)

Still an issue in swift 5.2 / XCode 11.4

Makes it hard to use quick since every it statement is a closure.

@swift-ci
Copy link
Collaborator Author

Comment by Texot (JIRA)

Still an issue in Swift 5.5.2 / XCode 13.2.1

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
Projects
None yet
Development

No branches or pull requests

1 participant