The name of the `TaskExecutor` protocol was recently changed to remove
underscores after the feature was accepted in Swift Evolution. An implication
of that rename is that the `buildOrdinaryTaskExecutorRef` builtin changed
the type that it expected as the argument. However, the original change
landed in the standard library which as since produced swiftinterfaces
that contain the following inlinable code:
```
@inlinable public init<E>(ordinary executor: __shared E) where E : _Concurrency._TaskExecutor {
#if $BuiltinBuildTaskExecutor
self.executor = Builtin.buildOrdinaryTaskExecutorRef(executor)
#else
fatalError("Swift compiler is incompatible with this SDK version")
#endif
}
```
When a compiler containing the protocol rename attempts to type check the
above inlinable code, it crashes because the builtin is expecting an argument
conforming to `TaskExecutor`, which doesn't exist in this version of the
standard library. The issue is that the current compiler still supports
the `$BuiltinBuildTaskExecutor` feature guard, but the builtin supported
has since changed.
To resolve this issue, we need to stop supporting the `$BuiltinBuildTaskExecutor`
feature guard and introduce a new one that is only supported by compiler versions
that contain the rename. This approach relies on nothing having adopted the
API, otherwise we would need to stage in the rename as a parallel set of APIs,
and only remove the old APIs once nothing is relying on the old _Concurrency
swiftinterfaces.
Don't delete the OS declaration of `exit` because the concurrency shims aren't always imported, and so the shim declaration might not always be available.
Don't override the OS declaration of `exit` in the concurrency shims since we can't just delete the OS one. Instead, set up internal shims just for building Concurrency that forward declares `exit`.
This entails passing a linker flags to Apple linkers when the standard
library is not meant for inclusion in such cache.
For this to have effect on every library, propagate link flags when
building _Concurrency and Observation.
This is needed for Apple internal configurations.
Addresses rdar://120653968
Allow `AsyncSequence.flatMap` to be defined with "incorrect" availability,
meaning that the function can refer to the `Failure` associated type
in its where clause even though the function is back-deployed to
before the `Failure` associated type was introduced.
We believe this is safe, and that this notion can be generalized to any
use of an associated type in a same-type constraint of a function
(yes, it sounds weird), but for now introduce a narrower hack to see
how things work in practice and whether it addresses all of the
source-compatibility concerns we've uncovered.
Use an optional isolated parameter to this new `next(_:)` overload to
keep it on the same actor as the caller, and pass `#isolation` when
desugaring the async for..in loop. This keeps async iteration loops on
the same actor, allowing non-Sendable values to be used with many
async sequences.
`AsyncFlatMapSequence` is somewhat troublesome for typed throws,
because it can produce errors from two different sources: the `Base`
async sequence and the `SegmentOfResult` async sequence. However, we
need to pick one `Failure` type for the `AsyncFlatMapSequence`, and
there is no surface-language equivalent to the `errorUnion` operation
described in SE-0413.
So, we do something a little bit sneaky. We effectively require that
`SegmentOfResult.Failure` either be equivalent to `Base.Failure` or be
`Never`, such so that when the async sequence retruned by the closure
throws, it throws the same thing as the base sequence. Therefore, the
`Failure` type is defined to be `Base.Failure`.
This property isn't enforced at the type level, but instead in the
`AsyncSequence.flatMap` signatures: we replace the one signature that
returned `AsyncFlatMapSequence` with three overloads that differ only
in their generic requirements, adding:
1. `where SegmentOfResult.Failure == Failure`
2. `where SegmentOfResult.Failure == Never`
3. `where SegmentOfResult.Failure == Never, Failure == Never` (a
tiebreaker between the two above)
For cases where `SegmentOfResult.Failure` is neither `Never` nor
`Failure`, overloading will choose the `flatMap` function that returns
an `AsyncThrowingFlatMapSequence`. This can mean that existing code
will choose a different overload and get a different type, but other
than the type identity changing, the resulting sequence will behave
the same way.
Start implementing `nextElement()` for the various async sequences
provided by the concurrency library, starting with those that
currently depend on `rethrows` with conformances, an undocumented
feature we're trying to stage out of the language.
With the exception of `AsyncFlatMapSequence`, all of these async
sequences have obvious implementations of `nextElement()`. We'll save
that one for later.
This couples together several changes to move entirely from
`@rethrows` over to typed throws:
* Use the `Failure` type to determine whether an async for-each loop
will throw, rather than depending on rethrows checking
* Introduce a special carve-out for `rethrows` functions that have a
generic requirement on an `AsyncSequence` or `AsyncIteratorProtocol`,
which uses that requirement's `Failure` type as potentially being part
of the thrown error type. This allows existing generic functions like
the following to continue to work:
func f<S: AsyncSequence>(_: S) rethrows
* Switch SIL generation for the async for-each loop from the prior
`next()` over to the typed-throws version `_nextElement`.
* Remove `@rethrows` from `AsyncSequence` and `AsyncIteratorProtocol`
entirely. We are now fully dependent on typed throws.
Introduce a new associated type `Failure` into the two protocols involved
in async sequences, which represents the type thrown when the sequence
fails. Introduce a defaulted `_nextElement()` operations that throws
`Failure` or produces the next element of the sequence. Provide a
default implementation of `_nextElement()` in terms of `next()` that
force-cases the thrown error to the `Failure` type.
Introduce special associated type inference logic for the `Failure`
type of an `AsyncIteratorProtocol` conformance when there is no
specific _nextElement()` witness. This inference logic looks at the
witness for `next()`:
* If `next()` throws nothing, `Failure` is inferred to `Never`.
* If `next()` throws, `Failure` is inferred to `any Error`.
* If `next()` rethrows, `Failure` is inferred to `T.Failure`, where
`T` is the first type parameter with a conformance to either
`AsyncSequence` or `AsyncIteratorProtocol`.
The default implementation and the inference rule, together, allow
existing async sequences to continue working as before, and set us up
for changing the contract of the `async for` loop to use
`_nextIterator()` rather than `next()`.
Give `AsyncSequence` and `AsyncIteratorProtocol` primary associated
types for the element and failure types, which will allow them to be
used more generally with existential and opaque types.
The function is marked `noreturn` but the compiler was not able to reason
statically about whether this constraint is met. From code inspection it's
clear that the call to `swift_task_donateThreadToGlobalExecutorUntil()` does
not return, so `swift_unreachable()` can be used to suppress the warning.
We are currently lacking the ability to describe "normal or distributed
actor" with a single protocol in a manner that allows hopping to it,
because `AnyActor` is a marker protocol. Use `Actor` while we sort
this out.
The `swift_unreachable()` is currently statically unreachable but we'd like to
leave it in place in case the control flow before it changes in the future.