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