Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions Sources/IssueReporting/ErrorReporting.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,38 @@ public func withErrorReporting<R>(
}
}

/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
/// - Parameters:
/// - message: A message describing the expectation.
/// - reporters: Issue reporters to notify during the operation.
/// - fileID: The source `#fileID` associated with the error reporting.
/// - filePath: The source `#filePath` associated with the error reporting.
/// - line: The source `#line` associated with the error reporting.
/// - column: The source `#column` associated with the error reporting.
/// - body: A synchronous operation.
/// - Returns: The optional result of the operation, or `nil` if an error was thrown.
@_transparent
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
catching body: () throws -> R?
) -> R? {
(withErrorReporting(
message(),
to: reporters,
fileID: fileID,
filePath: filePath,
line: line,
column: column,
catching: body
) as R??) ?? nil
}

#if compiler(>=6)
/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
Expand Down Expand Up @@ -113,6 +145,42 @@ public func withErrorReporting<R>(
}
}
}

/// Evaluates a throwing closure and automatically catches and reports any error thrown.
///
/// - Parameters:
/// - message: A message describing the expectation.
/// - reporters: Issue reporters to notify during the operation.
/// - fileID: The source `#fileID` associated with the error reporting.
/// - filePath: The source `#filePath` associated with the error reporting.
/// - line: The source `#line` associated with the error reporting.
/// - column: The source `#column` associated with the error reporting.
/// - isolation: The isolation associated with the error reporting.
/// - body: An asynchronous operation.
/// - Returns: The optional result of the operation, or `nil` if an error was thrown.
@_transparent
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
isolation: isolated (any Actor)? = #isolation,
// DO NOT FIX THE WHITESPACE IN THE NEXT LINE UNTIL 5.10 IS UNSUPPORTED
// https://github.com/swiftlang/swift/issues/79285
catching body: () async throws -> sending R?
) async -> R? {
(await withErrorReporting(
message(),
to: reporters,
fileID: fileID,
filePath: filePath,
line: line,
column: column,
catching: body
) as R??) ?? nil
}
#else
@_transparent
@_unsafeInheritExecutor
Expand Down Expand Up @@ -157,4 +225,26 @@ public func withErrorReporting<R>(
}
}
}

@_transparent
@_unsafeInheritExecutor
public func withErrorReporting<R>(
_ message: @autoclosure () -> String? = nil,
to reporters: [any IssueReporter]? = nil,
fileID: StaticString = #fileID,
filePath: StaticString = #filePath,
line: UInt = #line,
column: UInt = #column,
catching body: () async throws -> R?
) async -> R? {
(await withErrorReporting(
message(),
to: reporters,
fileID: fileID,
filePath: filePath,
line: line,
column: column,
catching: body
) as R??) ?? nil
}
#endif
22 changes: 22 additions & 0 deletions Tests/IssueReportingTests/WithErrorReportingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,28 @@
}
}

@Test func squashOptionalSync() async {
withKnownIssue {
let _: Int? = withErrorReporting { () -> Int? in
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError()\(issueDescriptionSuffix)"
}
}


@Test func squashOptionalAsync() async {
await withKnownIssue {
let _: Int? = await withErrorReporting { () -> Int? in
await Task.yield()
throw SomeError()
}
} matching: { issue in
issue.description == "Caught error: SomeError()\(issueDescriptionSuffix)"
}
}

#if compiler(<6.2)
@MainActor
@Test func isolation() async {
Expand Down