mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
* 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.
81 lines
2.7 KiB
Swift
81 lines
2.7 KiB
Swift
// ObjCClassConstants.swift - Tests for class constant casts w/ Obj-C
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
// -----------------------------------------------------------------------------
|
|
///
|
|
/// Contains tests for non-trapping type conversions reported by users.
|
|
///
|
|
// -----------------------------------------------------------------------------
|
|
// RUN: %empty-directory(%t)
|
|
//
|
|
// RUN: %target-clang -fmodules -c %S/Inputs/ObjCClassConstants/ObjCClassConstants.m -o %t/ObjCClassConstants.objc.o
|
|
//
|
|
// RUN: %target-build-swift -swift-version 5 -g -Onone -module-name a -I %S/Inputs/ObjCClassConstants -c %s -o %t/ObjCClassConstants.swift.Onone.o
|
|
// RUN: %target-swiftc_driver %t/ObjCClassConstants.objc.o %t/ObjCClassConstants.swift.Onone.o -o %t/a.swift5.Onone.out
|
|
// RUN: %target-codesign %t/a.swift5.Onone.out
|
|
// RUN: %target-run %t/a.swift5.Onone.out
|
|
//
|
|
// RUN: %target-build-swift -swift-version 5 -g -O -module-name a -I %S/Inputs/ObjCClassConstants -c %s -o %t/ObjCClassConstants.swift.O.o
|
|
// RUN: %target-swiftc_driver %t/ObjCClassConstants.objc.o %t/ObjCClassConstants.swift.O.o -o %t/a.swift5.O.out
|
|
// RUN: %target-codesign %t/a.swift5.O.out
|
|
// RUN: %target-run %t/a.swift5.O.out
|
|
//
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: objc_interop
|
|
// UNSUPPORTED: use_os_stdlib
|
|
|
|
import Foundation
|
|
import ObjCClassConstants
|
|
import Swift
|
|
|
|
import StdlibUnittest
|
|
|
|
let tests = TestSuite("ObjCClassConstants")
|
|
|
|
tests.test("ObjC and Swift type lookups should agree") {
|
|
// Look up class object from Obj-C (in an array)
|
|
// Extract first element, then cast to AnyObject
|
|
let a = OCClassConstants.classes
|
|
let b = a[0]
|
|
let c = b as? AnyObject
|
|
expectNotNil(c)
|
|
let d = c!
|
|
|
|
// Look up class object from Swift, cast to AnyObject
|
|
let e = OCClassConstants.self
|
|
let f = e as? AnyObject
|
|
expectNotNil(f)
|
|
let g = f!
|
|
|
|
// Should be exact same pointer
|
|
expectTrue(d === g)
|
|
}
|
|
|
|
tests.test("ObjC and Swift type lookups should agree (with array cast to AnyObject)") {
|
|
// Look up class object from Obj-C (in an array)
|
|
// Cast array to AnyObject, then extract first element
|
|
let a = OCClassConstants.classes
|
|
let b = a as? [AnyObject]
|
|
expectNotNil(b)
|
|
let c = b!
|
|
let d = c[0]
|
|
|
|
// Look up class object from Swift, cast to AnyObject
|
|
let e = OCClassConstants.self
|
|
let f = e as? AnyObject
|
|
expectNotNil(f)
|
|
let g = f!
|
|
|
|
// Should be exact same pointer
|
|
expectTrue(d === g)
|
|
}
|
|
|
|
runAllTests()
|