Files
swift-mirror/test/Casting/ObjCClassConstants.swift
tbkka d92f1d58f8 Dynamic Casting: Properly unwrap existential metatype sources (#34469)
* 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.
2020-10-29 14:46:10 -07:00

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()