Skip to content

Commit be3249d

Browse files
authored
[Sema] Reject @objc functions with incompatible property wrapper in… (#61189)
* [Sema] Reject `@objc` functions with incompatible property wrapper in params rdar://99443365 When generating `@objc` functions, the parameters were not checked for property wrapper and instead only the wrapped type was checked for compatibility. Added checks and diagnostics for incompatible property wrappers.
1 parent e458b53 commit be3249d

File tree

5 files changed

+129
-6
lines changed

5 files changed

+129
-6
lines changed

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ static void diagnoseTypeNotRepresentableInObjC(const DeclContext *DC,
182182
}
183183

184184
// Special diagnostic for structs.
185-
if (T->is<StructType>()) {
185+
if (auto *SD = T->getStructOrBoundGenericStruct()) {
186186
diags.diagnose(TypeRange.Start, diag::not_objc_swift_struct)
187187
.highlight(TypeRange)
188188
.limitBehavior(behavior);
@@ -291,9 +291,16 @@ static void diagnoseFunctionParamNotRepresentable(
291291
.limitBehavior(behavior));
292292
}
293293
SourceRange SR;
294-
if (auto typeRepr = P->getTypeRepr())
295-
SR = typeRepr->getSourceRange();
296-
diagnoseTypeNotRepresentableInObjC(AFD, P->getType(), SR, behavior);
294+
295+
if (P->hasAttachedPropertyWrapper()) {
296+
auto wrapperTy = P->getPropertyWrapperBackingPropertyType();
297+
SR = P->getOutermostAttachedPropertyWrapper()->getRange();
298+
diagnoseTypeNotRepresentableInObjC(AFD, wrapperTy, SR, behavior);
299+
} else {
300+
if (auto typeRepr = P->getTypeRepr())
301+
SR = typeRepr->getSourceRange();
302+
diagnoseTypeNotRepresentableInObjC(AFD, P->getType(), SR, behavior);
303+
}
297304
Reason.describe(AFD);
298305
}
299306

@@ -335,11 +342,17 @@ static bool isParamListRepresentableInObjC(const AbstractFunctionDecl *AFD,
335342

336343
if (param->getType()->hasError())
337344
return false;
338-
339-
if (param->getType()->isRepresentableIn(
345+
346+
if (param->hasAttachedPropertyWrapper()) {
347+
if (param->getPropertyWrapperBackingPropertyType()->isRepresentableIn(
340348
ForeignLanguage::ObjectiveC,
341349
const_cast<AbstractFunctionDecl *>(AFD)))
350+
continue;
351+
} else if (param->getType()->isRepresentableIn(
352+
ForeignLanguage::ObjectiveC,
353+
const_cast<AbstractFunctionDecl *>(AFD))) {
342354
continue;
355+
}
343356

344357
// Permit '()' when this method overrides a method with a
345358
// foreign error convention that replaces NSErrorPointer with ()

test/ClangImporter/objc_parse.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,9 +645,12 @@ class NewtypeUser {
645645
@objc func intNewtype(a: MyInt) {}
646646
@objc func intNewtypeOptional(a: MyInt?) {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
647647
@objc func intNewtypeArray(a: [MyInt]) {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
648+
// expected-note@-1 {{Swift structs cannot be represented in Objective-C}}
648649
@objc func intNewtypeDictionary(a: [MyInt: NSObject]) {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
650+
// expected-note@-1 {{Swift structs cannot be represented in Objective-C}}
649651
@objc func cfNewtype(a: CFNewType) {}
650652
@objc func cfNewtypeArray(a: [CFNewType]) {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
653+
// expected-note@-1 {{Swift structs cannot be represented in Objective-C}}
651654

652655
typealias MyTuple = (Int, AnyObject?)
653656
typealias MyNamedTuple = (a: Int, b: AnyObject?)
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// RUN: %target-swift-frontend -typecheck -verify -enable-objc-interop %s
2+
3+
// REQUIRES: objc_interop
4+
5+
import Foundation
6+
7+
class ObjcClassCase {
8+
@objc
9+
func foo(@WrapperObjcClass _ ref: Int) throws {}
10+
}
11+
12+
@propertyWrapper @objc
13+
public class WrapperObjcClass: NSObject {
14+
public var wrappedValue: Int
15+
16+
public init(wrappedValue: Int) {
17+
self.wrappedValue = wrappedValue
18+
}
19+
20+
public init(projectedValue: WrapperObjcClass) {
21+
fatalError()
22+
}
23+
24+
public var projectedValue: WrapperObjcClass {
25+
fatalError()
26+
}
27+
}
28+
29+
class GenericClassCase {
30+
@objc
31+
func foo(@WrapperGenericClass _ ref: Int) throws {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
32+
// expected-note@-1 {{classes not annotated with @objc cannot be represented in Objective-C}}
33+
}
34+
35+
@propertyWrapper
36+
public class WrapperGenericClass<Element> {
37+
public var wrappedValue: Element
38+
39+
public init(wrappedValue: Element) {
40+
self.wrappedValue = wrappedValue
41+
}
42+
43+
public init(projectedValue: WrapperGenericClass<Element>) {
44+
fatalError()
45+
}
46+
47+
public var projectedValue: WrapperGenericClass<Element> {
48+
fatalError()
49+
}
50+
}
51+
52+
class StructCase {
53+
@objc
54+
func foo(@WrapperStruct _ ref: Int) throws {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
55+
// expected-note@-1 {{Swift structs cannot be represented in Objective-C}}
56+
}
57+
58+
@propertyWrapper
59+
public struct WrapperStruct {
60+
public var wrappedValue: Int
61+
62+
public init(wrappedValue: Int) {
63+
self.wrappedValue = wrappedValue
64+
}
65+
66+
public init(projectedValue: WrapperStruct) {
67+
fatalError()
68+
}
69+
70+
public var projectedValue: WrapperStruct {
71+
fatalError()
72+
}
73+
}
74+
75+
class EnumCase {
76+
@objc
77+
func foo(@WrapperEnum _ ref: Int) throws {} // expected-error {{method cannot be marked @objc because the type of the parameter cannot be represented in Objective-C}}
78+
// expected-note@-1 {{non-'@objc' enums cannot be represented in Objective-C}}
79+
}
80+
81+
@propertyWrapper
82+
public enum WrapperEnum {
83+
public var wrappedValue: Int {
84+
fatalError()
85+
}
86+
87+
public init(wrappedValue: Int) {
88+
}
89+
90+
public init(projectedValue: WrapperStruct) {
91+
fatalError()
92+
}
93+
94+
public var projectedValue: WrapperStruct {
95+
fatalError()
96+
}
97+
}

test/attr/attr_objc.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,13 +1556,15 @@ class infer_instanceVar1 {
15561556
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType3_}}
15571557
var var_ArrayType3_: [PlainStruct]
15581558
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1559+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
15591560

15601561
var var_ArrayType4: [(AnyObject) -> AnyObject] // no-error
15611562
// CHECK-LABEL: {{^}} var var_ArrayType4: [(AnyObject) -> AnyObject]
15621563

15631564
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType4_}}
15641565
var var_ArrayType4_: [(AnyObject) -> AnyObject]
15651566
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1567+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
15661568

15671569
var var_ArrayType5: [Protocol_ObjC1]
15681570
// CHECK-LABEL: {{^}} @objc var var_ArrayType5: [Protocol_ObjC1]
@@ -1582,20 +1584,23 @@ class infer_instanceVar1 {
15821584
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType7_}}
15831585
var var_ArrayType7_: [PlainClass]
15841586
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1587+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
15851588

15861589
var var_ArrayType8: [PlainProtocol]
15871590
// CHECK-LABEL: {{^}} var var_ArrayType8: [PlainProtocol]
15881591

15891592
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType8_}}
15901593
var var_ArrayType8_: [PlainProtocol]
15911594
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1595+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
15921596

15931597
var var_ArrayType9: [Protocol_ObjC1 & PlainProtocol]
15941598
// CHECK-LABEL: {{^}} var var_ArrayType9: [PlainProtocol & Protocol_ObjC1]
15951599

15961600
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType9_}}
15971601
var var_ArrayType9_: [Protocol_ObjC1 & PlainProtocol]
15981602
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1603+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
15991604

16001605
var var_ArrayType10: [Protocol_ObjC1 & Protocol_ObjC2]
16011606
// CHECK-LABEL: {{^}} @objc var var_ArrayType10: [Protocol_ObjC1 & Protocol_ObjC2]
@@ -1616,13 +1621,15 @@ class infer_instanceVar1 {
16161621
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType13_}}
16171622
var var_ArrayType13_: [Any?]
16181623
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1624+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
16191625

16201626
var var_ArrayType15: [AnyObject?]
16211627
// CHECK-LABEL: {{^}} var var_ArrayType15: [AnyObject?]
16221628

16231629
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType15_}}
16241630
var var_ArrayType15_: [AnyObject?]
16251631
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1632+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
16261633

