Skip to content

[SR-487] Compiler fails to consider @autoclosure when satisfying try requirements #43104

Open
@swift-ci

Description

@swift-ci
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:

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 { }
}

Metadata

Metadata

Labels

@autoclosureFeature → attributes: the @autoclosure type attributeattributesFeature: Declaration and type attributesbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.closuresFeature: closurescompilerThe Swift compiler itselferror handlingexpressionsFeature: expressionsswift 6.0throws & rethrowsFeature → error handling: throws & rethrowstype checkerArea → compiler: Semantic analysistype inferenceFeature: type inferenceunexpected errorBug: Unexpected error

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions