Home | History | Annotate | Download | only in SemaObjCXX
      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;
    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