16271634
var var_ArrayType16: [[@convention(block) (AnyObject) -> AnyObject]] // no-error
16281635
// CHECK-LABEL: {{^}} @objc var var_ArrayType16: {{\[}}[@convention(block) (AnyObject) -> AnyObject]]
@@ -1636,6 +1643,7 @@ class infer_instanceVar1 {
16361643
@objc // bad-access-note-move{{infer_instanceVar1.var_ArrayType17_}}
16371644
var var_ArrayType17_: [[(AnyObject) -> AnyObject]]
16381645
// access-note-adjust{{@objc}} expected-error @-1{{property cannot be marked @objc because its type cannot be represented in Objective-C}}
1646+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
16391647
}
16401648

16411649
@objc // access-note-move{{ObjCBase}}
@@ -2649,6 +2657,7 @@ protocol issue51538_P {
26492657
func throwingMethod1() throws -> Unmanaged<CFArray> // Ok
26502658
func throwingMethod2() throws -> Unmanaged<issue51538_C> // expected-error {{method cannot be a member of an @objc protocol because its result type cannot be represented in Objective-C}}
26512659
// expected-note@-1 {{inferring '@objc' because the declaration is a member of an '@objc' protocol}}
2660+
// expected-note@-2 {{Swift structs cannot be represented in Objective-C}}
26522661
}
26532662

26542663
// https://github.com/apple/swift/issues/55246

test/attr/attr_objc_any.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Foo: NSObject {
1313
@objc func method(x: Any) -> Any { return x }
1414

1515
@objc func indirectAny(x: UnsafePointer<Any>) {} // expected-error{{type of the parameter cannot be represented in Objective-C}}
16+
// expected-note@-1 {{Swift structs cannot be represented in Objective-C}}
1617

1718
@objc func throwingMethod(x: Any) throws -> Any { return x }
1819

0 commit comments

Comments
 (0)