aboutsummaryrefslogtreecommitdiff
path: root/test/SemaObjC/block-type-safety.m
blob: 96c781b6a561cae9ef82e06d0de4879195349303 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -Wno-objc-root-class %s
// test for block type safety.

@interface Super  @end
@interface Sub : Super @end

void f2(void(^f)(Super *)) { // expected-note{{passing argument to parameter 'f' here}}
    Super *o;
    f(o);
}

void f3(void(^f)(Sub *)) {
    Sub *o;
    f(o);
}

void r0(Super* (^f)()) {
     Super *o = f();
}

void r1(Sub* (^f)()) { // expected-note{{passing argument to parameter 'f' here}}
    Sub *o = f();
}

@protocol NSObject;
@class NSObject;

void r2 (id<NSObject> (^f) (void)) {
  id o = f();
}

void test1() {
    f2(^(Sub *o) { });    // expected-error {{incompatible block pointer types passing}}
    f3(^(Super *o) { });  // OK, block taking Super* may be called with a Sub*

    r0(^Super* () { return 0; });  // OK
    r0(^Sub* () { return 0; });    // OK, variable of type Super* gets return value of type Sub*
    r0(^id () { return 0; });

    r1(^Super* () { return 0; });  // expected-error {{incompatible block pointer types passing}}
    r1(^Sub* () { return 0; });    // OK
    r1(^id () { return 0; }); 
     
    r2(^id<NSObject>() { return 0; });
}


@interface A @end
@interface B @end

void f0(void (^f)(A* x)) {
  A* a;
  f(a);
}

void f1(void (^f)(id x)) {
  B *b;
  f(b);
}

void test2(void) 
{ 
  f0(^(id a) { }); // OK
  f1(^(A* a) { });
   f1(^(id<NSObject> a) { });	// OK
}

@interface NSArray
   // Calls block() with every object in the array
   -enumerateObjectsWithBlock:(void (^)(id obj))block;
@end

@interface MyThing
-(void) printThing;
@end

@implementation MyThing
    static NSArray* myThings;  // array of MyThing*

   -(void) printThing {  }

// programmer wants to write this:
   -printMyThings1 {
       [myThings enumerateObjectsWithBlock: ^(MyThing *obj) {
           [obj printThing];
       }];
   }

// strict type safety requires this:
   -printMyThings {
       [myThings enumerateObjectsWithBlock: ^(id obj) {
           MyThing *obj2 = (MyThing *)obj;
           [obj2 printThing];
       }];
   }
@end

@protocol P, P2;
void f4(void (^f)(id<P> x)) { // expected-note{{passing argument to parameter 'f' here}}
    NSArray<P2> *b;
    f(b);	// expected-warning {{passing 'NSArray<P2> *' to parameter of incompatible type 'id<P>'}}
}

void test3() {
  f4(^(NSArray<P2>* a) { });  // expected-error {{incompatible block pointer types passing 'void (^)(NSArray<P2> *)' to parameter of type 'void (^)(id<P>)'}}
}

// rdar : //8302845
@protocol Foo @end

@interface Baz @end

@interface Baz(FooConformance) <Foo>
@end

@implementation Baz @end

int test4 () {
    id <Foo> (^b)() = ^{ // Doesn't work
        return (Baz *)0;
    };
    return 0;
}

// rdar:// 9118343

@protocol NSCopying @end

@interface NSAllArray <NSCopying>
@end

@interface NSAllArray (FooConformance) <Foo>
@end

int test5() {
    NSAllArray *(^block)(id);
    id <Foo> (^genericBlock)(id);
    genericBlock = block;
    return 0;
}

// rdar://10798770
typedef int NSInteger;

typedef enum : NSInteger {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending} NSComparisonResult;

typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);

@interface radar10798770
- (void)sortUsingComparator:(NSComparator)c;
@end

void f() {
   radar10798770 *f;
   [f sortUsingComparator:^(id a, id b) {
        return NSOrderedSame;
   }];
}

// rdar://16739120
@protocol P1 @end
@protocol P2 @end

void Test() {
void (^aBlock)();
id anId = aBlock;  // OK

id<P1,P2> anQualId = aBlock;  // expected-error {{initializing 'id<P1,P2>' with an expression of incompatible type 'void (^)()'}}

NSArray* anArray = aBlock; // expected-error {{initializing 'NSArray *' with an expression of incompatible type 'void (^)()'}}

aBlock = anId; // OK

id<P1,P2> anQualId1;
aBlock = anQualId1; // expected-error {{assigning to 'void (^)()' from incompatible type 'id<P1,P2>'}}

NSArray* anArray1;
aBlock = anArray1; // expected-error {{assigning to 'void (^)()' from incompatible type 'NSArray *'}}
}

void Test2() {
  void (^aBlock)();
  id<NSObject> anQualId1 = aBlock; // Ok
  id<NSObject, NSCopying> anQualId2 = aBlock; // Ok
  id<NSObject, NSCopying, NSObject, NSCopying> anQualId3 = aBlock; // Ok
  id <P1>  anQualId4  = aBlock; // expected-error {{initializing 'id<P1>' with an expression of incompatible type 'void (^)()'}}
  id<NSObject, P1, NSCopying> anQualId5 = aBlock; // expected-error {{initializing 'id<NSObject,P1,NSCopying>' with an expression of incompatible type 'void (^)()'}}
  id<NSCopying> anQualId6 = aBlock; // Ok
}

void Test3() {
  void (^aBlock)();
  NSObject *NSO = aBlock; // Ok
  NSObject<NSObject> *NSO1 = aBlock; // Ok
  NSObject<NSObject, NSCopying> *NSO2 = aBlock; // Ok
  NSObject<NSObject, NSCopying, NSObject, NSCopying> *NSO3 = aBlock; // Ok
  NSObject <P1>  *NSO4  = aBlock; // expected-error {{initializing 'NSObject<P1> *' with an expression of incompatible type 'void (^)()'}}
  NSObject<NSObject, P1, NSCopying> *NSO5 = aBlock; // expected-error {{initializing 'NSObject<NSObject,P1,NSCopying> *' with an expression of incompatible type 'void (^)()'}}
  NSObject<NSCopying> *NSO6 = aBlock; // Ok
}

// rdar://problem/19420731
typedef NSObject<P1> NSObject_P1;
typedef NSObject_P1<P2> NSObject_P1_P2;

void Test4(void (^handler)(NSObject_P1_P2 *p)) {
  Test4(^(NSObject<P2> *p) { });
}