Files
swift-mirror/test/Interpreter/objc_class_properties.swift
Slava Pestov c1c54d1462 Sema: Fix materializeForSet for members of extensions of imported classes
An assertion I added recently to check property overrides in
the ASTVerifier uncovered some bugs in this area:

- We did not synthesize a materializeForSet for properties
  defined in extensions of imported classes unless they
  witnessed a protocol requirement.

  This triggered an assertion if the property had an
  override that was checked before the protocol conformance,
  since the override's materializeForSet would not be marked
  as an override of the base materializeForSet.

- materializeForSet for properties defined in extensions would
  statically dispatch the getter and setter instead of dynamically
  dispatching. This is incorrect since we statically dispatch
  to the materializeForSet in this case, and we can in fact
  override it in a subclass.

Fixes <rdar://problem/31334272>.
2017-04-02 23:43:41 -07:00

243 lines
5.7 KiB
Swift

// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang %target-cc-options -isysroot %sdk -fobjc-arc %S/Inputs/ObjCClasses/ObjCClasses.m -c -o %t/ObjCClasses.o
// RUN: %target-build-swift -I %S/Inputs/ObjCClasses/ %t/ObjCClasses.o %s -o %t/a.out
// RUN: %target-run %t/a.out
// REQUIRES: executable_test
// REQUIRES: objc_interop
import Foundation
import StdlibUnittest
import ObjCClasses
class SwiftClass : ProtoWithClassProperty {
static var getCount = 0
static var setCount = 0
private static var _value: CInt = 0
@objc class func reset() {
getCount = 0
setCount = 0
_value = 0
}
@objc class var value: CInt {
get {
getCount += 1
return _value
}
set {
setCount += 1
_value = newValue
}
}
@objc class var optionalClassProp: Bool {
return true
}
}
class Subclass : ClassWithClassProperty {
static var getCount = 0
static var setCount = 0
override class func reset() {
getCount = 0
setCount = 0
super.reset()
}
override class var value: CInt {
get {
getCount += 1
return super.value
}
set {
setCount += 1
super.value = newValue
}
}
override class var optionalClassProp: Bool {
return true
}
}
var ClassProperties = TestSuite("ClassProperties")
ClassProperties.test("direct") {
ClassWithClassProperty.reset()
expectEqual(0, ClassWithClassProperty.value)
ClassWithClassProperty.value = 4
expectEqual(4, ClassWithClassProperty.value)
Subclass.reset()
expectEqual(0, Subclass.value)
Subclass.value = 4
expectEqual(4, Subclass.value)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testExistential(_ e: ProtoWithClassProperty.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("existentials") {
testExistential(ClassWithClassProperty.self)
testExistential(ObjCSubclassWithClassProperty.self)
testExistential(SwiftClass.self)
expectEqual(2, SwiftClass.getCount)
expectEqual(1, SwiftClass.setCount)
testExistential(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testGeneric<T: ProtoWithClassProperty>(_ e: T.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("generics") {
testGeneric(ClassWithClassProperty.self)
testGeneric(ObjCSubclassWithClassProperty.self)
testGeneric(SwiftClass.self)
expectEqual(2, SwiftClass.getCount)
expectEqual(1, SwiftClass.setCount)
testGeneric(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testInheritance(_ e: ClassWithClassProperty.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("inheritance") {
testInheritance(ClassWithClassProperty.self)
testInheritance(ObjCSubclassWithClassProperty.self)
testInheritance(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
func testInheritanceGeneric<T: ClassWithClassProperty>(_ e: T.Type) {
e.reset()
expectEqual(0, e.value)
e.value = 4
expectEqual(4, e.value)
}
ClassProperties.test("inheritance/generic") {
testInheritanceGeneric(ClassWithClassProperty.self)
testInheritanceGeneric(ObjCSubclassWithClassProperty.self)
testInheritanceGeneric(Subclass.self)
expectEqual(2, Subclass.getCount)
expectEqual(1, Subclass.setCount)
}
ClassProperties.test("optionalProp") {
let noProp: ProtoWithClassProperty.Type = ClassWithClassProperty.self
expectNil(noProp.optionalClassProp)
let hasProp: ProtoWithClassProperty.Type = Subclass.self
expectNotNil(hasProp.optionalClassProp)
expectEqual(true, hasProp.optionalClassProp!)
let hasOwnProp: ProtoWithClassProperty.Type = SwiftClass.self
expectNotNil(hasOwnProp.optionalClassProp)
expectEqual(true, hasOwnProp.optionalClassProp!)
let hasPropObjC: ProtoWithClassProperty.Type = ObjCSubclassWithClassProperty.self
expectNotNil(hasPropObjC.optionalClassProp)
expectEqual(true, hasPropObjC.optionalClassProp!)
}
class NamingConflictSubclass : PropertyNamingConflict {
override var prop: Any? { return nil }
override class var prop: Any? { return NamingConflictSubclass() }
}
ClassProperties.test("namingConflict") {
let obj = PropertyNamingConflict()
expectTrue(obj === obj.prop.map { $0 as AnyObject })
expectNil(type(of: obj).prop)
expectNil(PropertyNamingConflict.prop)
let sub = NamingConflictSubclass()
expectNil(sub.prop)
expectNotNil(type(of: sub).prop)
expectNotNil(NamingConflictSubclass.prop)
}
extension NamingConflictSubclass : PropertyNamingConflictProto {
var protoProp: Any? {
get { return self }
set {}
}
class var protoProp: Any? {
get { return nil }
set {}
}
}
ClassProperties.test("namingConflict/protocol") {
let obj: PropertyNamingConflictProto = NamingConflictSubclass()
expectTrue(obj === obj.protoProp.map { $0 as AnyObject })
expectNil(type(of: obj).protoProp)
let type: PropertyNamingConflictProto.Type = NamingConflictSubclass.self
expectNil(type.protoProp)
}
var global1: Int = 0
var global2: Int = 0
class Steak : NSObject {
@objc override var thickness: Int {
get { return global1 } set { global1 = newValue }
}
}
extension NSObject : HasThickness {
@objc var thickness: Int { get { return global2 } set { global2 = newValue } }
}
protocol HasThickness : class {
var thickness: Int { get set }
}
ClassProperties.test("dynamicOverride") {
// Calls NSObject.thickness
NSObject().thickness += 1
// Calls Steak.thickness
(Steak() as NSObject).thickness += 1
Steak().thickness += 1
(Steak() as HasThickness).thickness += 1
expectEqual(3, global1)
expectEqual(1, global2)
}
runAllTests()