Skip to content

Commit 83bcf23

Browse files
committed
[sending] Check for a nullptr in AssociatedTypeInference when calling computeFailureTypeWitness.
The problem happens when a type conforms to AsyncIterator.next when next in the protocol returns its value as sending, but the witness does not have sending. This results in the function subtyping rules rejecting the witness... but we still leave in the witness as a nullptr... so we need to handle it here. rdar://129300953
1 parent 3c166b5 commit 83bcf23

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2425,7 +2425,9 @@ AssociatedTypeInference::computeFailureTypeWitness(
24252425
// it.
24262426
for (const auto &witness : valueWitnesses) {
24272427
if (isAsyncIteratorProtocolNext(witness.first)) {
2428-
if (auto witnessFunc = dyn_cast<AbstractFunctionDecl>(witness.second)) {
2428+
// We use a dyn_cast_or_null since we can get a nullptr here if we fail to
2429+
// match a witness. In such a case, we should just fail here.
2430+
if (auto witnessFunc = dyn_cast_or_null<AbstractFunctionDecl>(witness.second)) {
24292431
auto thrownError = witnessFunc->getEffectiveThrownErrorType();
24302432

24312433
// If it doesn't throw, Failure == Never.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// RUN: not %target-swift-frontend %s -c -swift-version 6 -module-name _Concurrency
2+
3+
// READ THIS: This test is only supposed to be making sure that we do not crash
4+
// when we fail to match a witness that doesn't match AsyncIteratorProtocol.next
5+
// b/c of sending. It should fail... but not crash.
6+
7+
@available(SwiftStdlib 5.1, *)
8+
public protocol AsyncIteratorProtocol<Element, Failure> {
9+
associatedtype Element
10+
11+
/// The type of failure produced by iteration.
12+
@available(SwiftStdlib 6.0, *)
13+
associatedtype Failure: Error = any Error
14+
15+
/// Asynchronously advances to the next element and returns it, or ends the
16+
/// sequence if there is no next element.
17+
///
18+
/// - Returns: The next element, if it exists, or `nil` to signal the end of
19+
/// the sequence.
20+
mutating func next() async throws -> sending Element?
21+
22+
/// Asynchronously advances to the next element and returns it, or ends the
23+
/// sequence if there is no next element.
24+
///
25+
/// - Returns: The next element, if it exists, or `nil` to signal the end of
26+
/// the sequence.
27+
@available(SwiftStdlib 6.0, *)
28+
mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> sending Element?
29+
}
30+
31+
@available(SwiftStdlib 5.1, *)
32+
extension AsyncIteratorProtocol {
33+
/// Default implementation of `next(isolation:)` in terms of `next()`, which
34+
/// is required to maintain backward compatibility with existing async
35+
/// iterators.
36+
@available(SwiftStdlib 6.0, *)
37+
@inlinable
38+
public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> sending Element? {
39+
do {
40+
return try await next()
41+
} catch {
42+
throw error as! Failure
43+
}
44+
}
45+
}
46+
47+
@available(SwiftStdlib 5.1, *)
48+
extension AsyncIteratorProtocol {
49+
/// Default implementation of `next()` in terms of `next(isolation:)`, which
50+
/// is required to maintain backward compatibility with existing async
51+
/// iterators.
52+
@available(SwiftStdlib 6.0, *)
53+
@inlinable
54+
public mutating func next() async throws(Failure) -> sending Element? {
55+
#if $OptionalIsolatedParameters
56+
return try await next(isolation: nil)
57+
#else
58+
fatalError("unsupported compiler")
59+
#endif
60+
}
61+
}
62+
63+
public struct FakeMapSequence<T> : AsyncIteratorProtocol {
64+
typealias Element = T
65+
66+
@available(SwiftStdlib 6.0, *)
67+
@inlinable
68+
public mutating func next(isolation actor: isolated (any Actor)?) async throws(Failure) -> Element? {
69+
fatalError()
70+
}
71+
72+
@inlinable
73+
public mutating func next() async throws -> Element? {
74+
fatalError()
75+
}
76+
}
77+

0 commit comments

Comments
 (0)