483 lines · plain
1// RUN: %clang_cc1 -fblocks -fsyntax-only -Wnullable-to-nonnull-conversion %s -verify2//3// Test the substitution of type arguments for type parameters when4// using parameterized classes in Objective-C.5 6@protocol NSObject7@end8 9__attribute__((objc_root_class))10@interface NSObject <NSObject>11+ (instancetype)alloc;12- (instancetype)init;13@end14 15@protocol NSCopying16@end17 18@interface NSString : NSObject <NSCopying>19@end20 21@interface NSMutableString : NSString22@end23 24@interface NSNumber : NSObject <NSCopying>25@end26 27@interface NSArray<T> : NSObject <NSCopying> {28@public29 T *data; // don't try this at home30}31- (T)objectAtIndexedSubscript:(int)index;32+ (NSArray<T> *)array;33+ (void)setArray:(NSArray <T> *)array;34@property (copy,nonatomic) T lastObject;35@end36 37@interface NSMutableArray<T> : NSArray<T>38-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}}39- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}}40@end41 42@interface NSStringArray : NSArray<NSString *>43@end44 45@interface NSSet<T> : NSObject <NSCopying>46- (T)firstObject;47@property (nonatomic, copy) NSArray<T> *allObjects;48@end49 50// Parameterized inheritance (simple case)51@interface NSMutableSet<U : id<NSCopying>> : NSSet<U>52- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}}53@end54 55@interface Widget : NSObject <NSCopying>56@end57 58// Non-parameterized class inheriting from a specialization of a59// parameterized class.60@interface WidgetSet : NSMutableSet<Widget *>61@end62 63// Parameterized inheritance with a more interesting transformation in64// the specialization.65@interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*>66@end67 68// Inheriting from an unspecialized form of a parameterized type.69@interface UntypedMutableSet : NSMutableSet70@end71 72@interface Window : NSObject73@end74 75@interface NSDictionary<K, V> : NSObject <NSCopying>76- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}}77@end78 79@interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V>80- (void)setObject:(V)object forKeyedSubscript:(K)key;81// expected-note@-1 {{parameter 'object' here}}82// expected-note@-2 {{parameter 'object' here}}83// expected-note@-3 {{parameter 'key' here}}84// expected-note@-4 {{parameter 'key' here}}85 86@property (strong) K someRandomKey;87@end88 89@interface WindowArray : NSArray<Window *>90@end91 92@interface NSSet<T> (Searching)93- (T)findObject:(T)object;94@end95 96@interface NSView : NSObject97@end98 99@interface NSControl : NSView100- (void)toggle;101@end102 103@interface NSViewController<ViewType : NSView *> : NSObject104@property (nonatomic,retain) ViewType view;105@end106 107@interface TypedefTypeParam<T> : NSObject108typedef T AliasT;109- (void)test:(AliasT)object;110// expected-note@-1 {{parameter 'object' here}}111@end112 113// --------------------------------------------------------------------------114// Nullability115// --------------------------------------------------------------------------116typedef NSControl * _Nonnull Nonnull_NSControl;117 118@interface NSNullableTest<ViewType : NSView *> : NSObject119- (ViewType)view;120- (nullable ViewType)maybeView;121@end122 123@interface NSNullableTest2<ViewType : NSView * _Nullable> : NSObject // expected-error{{type parameter 'ViewType' bound 'NSView * _Nullable' cannot explicitly specify nullability}}124@end125 126void test_nullability(void) {127 NSControl * _Nonnull nonnull_NSControl;128 129 // Nullability introduced by substitution.130 NSNullableTest<NSControl *> *unspecifiedControl;131 nonnull_NSControl = [unspecifiedControl view];132 nonnull_NSControl = [unspecifiedControl maybeView]; // expected-warning{{from nullable pointer 'NSControl * _Nullable' to non-nullable pointer type 'NSControl * _Nonnull'}}133 134 // Nullability overridden by substitution.135 NSNullableTest<Nonnull_NSControl> *nonnullControl;136 nonnull_NSControl = [nonnullControl view];137 nonnull_NSControl = [nonnullControl maybeView]; // expected-warning{{from nullable pointer 'Nonnull_NSControl _Nullable' (aka 'NSControl *') to non-nullable pointer type 'NSControl * _Nonnull'}}138 139 // Nullability cannot be specified directly on a type argument.140 NSNullableTest<NSControl * _Nonnull> *nonnullControl2; // expected-error{{type argument 'NSControl *' cannot explicitly specify nullability}}141}142 143// --------------------------------------------------------------------------144// Message sends.145// --------------------------------------------------------------------------146void test_message_send_result(147 NSSet<NSString *> *stringSet,148 NSMutableSet<NSString *> *mutStringSet,149 WidgetSet *widgetSet,150 UntypedMutableSet *untypedMutSet,151 MutableSetOfArrays<NSString *> *mutStringArraySet,152 NSSet *set,153 NSMutableSet *mutSet,154 MutableSetOfArrays *mutArraySet,155 NSArray<NSString *> *stringArray,156 NSArray<__kindof NSString *> *kindofStringArray,157 void (^block)(void)) {158 int *ip;159 ip = [stringSet firstObject]; // expected-error{{from 'NSString *'}}160 ip = [mutStringSet firstObject]; // expected-error{{from 'NSString *'}}161 ip = [widgetSet firstObject]; // expected-error{{from 'Widget *'}}162 ip = [untypedMutSet firstObject]; // expected-error{{from 'id'}}163 ip = [mutStringArraySet firstObject]; // expected-error{{from 'NSArray<NSString *> *'}}164 ip = [set firstObject]; // expected-error{{from 'id'}}165 ip = [mutSet firstObject]; // expected-error{{from 'id'}}166 ip = [mutArraySet firstObject]; // expected-error{{from 'id'}}167 ip = [block firstObject]; // expected-error{{from 'id'}}168 169 ip = [stringSet findObject:@"blah"]; // expected-error{{from 'NSString *'}}170 171 // Class messages.172 ip = [NSSet<NSString *> alloc]; // expected-error{{from 'NSSet<NSString *> *'}}173 ip = [NSSet alloc]; // expected-error{{from 'NSSet *'}}174 ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from 'MutableSetOfArrays<NSString *> *'}}175 ip = [MutableSetOfArrays alloc]; // expected-error{{from 'MutableSetOfArrays *'}}176 ip = [NSArray<NSString *> array]; // expected-error{{from 'NSArray<NSString *> *'}}177 ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from 'NSArray<NSString *> *'}}178 179 ip = [[NSMutableArray<NSString *> alloc] init]; // expected-error{{from 'NSMutableArray<NSString *> *'}}180 181 [[NSMutableArray alloc] initWithArray: stringArray]; // okay182 [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay183 [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{sending 'NSArray<NSString *> *' to parameter of type 'NSArray<NSNumber *> *'}}184 185 ip = [[[NSViewController alloc] init] view]; // expected-error{{from '__kindof NSView *'}}186 [[[[NSViewController alloc] init] view] toggle];187 188 NSMutableString *mutStr = kindofStringArray[0];189 NSNumber *number = kindofStringArray[0]; // expected-error{{of type '__kindof NSString *'}}190}191 192void test_message_send_param(193 NSMutableSet<NSString *> *mutStringSet,194 WidgetSet *widgetSet,195 UntypedMutableSet *untypedMutSet,196 MutableSetOfArrays<NSString *> *mutStringArraySet,197 NSMutableSet *mutSet,198 MutableSetOfArrays *mutArraySet,199 TypedefTypeParam<NSString *> *typedefTypeParam,200 void (^block)(void)) {201 Window *window;202 203 [mutStringSet addObject: window]; // expected-error{{parameter of type 'NSString *'}}204 [widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}}205 [untypedMutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}206 [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}}207 [mutSet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}208 [mutArraySet addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}209 [typedefTypeParam test: window]; // expected-error{{parameter of type 'NSString *'}}210 [block addObject: window]; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}211}212 213// --------------------------------------------------------------------------214// Property accesses.215// --------------------------------------------------------------------------216void test_property_read(217 NSSet<NSString *> *stringSet,218 NSMutableSet<NSString *> *mutStringSet,219 WidgetSet *widgetSet,220 UntypedMutableSet *untypedMutSet,221 MutableSetOfArrays<NSString *> *mutStringArraySet,222 NSSet *set,223 NSMutableSet *mutSet,224 MutableSetOfArrays *mutArraySet,225 NSMutableDictionary *mutDict) {226 int *ip;227 ip = stringSet.allObjects; // expected-error{{from 'NSArray<NSString *> *'}}228 ip = mutStringSet.allObjects; // expected-error{{from 'NSArray<NSString *> *'}}229 ip = widgetSet.allObjects; // expected-error{{from 'NSArray<Widget *> *'}}230 ip = untypedMutSet.allObjects; // expected-error{{from 'NSArray *'}}231 ip = mutStringArraySet.allObjects; // expected-error{{from 'NSArray<NSArray<NSString *> *> *'}}232 ip = set.allObjects; // expected-error{{from 'NSArray *'}}233 ip = mutSet.allObjects; // expected-error{{from 'NSArray *'}}234 ip = mutArraySet.allObjects; // expected-error{{from 'NSArray *'}}235 236 ip = mutDict.someRandomKey; // expected-error{{from '__kindof id<NSCopying>'}}237 238 ip = [[NSViewController alloc] init].view; // expected-error{{from '__kindof NSView *'}}239}240 241void test_property_write(242 NSMutableSet<NSString *> *mutStringSet,243 WidgetSet *widgetSet,244 UntypedMutableSet *untypedMutSet,245 MutableSetOfArrays<NSString *> *mutStringArraySet,246 NSMutableSet *mutSet,247 MutableSetOfArrays *mutArraySet,248 NSMutableDictionary *mutDict) {249 int *ip;250 251 mutStringSet.allObjects = ip; // expected-error{{to 'NSArray<NSString *> *'}}252 widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}}253 untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}254 mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}}255 mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}256 mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}}257 258 mutDict.someRandomKey = ip; // expected-error{{to 'id<NSCopying>'}}259}260 261// --------------------------------------------------------------------------262// Subscripting263// --------------------------------------------------------------------------264void test_subscripting(265 NSArray<NSString *> *stringArray,266 NSMutableArray<NSString *> *mutStringArray,267 NSArray *array,268 NSMutableArray *mutArray,269 NSDictionary<NSString *, Widget *> *stringWidgetDict,270 NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict,271 NSDictionary *dict,272 NSMutableDictionary *mutDict) {273 int *ip;274 NSString *string;275 Widget *widget;276 Window *window;277 278 ip = stringArray[0]; // expected-error{{from 'NSString *'}}279 280 ip = mutStringArray[0]; // expected-error{{from 'NSString *'}}281 mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}}282 283 ip = array[0]; // expected-error{{from 'id'}}284 285 ip = mutArray[0]; // expected-error{{from 'id'}}286 mutArray[0] = ip; // expected-error{{parameter of type 'id'}}287 288 ip = stringWidgetDict[string]; // expected-error{{from 'Widget *'}}289 widget = stringWidgetDict[widget]; // expected-error{{to parameter of type 'NSString *'}}290 291 ip = mutStringWidgetDict[string]; // expected-error{{from 'Widget *'}}292 widget = mutStringWidgetDict[widget]; // expected-error{{to parameter of type 'NSString *'}}293 mutStringWidgetDict[string] = ip; // expected-error{{to parameter of type 'Widget *'}}294 mutStringWidgetDict[widget] = widget; // expected-error{{to parameter of type 'NSString *'}}295 296 ip = dict[string]; // expected-error{{from 'id'}}297 298 ip = mutDict[string]; // expected-error{{from 'id'}}299 mutDict[string] = ip; // expected-error{{to parameter of type 'id'}}300 301 widget = mutDict[window];302 mutDict[window] = widget; // expected-warning{{parameter of incompatible type 'id<NSCopying>'}}303}304 305// --------------------------------------------------------------------------306// Instance variable access.307// --------------------------------------------------------------------------308void test_instance_variable(NSArray<NSString *> *stringArray,309 NSArray *array) {310 int *ip;311 312 ip = stringArray->data; // expected-error{{from 'NSString **'}}313 ip = array->data; // expected-error{{from 'id *'}}314}315 316@implementation WindowArray317- (void)testInstanceVariable {318 int *ip;319 320 ip = data; // expected-error{{from 'Window **'}}321}322@end323 324// --------------------------------------------------------------------------325// Implicit conversions.326// --------------------------------------------------------------------------327void test_implicit_conversions(NSArray<NSString *> *stringArray,328 NSArray<NSNumber *> *numberArray,329 NSMutableArray<NSString *> *mutStringArray,330 NSArray *array,331 NSMutableArray *mutArray) {332 // Specialized -> unspecialized (same level)333 array = stringArray;334 335 // Unspecialized -> specialized (same level)336 stringArray = array;337 338 // Specialized -> specialized failure (same level).339 stringArray = numberArray; // expected-error{{incompatible pointer types assigning to 'NSArray<NSString *> *' from 'NSArray<NSNumber *> *'}}340 341 // Specialized -> specialized (different levels).342 stringArray = mutStringArray;343 344 // Specialized -> specialized failure (different levels).345 numberArray = mutStringArray; // expected-error{{incompatible pointer types assigning to 'NSArray<NSNumber *> *' from 'NSMutableArray<NSString *> *'}}346 347 // Unspecialized -> specialized (different levels).348 stringArray = mutArray;349 350 // Specialized -> unspecialized (different levels).351 array = mutStringArray;352}353 354@interface NSCovariant1<__covariant T>355@end356 357@interface NSContravariant1<__contravariant T>358@end359 360void test_variance(NSCovariant1<NSString *> *covariant1,361 NSCovariant1<NSMutableString *> *covariant2,362 NSCovariant1<NSString *(^)(void)> *covariant3,363 NSCovariant1<NSMutableString *(^)(void)> *covariant4,364 NSCovariant1<id> *covariant5,365 NSCovariant1<id<NSCopying>> *covariant6,366 NSContravariant1<NSString *> *contravariant1,367 NSContravariant1<NSMutableString *> *contravariant2) {368 covariant1 = covariant2; // okay369 covariant2 = covariant1; // expected-error{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *> *' from 'NSCovariant1<NSString *> *'}}370 371 covariant3 = covariant4; // okay372 covariant4 = covariant3; // expected-error{{incompatible pointer types assigning to 'NSCovariant1<NSMutableString *(^)(void)> *' from 'NSCovariant1<NSString *(^)(void)> *'}}373 374 covariant5 = covariant1; // okay375 covariant1 = covariant5; // okay: id is promiscuous376 377 covariant5 = covariant3; // okay378 covariant3 = covariant5; // okay379 380 contravariant1 = contravariant2; // expected-error{{incompatible pointer types assigning to 'NSContravariant1<NSString *> *' from 'NSContravariant1<NSMutableString *> *'}}381 contravariant2 = contravariant1; // okay382}383 384// --------------------------------------------------------------------------385// Ternary operator386// --------------------------------------------------------------------------387void test_ternary_operator(NSArray<NSString *> *stringArray,388 NSArray<NSNumber *> *numberArray,389 NSMutableArray<NSString *> *mutStringArray,390 NSStringArray *stringArray2,391 NSArray *array,392 NSMutableArray *mutArray,393 int cond) {394 int *ip;395 id object;396 397 ip = cond ? stringArray : mutStringArray; // expected-error{{from 'NSArray<NSString *> *'}}398 ip = cond ? mutStringArray : stringArray; // expected-error{{from 'NSArray<NSString *> *'}}399 400 ip = cond ? stringArray2 : mutStringArray; // expected-error{{from 'NSArray<NSString *> *'}}401 ip = cond ? mutStringArray : stringArray2; // expected-error{{from 'NSArray<NSString *> *'}}402 403 ip = cond ? stringArray : mutArray; // expected-error{{from 'NSArray *'}}404 405 ip = cond ? stringArray2 : mutArray; // expected-error{{from 'NSArray *'}}406 407 ip = cond ? mutArray : stringArray; // expected-error{{from 'NSArray *'}}408 409 ip = cond ? mutArray : stringArray2; // expected-error{{from 'NSArray *'}}410 411 object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}}412}413 414// --------------------------------------------------------------------------415// super416// --------------------------------------------------------------------------417@implementation NSStringArray418- (void)useSuperMethod {419 int *ip;420 ip = super.lastObject; // expected-error{{from 'NSString *'}}421 super.lastObject = ip; // expected-error{{to 'NSString *'}}422 ip = [super objectAtIndexedSubscript:0]; // expected-error{{from 'NSString *'}}423}424 425+ (void)useSuperMethod {426 int *ip;427 ip = super.array; // expected-error{{from 'NSArray<NSString *> *'}}428 super.array = ip; // expected-error{{to 'NSArray<NSString *> *'}}429 ip = [super array]; // expected-error{{from 'NSArray<NSString *> *'}}430}431@end432 433// --------------------------------------------------------------------------434// warning about likely protocol/class name typos.435// --------------------------------------------------------------------------436typedef NSArray<NSObject> ArrayOfNSObjectWarning; // expected-warning{{parameterized class 'NSArray' already conforms to the protocols listed; did you forget a '*'?}}437 438@interface MyMutableDictionary<KeyType, ObjectType> : NSObject439- (void)setObject:(ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key; // expected-note{{passing argument to parameter 'obj' here}} \440 // expected-note{{passing argument to parameter 'key' here}}441@end442 443void bar(MyMutableDictionary<NSString *, NSString *> *stringsByString,444 NSNumber *n1, NSNumber *n2) {445 // We warn here when the key types do not match.446 stringsByString[n1] = n2; // expected-error{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString *'}} \447 // expected-error{{incompatible pointer types sending 'NSNumber *' to parameter of type 'NSString<NSCopying> *'}}448}449 450@interface MyTest<K, V> : NSObject <NSCopying>451- (V)test:(K)key;452- (V)test2:(K)key; // expected-note{{previous definition is here}}453- (void)mapUsingBlock:(id (^)(V))block;454- (void)mapUsingBlock2:(id (^)(V))block; // expected-note{{previous definition is here}}455@end456 457@implementation MyTest458- (id)test:(id)key {459 return key;460}461- (int)test2:(id)key{ // expected-warning{{conflicting return type in implementation}}462 return 0;463}464- (void)mapUsingBlock:(id (^)(id))block {465}466- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}}467}468@end469 470// --------------------------------------------------------------------------471// Use a type parameter as a type argument.472// --------------------------------------------------------------------------473// Type bounds in a category/extension are omitted.474@interface ParameterizedContainer<T : id<NSCopying>>475- (ParameterizedContainer<T> *)inInterface;476@end477@interface ParameterizedContainer<T> (Cat)478- (ParameterizedContainer<T> *)inCategory;479@end480@interface ParameterizedContainer<U> ()481- (ParameterizedContainer<U> *)inExtension;482@end483