Background: We've noticed a lot of problems from Obj-C APIs that returned null
even though they were declared to never do so. These mismatches subvert Swift's
type system and can lead to hard-to-diagnose crashes much later in the program.
This fatal error was introduced into the primary casting function to help catch
such problems closer to the point where they occur so developers could more
easily identify and fix them.
However, there's been some concern about what this means for old binaries, so
we're considering a check here that would allow the old behavior in certain
cases yet to be determined. This PR adds the framework for such a check.
Resolves rdar://72323929
* Dynamic Casting: Properly unwrap existential metatype sources
Existential metatypes are really just existentials that hold metatypes. As
such, they should be handled in the general casting logic in much the same way
as regular existentials: They should generally be ignored by most casting logic,
and unwrapped as necessary at the top level.
In particular, the previous code would fail to correctly handle the following
cast from an existential metatype (`AnyObject.Type`) to an existential
(`AnyObject`):
```
class C {}
let a = C.self as AnyObject.Type
let b = a as! AnyObject
```
With the old code, `b` above would hold a reference to a `__SwiftValue` box
containing the type reference. The correct result would simply store the type
reference directly in `b`. These two are only really distinguishable in that
the correct form permits `a === b` to return `true`.
Fixes rdar://70582753
Note: This is not yet fully supported on Linux. Basically, metatypes on Linux are not currently
fully compatible with reference-counted class pointers, which prevents us from
fully supporting metatype operations on Linux that we support on macOS.
* Dynamic Cast Rework: Runtime
This is a completely refactored version of the core swift_dynamicCast
runtime method.
This fixes a number of bugs, especially in the handling of multiply-wrapped
types such as Optional within Any. The result should be much closer to the
behavior specified by `docs/DynamicCasting.md`.
Most of the type-specific logic is simply copied over from the
earlier implementation, but the overall structure has been changed
to be uniformly recursive. In particular, this provides uniform
handling of Optional, existentials, Any and other common "box"
types along all paths. The consistent structure should also be
easier to update in the future with new general types.
Benchmarking does not show any noticable performance implications.
**Temporarily**, the old implementation is still available. Setting the
environment variable `SWIFT_OLD_DYNAMIC_CAST_RUNTIME` before launching a program
will use the old runtime implementation. This is only to facilitate testing;
once the new implementation is stable, I expect to completely remove the old
implementation.