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// --------------------------------------------------------------------------
97void 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{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
110  ip = [mutStringSet firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
111  ip = [widgetSet firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'Widget *'}}
112  ip = [untypedMutSet firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
113  ip = [mutStringArraySet firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
114  ip = [set firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
115  ip = [mutSet firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
116  ip = [mutArraySet firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
117  ip = [block firstObject]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
118
119  ip = [stringSet findObject:@"blah"]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
120
121  // Class messages.
122  ip = [NSSet<NSString *> alloc]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSSet<NSString *> *'}}
123  ip = [NSSet alloc]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSSet *'}}
124  ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{incompatible pointer types assigning to 'int *' from 'MutableSetOfArrays<NSString *> *'}}
125  ip = [MutableSetOfArrays alloc];  // expected-error{{incompatible pointer types assigning to 'int *' from 'MutableSetOfArrays *'}}
126  ip = [NSArray<NSString *> array]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
127  ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
128
129  ip = [[NSMutableArray<NSString *> alloc] init];  // expected-error{{incompatible pointer types assigning to 'int *' from '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
136void 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// --------------------------------------------------------------------------
158void 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{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
170  ip = mutStringSet.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
171  ip = widgetSet.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<Widget *> *'}}
172  ip = untypedMutSet.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
173  ip = mutStringArraySet.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSArray<NSString *> *> *'}}
174  ip = set.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
175  ip = mutSet.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
176  ip = mutArraySet.allObjects; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
177
178  ip = mutDict.someRandomKey; // expected-error{{incompatible pointer types assigning to 'int *' from '__kindof id<NSCopying>'}}
179}
180
181void 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// --------------------------------------------------------------------------
204void 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{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
219
220  ip = mutStringArray[0]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
221  mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}}
222
223  ip = array[0]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
224
225  ip = mutArray[0]; // expected-error{{incompatible pointer types assigning to 'int *' from 'id'}}
226  mutArray[0] = ip; // expected-error{{parameter of type 'id'}}
227
228  ip = stringWidgetDict[string]; // expected-error{{incompatible pointer types assigning to 'int *' from 'Widget *'}}
229  widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
230
231  ip = mutStringWidgetDict[string]; // expected-error{{incompatible pointer types assigning to 'int *' from '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{{incompatible pointer types assigning to 'int *' from 'id'}}
237
238  ip = mutDict[string]; // expected-error{{incompatible pointer types assigning to 'int *' from '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// --------------------------------------------------------------------------
248void test_instance_variable(NSArray<NSString *> *stringArray,
249                            NSArray *array) {
250  int *ip;
251
252  ip = stringArray->data; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSString **'}}
253  ip = array->data; // expected-error{{incompatible pointer types assigning to 'int *' from 'id *'}}
254}
255
256@implementation WindowArray
257- (void)testInstanceVariable {
258  int *ip;
259
260  ip = data; // expected-error{{incompatible pointer types assigning to 'int *' from 'Window **'}}
261}
262@end
263
264// --------------------------------------------------------------------------
265// Implicit conversions.
266// --------------------------------------------------------------------------
267void 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{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}}
280
281  // Specialized -> specialized (different levels).
282  stringArray = mutStringArray;
283
284  // Specialized -> specialized failure (different levels).
285  numberArray = mutStringArray; // expected-error{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from '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
300void 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// --------------------------------------------------------------------------
327void 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{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
338  ip = cond ? mutStringArray : stringArray; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
339
340  ip = cond ? stringArray2 : mutStringArray; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
341  ip = cond ? mutStringArray : stringArray2; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
342
343  ip = cond ? stringArray : mutArray; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
344
345  ip = cond ? stringArray2 : mutArray; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
346
347  ip = cond ? mutArray : stringArray; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray *'}}
348
349  ip = cond ? mutArray : stringArray2; // expected-error{{incompatible pointer types assigning to 'int *' from '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{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
361  ip = [super objectAtIndexedSubscript:0]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSString *'}}
362}
363
364+ (void)useSuperMethod {
365  int *ip;
366  ip = super.array; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
367  ip = [super array]; // expected-error{{incompatible pointer types assigning to 'int *' from 'NSArray<NSString *> *'}}
368}
369@end
370
371// --------------------------------------------------------------------------
372// Template instantiation
373// --------------------------------------------------------------------------
374template<typename K, typename V>
375struct 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
379template<typename ...Args>
380struct 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
386void 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
395void 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// --------------------------------------------------------------------------
411template<template<typename T, typename U> class TT>
412struct AcceptsTemplateTemplate { };
413
414typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}}
415
416template<typename T>
417struct 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
421struct NSMutableDictionaryBuilder {
422  typedef NSMutableDictionary apply; // expected-note 2{{declared as a non-template here}}
423};
424
425typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}}
426
427template<typename K, typename V>
428struct NonDependentTemplate {
429  typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
430};
431
432// However, one can use an alias template to turn a parameterized
433// class into a template.
434template<typename K, typename V>
435using NSMutableDictionaryAlias = NSMutableDictionary<K, V>;
436
437typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay
438
439
440