1 | // RUN: %clang_cc1 -fblocks -fsyntax-only -std=c++11 %s -verify |
2 | // |
3 | // Test the substitution of type arguments for type parameters when |
4 | // using parameterized classes in Objective-C. |
5 | |
6 | __attribute__((objc_root_class)) |
7 | @interface NSObject |
8 | + (instancetype)alloc; |
9 | - (instancetype)init; |
10 | @end |
11 | |
12 | @protocol NSCopying |
13 | @end |
14 | |
15 | @interface NSString : NSObject <NSCopying> |
16 | @end |
17 | |
18 | @interface NSMutableString : NSString |
19 | @end |
20 | |
21 | @interface NSNumber : NSObject <NSCopying> |
22 | @end |
23 | |
24 | @interface NSArray<T> : NSObject <NSCopying> { |
25 | @public |
26 | T *data; // don't try this at home |
27 | } |
28 | - (T)objectAtIndexedSubscript:(int)index; |
29 | + (NSArray<T> *)array; |
30 | @property (copy,nonatomic) T lastObject; |
31 | @end |
32 | |
33 | @interface NSMutableArray<T> : NSArray<T> |
34 | -(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}} |
35 | - (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}} |
36 | @end |
37 | |
38 | @interface NSStringArray : NSArray<NSString *> |
39 | @end |
40 | |
41 | @interface NSSet<T> : NSObject <NSCopying> |
42 | - (T)firstObject; |
43 | @property (nonatomic, copy) NSArray<T> *allObjects; |
44 | @end |
45 | |
46 | // Parameterized inheritance (simple case) |
47 | @interface NSMutableSet<U : id<NSCopying>> : NSSet<U> |
48 | - (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}} |
49 | @end |
50 | |
51 | @interface Widget : NSObject <NSCopying> |
52 | @end |
53 | |
54 | // Non-parameterized class inheriting from a specialization of a |
55 | // parameterized class. |
56 | @interface WidgetSet : NSMutableSet<Widget *> |
57 | @end |
58 | |
59 | // Parameterized inheritance with a more interesting transformation in |
60 | // the specialization. |
61 | @interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*> |
62 | @end |
63 | |
64 | // Inheriting from an unspecialized form of a parameterized type. |
65 | @interface UntypedMutableSet : NSMutableSet |
66 | @end |
67 | |
68 | @interface Window : NSObject |
69 | @end |
70 | |
71 | @interface NSDictionary<K, V> : NSObject <NSCopying> |
72 | - (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}} |
73 | @end |
74 | |
75 | @interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> // expected-note 2{{type parameter 'K' declared here}} \ |
76 | // expected-note 2{{'NSMutableDictionary' declared here}} |
77 | - (void)setObject:(V)object forKeyedSubscript:(K)key; |
78 | // expected-note@-1 {{parameter 'object' here}} |
79 | // expected-note@-2 {{parameter 'object' here}} |
80 | // expected-note@-3 {{parameter 'key' here}} |
81 | // expected-note@-4 {{parameter 'key' here}} |
82 | |
83 | @property (strong) K someRandomKey; |
84 | @end |
85 | |
86 | @interface WindowArray : NSArray<Window *> |
87 | @end |
88 | |
89 | @interface NSSet<T> (Searching) |
90 | - (T)findObject:(T)object; |
91 | @end |
92 | |
93 | |
94 | // -------------------------------------------------------------------------- |
95 | // Message sends. |
96 | // -------------------------------------------------------------------------- |
97 | void test_message_send_result( |
98 | NSSet<NSString *> *stringSet, |
99 | NSMutableSet<NSString *> *mutStringSet, |
100 | WidgetSet *widgetSet, |
101 | UntypedMutableSet *untypedMutSet, |
102 | MutableSetOfArrays<NSString *> *mutStringArraySet, |
103 | NSSet *set, |
104 | NSMutableSet *mutSet, |
105 | MutableSetOfArrays *mutArraySet, |
106 | NSArray<NSString *> *stringArray, |
107 | void (^block)(void)) { |
108 | int *ip; |
109 | ip = [stringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}} |
110 | ip = [mutStringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}} |
111 | ip = [widgetSet firstObject]; // expected-error{{from incompatible type 'Widget *'}} |
112 | ip = [untypedMutSet firstObject]; // expected-error{{from incompatible type 'id'}} |
113 | ip = [mutStringArraySet firstObject]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
114 | ip = [set firstObject]; // expected-error{{from incompatible type 'id'}} |
115 | ip = [mutSet firstObject]; // expected-error{{from incompatible type 'id'}} |
116 | ip = [mutArraySet firstObject]; // expected-error{{from incompatible type 'id'}} |
117 | ip = [block firstObject]; // expected-error{{from incompatible type 'id'}} |
118 | |
119 | ip = [stringSet findObject:@"blah"]; // expected-error{{from incompatible type 'NSString *'}} |
120 | |
121 | // Class messages. |
122 | ip = [NSSet<NSString *> alloc]; // expected-error{{from incompatible type 'NSSet<NSString *> *'}} |
123 | ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}} |
124 | ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays<NSString *> *'}} |
125 | ip = [MutableSetOfArrays alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays *'}} |
126 | ip = [NSArray<NSString *> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
127 | ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
128 | |
129 | ip = [[NSMutableArray<NSString *> alloc] init]; // expected-error{{from incompatible type 'NSMutableArray<NSString *> *'}} |
130 | |
131 | [[NSMutableArray alloc] initWithArray: stringArray]; // okay |
132 | [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay |
133 | [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray<NSNumber *> *' with an lvalue of type 'NSArray<NSString *> *'}} |
134 | } |
135 | |
136 | void test_message_send_param( |
137 | NSMutableSet<NSString *> *mutStringSet, |
138 | WidgetSet *widgetSet, |
139 | UntypedMutableSet *untypedMutSet, |
140 | MutableSetOfArrays<NSString *> *mutStringArraySet, |
141 | NSMutableSet *mutSet, |
142 | MutableSetOfArrays *mutArraySet, |
143 | void (^block)(void)) { |
144 | Window *window; |
145 | |
146 | [mutStringSet addObject: window]; // expected-error{{parameter of type 'NSString *'}} |
147 | [widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}} |
148 | [untypedMutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} |
149 | [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}} |
150 | [mutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} |
151 | [mutArraySet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} |
152 | [block addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}} |
153 | } |
154 | |
155 | // -------------------------------------------------------------------------- |
156 | // Property accesses. |
157 | // -------------------------------------------------------------------------- |
158 | void test_property_read( |
159 | NSSet<NSString *> *stringSet, |
160 | NSMutableSet<NSString *> *mutStringSet, |
161 | WidgetSet *widgetSet, |
162 | UntypedMutableSet *untypedMutSet, |
163 | MutableSetOfArrays<NSString *> *mutStringArraySet, |
164 | NSSet *set, |
165 | NSMutableSet *mutSet, |
166 | MutableSetOfArrays *mutArraySet, |
167 | NSMutableDictionary *mutDict) { |
168 | int *ip; |
169 | ip = stringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
170 | ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
171 | ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray<Widget *> *'}} |
172 | ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} |
173 | ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray<NSArray<NSString *> *> *'}} |
174 | ip = set.allObjects; // expected-error{{from incompatible type 'NSArray *'}} |
175 | ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} |
176 | ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}} |
177 | |
178 | ip = mutDict.someRandomKey; // expected-error{{from incompatible type '__kindof id<NSCopying>'}} |
179 | } |
180 | |
181 | void test_property_write( |
182 | NSMutableSet<NSString *> *mutStringSet, |
183 | WidgetSet *widgetSet, |
184 | UntypedMutableSet *untypedMutSet, |
185 | MutableSetOfArrays<NSString *> *mutStringArraySet, |
186 | NSMutableSet *mutSet, |
187 | MutableSetOfArrays *mutArraySet, |
188 | NSMutableDictionary *mutDict) { |
189 | int *ip; |
190 | |
191 | mutStringSet.allObjects = ip; // expected-error{{to 'NSArray<NSString *> *'}} |
192 | widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}} |
193 | untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}} |
194 | mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}} |
195 | mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}} |
196 | mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}} |
197 | |
198 | mutDict.someRandomKey = ip; // expected-error{{to 'id<NSCopying>'}} |
199 | } |
200 | |
201 | // -------------------------------------------------------------------------- |
202 | // Subscripting |
203 | // -------------------------------------------------------------------------- |
204 | void test_subscripting( |
205 | NSArray<NSString *> *stringArray, |
206 | NSMutableArray<NSString *> *mutStringArray, |
207 | NSArray *array, |
208 | NSMutableArray *mutArray, |
209 | NSDictionary<NSString *, Widget *> *stringWidgetDict, |
210 | NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict, |
211 | NSDictionary *dict, |
212 | NSMutableDictionary *mutDict) { |
213 | int *ip; |
214 | NSString *string; |
215 | Widget *widget; |
216 | Window *window; |
217 | |
218 | ip = stringArray[0]; // expected-error{{from incompatible type 'NSString *'}} |
219 | |
220 | ip = mutStringArray[0]; // expected-error{{from incompatible type 'NSString *'}} |
221 | mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}} |
222 | |
223 | ip = array[0]; // expected-error{{from incompatible type 'id'}} |
224 | |
225 | ip = mutArray[0]; // expected-error{{from incompatible type 'id'}} |
226 | mutArray[0] = ip; // expected-error{{parameter of type 'id'}} |
227 | |
228 | ip = stringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}} |
229 | widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}} |
230 | |
231 | ip = mutStringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}} |
232 | widget = mutStringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}} |
233 | mutStringWidgetDict[string] = ip; // expected-error{{parameter of type 'Widget *'}} |
234 | mutStringWidgetDict[widget] = widget; // expected-error{{parameter of type 'NSString *'}} |
235 | |
236 | ip = dict[string]; // expected-error{{from incompatible type 'id'}} |
237 | |
238 | ip = mutDict[string]; // expected-error{{incompatible type 'id'}} |
239 | mutDict[string] = ip; // expected-error{{parameter of type 'id'}} |
240 | |
241 | widget = mutDict[window]; |
242 | mutDict[window] = widget; // expected-error{{parameter of type 'id<NSCopying>'}} |
243 | } |
244 | |
245 | // -------------------------------------------------------------------------- |
246 | // Instance variable access. |
247 | // -------------------------------------------------------------------------- |
248 | void test_instance_variable(NSArray<NSString *> *stringArray, |
249 | NSArray *array) { |
250 | int *ip; |
251 | |
252 | ip = stringArray->data; // expected-error{{from incompatible type 'NSString **'}} |
253 | ip = array->data; // expected-error{{from incompatible type 'id *'}} |
254 | } |
255 | |
256 | @implementation WindowArray |
257 | - (void)testInstanceVariable { |
258 | int *ip; |
259 | |
260 | ip = data; // expected-error{{from incompatible type 'Window **'}} |
261 | } |
262 | @end |
263 | |
264 | // -------------------------------------------------------------------------- |
265 | // Implicit conversions. |
266 | // -------------------------------------------------------------------------- |
267 | void test_implicit_conversions(NSArray<NSString *> *stringArray, |
268 | NSArray<NSNumber *> *numberArray, |
269 | NSMutableArray<NSString *> *mutStringArray, |
270 | NSArray *array, |
271 | NSMutableArray *mutArray) { |
272 | // Specialized -> unspecialized (same level) |
273 | array = stringArray; |
274 | |
275 | // Unspecialized -> specialized (same level) |
276 | stringArray = array; |
277 | |
278 | // Specialized -> specialized failure (same level). |
279 | stringArray = numberArray; // expected-error{{assigning to 'NSArray<NSString *> *' from incompatible type 'NSArray<NSNumber *> *'}} |
280 | |
281 | // Specialized -> specialized (different levels). |
282 | stringArray = mutStringArray; |
283 | |
284 | // Specialized -> specialized failure (different levels). |
285 | numberArray = mutStringArray; // expected-error{{assigning to 'NSArray<NSNumber *> *' from incompatible type 'NSMutableArray<NSString *> *'}} |
286 | |
287 | // Unspecialized -> specialized (different levels). |
288 | stringArray = mutArray; |
289 | |
290 | // Specialized -> unspecialized (different levels). |
291 | array = mutStringArray; |
292 | } |
293 | |
294 | @interface NSCovariant1<__covariant T> |
295 | @end |
296 | |
297 | @interface NSContravariant1<__contravariant T> |
298 | @end |
299 | |
300 | void test_variance(NSCovariant1<NSString *> *covariant1, |
301 | NSCovariant1<NSMutableString *> *covariant2, |
302 | NSCovariant1<NSString *(^)(void)> *covariant3, |
303 | NSCovariant1<NSMutableString *(^)(void)> *covariant4, |
304 | NSCovariant1<id> *covariant5, |
305 | NSCovariant1<id<NSCopying>> *covariant6, |
306 | NSContravariant1<NSString *> *contravariant1, |
307 | NSContravariant1<NSMutableString *> *contravariant2) { |
308 | covariant1 = covariant2; // okay |
309 | covariant2 = covariant1; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}} |
310 | |
311 | covariant3 = covariant4; // okay |
312 | covariant4 = covariant3; // expected-warning{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)()> *' from 'NSCovariant1<NSString *(^)()> *'}} |
313 | |
314 | covariant5 = covariant1; // okay |
315 | covariant1 = covariant5; // okay: id is promiscuous |
316 | |
317 | covariant5 = covariant3; // okay |
318 | covariant3 = covariant5; // okay |
319 | |
320 | contravariant1 = contravariant2; // expected-warning{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}} |
321 | contravariant2 = contravariant1; // okay |
322 | } |
323 | |
324 | // -------------------------------------------------------------------------- |
325 | // Ternary operator |
326 | // -------------------------------------------------------------------------- |
327 | void test_ternary_operator(NSArray<NSString *> *stringArray, |
328 | NSArray<NSNumber *> *numberArray, |
329 | NSMutableArray<NSString *> *mutStringArray, |
330 | NSStringArray *stringArray2, |
331 | NSArray *array, |
332 | NSMutableArray *mutArray, |
333 | int cond) { |
334 | int *ip; |
335 | id object; |
336 | |
337 | ip = cond ? stringArray : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
338 | ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
339 | |
340 | ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
341 | ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
342 | |
343 | ip = cond ? stringArray : mutArray; // expected-error{{from incompatible type 'NSArray *'}} |
344 | |
345 | ip = cond ? stringArray2 : mutArray; // expected-error{{from incompatible type 'NSArray *'}} |
346 | |
347 | ip = cond ? mutArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}} |
348 | |
349 | ip = cond ? mutArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}} |
350 | |
351 | object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}} |
352 | } |
353 | |
354 | // -------------------------------------------------------------------------- |
355 | // super |
356 | // -------------------------------------------------------------------------- |
357 | @implementation NSStringArray |
358 | - (void)useSuperMethod { |
359 | int *ip; |
360 | ip = super.lastObject; // expected-error{{from incompatible type 'NSString *'}} |
361 | ip = [super objectAtIndexedSubscript:0]; // expected-error{{from incompatible type 'NSString *'}} |
362 | } |
363 | |
364 | + (void)useSuperMethod { |
365 | int *ip; |
366 | ip = super.array; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
367 | ip = [super array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}} |
368 | } |
369 | @end |
370 | |
371 | // -------------------------------------------------------------------------- |
372 | // Template instantiation |
373 | // -------------------------------------------------------------------------- |
374 | template<typename K, typename V> |
375 | struct NSMutableDictionaryOf { |
376 | typedef NSMutableDictionary<K, V> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}} |
377 | }; |
378 | |
379 | template<typename ...Args> |
380 | struct VariadicNSMutableDictionaryOf { |
381 | typedef NSMutableDictionary<Args...> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}} |
382 | // expected-error@-1{{too many type arguments for class 'NSMutableDictionary' (have 3, expected 2)}} |
383 | // expected-error@-2{{too few type arguments for class 'NSMutableDictionary' (have 1, expected 2)}} |
384 | }; |
385 | |
386 | void testInstantiation() { |
387 | int *ip; |
388 | |
389 | typedef NSMutableDictionaryOf<NSString *, NSObject *>::type Dict1; |
390 | Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}} |
391 | |
392 | typedef NSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}} |
393 | } |
394 | |
395 | void testVariadicInstantiation() { |
396 | int *ip; |
397 | |
398 | typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *>::type Dict1; |
399 | Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}} |
400 | |
401 | typedef VariadicNSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}} |
402 | |
403 | typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *, NSObject *>::type Dict3; // expected-note{{in instantiation of template}} |
404 | |
405 | typedef VariadicNSMutableDictionaryOf<NSString *>::type Dict3; // expected-note{{in instantiation of template}} |
406 | } |
407 | |
408 | // -------------------------------------------------------------------------- |
409 | // Parameterized classes are not templates |
410 | // -------------------------------------------------------------------------- |
411 | template<template<typename T, typename U> class TT> |
412 | struct AcceptsTemplateTemplate { }; |
413 | |
414 | typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}} |
415 | |
416 | template<typename T> |
417 | struct DependentTemplate { |
418 | typedef typename T::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}} |
419 | }; |
420 | |
421 | struct NSMutableDictionaryBuilder { |
422 | typedef NSMutableDictionary apply; // expected-note 2{{declared as a non-template here}} |
423 | }; |
424 | |
425 | typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}} |
426 | |
427 | template<typename K, typename V> |
428 | struct NonDependentTemplate { |
429 | typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}} |
430 | // expected-error@-1{{expected member name or }} |
431 | }; |
432 | |
433 | // However, one can use an alias template to turn a parameterized |
434 | // class into a template. |
435 | template<typename K, typename V> |
436 | using NSMutableDictionaryAlias = NSMutableDictionary<K, V>; |
437 | |
438 | typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay |
439 | |
440 | |
441 | |