In 1ae317dd88, all the machinery was added
to enable calling ObjC functions that have both async and error
conventions. The handling that was added for matching up arguments and
parameters, however, failed to handle functions that had both foreign
async and foreign error and other arguments. Here, that handling is
fixed.
The fix is in four parts:
- Reverting to a single call to CallSite::emit to emit the formal
params. At this point, the foreign async and/or error params will be
claimed as well.
- Separately counting the async and error parameters in
ParamLowering::claimParams to ensure we get the right parameter
slices.
- Letting ArgEmitter::maybeEmitForeignArgument look for an error
parameter even if it already found an async parameter.
- Letting ArgEmitter::maybeEmitForeignArgument keep looking for foreign
arguments after it finds one.
rdar://80704984
In the synthesized completion handler that is passed to ObjC methods
that are called as async, the formal type of each argument is the
corresponding parameter of the formal type of the block. The non-error,
non-index arguments need to be prepared so that they can be used to
fulfill the continuation; the lambda which does that preparation for
each such argument takes the formal type of that argument. As such, the
call to that lambda needs to pass the type of the corresponding
parameter of the formal type of the block to that lambda. Doing so
entails skipping over the error and flag parameters if they appear
before some of the non-error, non-index arguments.
Previously, no parameters were skipped over. Consequently, when an
error or flag argument preceded one of the non-error, non-index
arguments, the wrong formal type was passed to the preparation lambda.
Here, that is fixed by passing the correct index. The to-be-used
indices for the formal block parameters are the same as the to-be-used
indices for the lowered block parameters minus one reflecting the fact
that the lowered block always has an initial block_storage parameter as
the first argument which the formal type never has.
rdar://81617749
Previously, the function emitCBridgedToNativeValue handled three
situations around optionals:
- Bridged?, Native?
- Bridged, Native?
- Bridged, Native
Here, handling for the fourth case
- Bridged?, Native
is added.
To enable this, the number of Optional wrappings that the bridged type
has that the native type does not is passed in to the function. Then,
in the portions of the function where actual transformations are done,
the values are unwrapped an appropriate number of times. Mostly that
means force unwrapping N times before doing the transformation. In the
case of types that conform to _ObjectiveCBridgeable, however, it means
force unwrapping the value N-1 times after doing the transformation
because _ObjectiveCBridgeable._unconditionallyBridgeFromObjectiveC
performs one layer of unwrapping itself.
rdar://81590807
Previously, SILGen assumed that a foreign function could either have a
foreign async convention or a foreign error convention, but if it had
both, the error would be subsumed into the completion. That resulted in
failures to emit code for async calls of functions like
```
- (BOOL)minimalWithError:(NSError* _Nullable*)error
completionHandler:(void (^ _Nonnull)(void))completionHandler;
```
Here, SILGen gains the ability to emit such functions. To enable that,
a few changes were required when both conventions are present:
- a separate argument for each convention is used
- the ResultPlan is a ForeignErrorResultPlan nesting a
ForeignAsyncResultPlan
- the continuation is always of the form UnsafeContinuation<_, Error>
regardless of whether the completion handler takes an error
- the foreign error block fills the continuation with the error that was
passed by reference out of the ObjC method call
- the foreign error block branches to the block containing the await
instruction
rdar://80704984
Stopped validation-test/compiler_crashers_2_fixed/rdar79383990.swift
from trying to call -[NSBackgroundActivityScheduler scheduleWithBlock:]
async--that method is now annotated NS_SWIFT_DISABLE_ASYNC.
This test case was also posted by a developer in
https://bugs.swift.org/browse/SR-11153, but it appears to
be a different problem that was fixed in Swift 5.2.
Some old circularity-breaking code caused an unexpected null type, which led to crashes in the decl checker when trying to check that an `appendInterpolation` method in a different file would satisfy the informal requirement for one in a StringInterpolationProtocol conformer. This code appears to now be unnecessary, so this commit removes it. Fixes rdar://problem/55864759.
- Deinitializers never get a custom Objective-C name.
- Classes and protocols are never bridged themselves; that only matters
for structs and enums.
This avoids another circularity issue like the one in a8bc132565,
where the Clang importer ends up importing a class and hands it to the
type checker, which then asks about conformances. The conformance
lookup table goes to add the extension from the Swift module, except
that the Swift module is what asked for the import in the first place.
It's possible there's a more general solution here, but this
particular change is good even in the non-crashy cases, and definitely
safe for Swift 4.0. Even if the test case is even more idiosyncratic
than the last one.
The test case change for SourceKit is probably due to the first
category not triggering the import of the other two
categories. Changes in import order have been known to affect source
compatibility, though not frequently. However, categories are not
intended to be ordered in the first place. There's still more we can
do in this space, and implicitly depending on these calls /outside/ of
the importer to control category import order was quite brittle
anyway.
SR-5330 / rdar://problem/32677610
This addresses a crash where the compiler asks if an imported class
inherits initializers from its superclass /during the SIL passes/. In
this particular arrangement of subclasses and initializers (see test
case), this leads to us importing members of an Objective-C class for
the first time well after we've destroyed the type checker, and then
checking to see if an initializer added in a Swift extension can
prevent initializer inheritance. That initializer hasn't been
type-checked (because it's in another file and isn't supposed to
affect anything), and so the compiler chokes. A spot fix would merely
check for 'resolver' here and skip over the initializer if it doesn't
have a type, but it's not clear what the right semantics are in that
case.
The real issue here is that we don't support importing new declarations
after the type checker has been torn down, and that keeps causing us
problems, but that's a much bigger thing to fix.
https://bugs.swift.org/browse/SR-3853