#if !__has_feature(objc_generics)
# error Compiler does not support Objective-C generics?
#endif
#if !__has_feature(objc_generics_variance)
# error Compiler does not support co- and contr-variance?
#endif
#define nil 0
typedef unsigned long NSUInteger;
typedef int BOOL;
@protocol NSObject
+ (id)alloc;
- (id)init;
@end
@protocol NSCopying
@end
__attribute__((objc_root_class))
@interface NSObject <NSObject>
@end
@interface NSString : NSObject <NSCopying>
@end
@interface NSMutableString : NSString
@end
@interface NSNumber : NSObject <NSCopying>
@end
@interface NSSet : NSObject <NSCopying>
@end
@interface NSArray<__covariant ObjectType> : NSObject
+ (instancetype)arrayWithObjects:(const ObjectType [])objects count:(NSUInteger)count;
+ (instancetype)getEmpty;
+ (NSArray<ObjectType> *)getEmpty2;
- (BOOL)contains:(ObjectType)obj;
- (BOOL)containsObject:(ObjectType)anObject;
- (ObjectType)getObjAtIndex:(NSUInteger)idx;
- (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
- (NSArray<ObjectType> *)arrayByAddingObject:(ObjectType)anObject;
@property(readonly) ObjectType firstObject;
@end
@interface NSMutableArray<ObjectType> : NSArray<ObjectType>
- (void)addObject:(ObjectType)anObject;
- (instancetype)init;
@end
@interface MutableArray<ObjectType> : NSArray<ObjectType>
- (void)addObject:(ObjectType)anObject;
@end
@interface LegacyMutableArray : MutableArray
@end
@interface LegacySpecialMutableArray : LegacyMutableArray
@end
@interface BuggyMutableArray<T> : MutableArray
@end
@interface BuggySpecialMutableArray<T> : BuggyMutableArray<T>
@end
@interface MyMutableStringArray : MutableArray<NSString *>
@end
@interface ExceptionalArray<ExceptionType> : MutableArray<NSString *>
- (ExceptionType) getException;
@end
@interface UnrelatedType : NSObject<NSCopying>
@end
int getUnknown(void);
NSArray *getStuff(void);
NSArray *getTypedStuff(void) {
NSArray<NSNumber *> *c = getStuff();
return c;
}
void doStuff(NSArray<NSNumber *> *);
void withArrString(NSArray<NSString *> *);
void withArrMutableString(NSArray<NSMutableString *> *);
void withMutArrString(MutableArray<NSString *> *);
void withMutArrMutableString(MutableArray<NSMutableString *> *);
void incompatibleTypesErased(NSArray *a, NSMutableArray<NSString *> *b,
NSArray<NSNumber *> *c,
NSMutableArray *d) {
a = b;
c = a; [a contains: [[NSNumber alloc] init]];
[a contains: [[NSString alloc] init]];
doStuff(a);
d = b;
[d addObject: [[NSNumber alloc] init]]; }
void crossProceduralErasedTypes(void) {
NSArray<NSString *> *a = getTypedStuff(); }
void incompatibleTypesErasedReverseConversion(NSMutableArray *a,
NSMutableArray<NSString *> *b) {
b = a;
[a contains: [[NSNumber alloc] init]];
[a contains: [[NSString alloc] init]];
doStuff(a);
[a addObject: [[NSNumber alloc] init]]; }
void idErasedIncompatibleTypesReverseConversion(id a, NSMutableArray<NSString *> *b) {
b = a;
[a contains: [[NSNumber alloc] init]];
[a contains: [[NSString alloc] init]];
doStuff(a);
[a addObject:[[NSNumber alloc] init]]; }
void idErasedIncompatibleTypes(id a, NSMutableArray<NSString *> *b,
NSArray<NSNumber *> *c) {
a = b;
c = a; [a contains: [[NSNumber alloc] init]];
[a contains: [[NSString alloc] init]];
doStuff(a);
[a addObject:[[NSNumber alloc] init]]; }
void pathSensitiveInference(MutableArray *m, MutableArray<NSString *> *a,
MutableArray<NSMutableString *> *b) {
if (getUnknown() == 5) {
m = a;
[m contains: [[NSString alloc] init]];
} else {
m = b;
[m contains: [[NSMutableString alloc] init]];
}
[m addObject: [[NSString alloc] init]]; [m addObject: [[NSMutableString alloc] init]];
}
void verifyAPIusage(id a, MutableArray<NSString *> *b) {
b = a;
doStuff(a); }
void dontInferFromExplicitCastsOnUnspecialized(MutableArray *a,
MutableArray<NSMutableString *> *b) {
b = (MutableArray<NSMutableString *> *)a;
[a addObject: [[NSString alloc] init]]; }
void dontWarnOnExplicitCastsAfterInference(MutableArray *a) {
withMutArrString(a);
withMutArrMutableString((MutableArray<NSMutableString *> *)a); }
void dontDiagnoseOnExplicitCrossCasts(MutableArray<NSSet *> *a,
MutableArray<NSMutableString *> *b) {
b = (MutableArray<NSMutableString *> *)a; [a addObject: [[NSSet alloc] init]]; [b addObject: [[NSMutableString alloc] init]]; }
void subtypeOfGeneric(id d, MyMutableStringArray *a,
MutableArray<NSString *> *b,
MutableArray<NSNumber *> *c) {
d = a;
b = d;
c = d; }
void genericSubtypeOfGeneric(id d, ExceptionalArray<NSString *> *a,
MutableArray<NSString *> *b,
MutableArray<NSNumber *> *c) {
d = a;
[d contains: [[NSString alloc] init]];
[d contains: [[NSNumber alloc] init]];
b = d;
c = d;
[d addObject: [[NSNumber alloc] init]]; }
void genericSubtypeOfGenericReverse(id d, ExceptionalArray<NSString *> *a,
MutableArray<NSString *> *b,
MutableArray<NSNumber *> *c) {
a = d;
[d contains: [[NSString alloc] init]];
[d contains: [[NSNumber alloc] init]];
b = d;
c = d;
[d addObject: [[NSNumber alloc] init]]; }
void inferenceFromAPI(id a) {
withMutArrString(a);
withMutArrMutableString(a); }
void inferenceFromAPI2(id a) {
withMutArrMutableString(a);
withMutArrString(a); }
void inferenceFromAPIWithLegacyTypes(LegacyMutableArray *a) {
withMutArrMutableString(a);
withMutArrString(a); }
void inferenceFromAPIWithLegacyTypes2(LegacySpecialMutableArray *a) {
withMutArrString(a);
withMutArrMutableString(a); }
void inferenceFromAPIWithLegacyTypes3(__kindof NSArray<NSString *> *a) {
LegacyMutableArray *b = a;
withMutArrString(b);
withMutArrMutableString(b); }
void inferenceFromAPIWithBuggyTypes(BuggyMutableArray<NSMutableString *> *a) {
withMutArrString(a);
withMutArrMutableString(a); }
void InferenceFromAPIWithBuggyTypes2(BuggySpecialMutableArray<NSMutableString *> *a) {
withMutArrMutableString(a);
withMutArrString(a); }
void InferenceFromAPIWithBuggyTypes3(MutableArray<NSMutableString *> *a) {
id b = a;
withMutArrMutableString((BuggyMutableArray<NSMutableString *> *)b);
withMutArrString(b); }
void InferenceFromAPIWithBuggyTypes4(__kindof NSArray<NSString *> *a) {
BuggyMutableArray<NSMutableString *> *b = a;
withMutArrString(b);
withMutArrMutableString(b); }
NSArray<NSString *> *getStrings(void);
void enforceDynamicRulesInsteadOfStatic(NSArray<NSNumber *> *a) {
NSArray *b = a;
b = getStrings();
}
void workWithProperties(NSArray<NSNumber *> *a) {
NSArray *b = a;
NSString *str = [b getObjAtIndex: 0]; NSNumber *num = [b getObjAtIndex: 0];
str = [b firstObject]; num = [b firstObject];
str = b.firstObject; num = b.firstObject;
str = b[0]; num = b[0];
}
void findMethodDeclInTrackedType(id m, NSArray<NSMutableString *> *a,
MutableArray<NSMutableString *> *b) {
a = b;
if (getUnknown() == 5) {
m = a;
[m addObject: [[NSString alloc] init]]; } else {
m = b;
[m addObject: [[NSMutableString alloc] init]];
}
}
void findMethodDeclInTrackedType2(__kindof NSArray<NSString *> *a,
MutableArray<NSMutableString *> *b) {
a = b;
if (getUnknown() == 5) {
[a addObject: [[NSString alloc] init]]; } else {
[a addObject: [[NSMutableString alloc] init]];
}
}
void testUnannotatedLiterals(void) {
NSArray *arr = @[@"A", @"B"];
[arr contains: [[NSNumber alloc] init]];
}
void testAnnotatedLiterals(void) {
NSArray<NSString *> *arr = @[@"A", @"B"];
NSArray *arr2 = arr;
[arr2 contains: [[NSNumber alloc] init]];
}
void nonExistentMethodDoesNotCrash(id a, MutableArray<NSMutableString *> *b) {
a = b;
[a nonExistentMethod];
}
void trackedClassVariables(void) {
Class c = [NSArray<NSString *> class];
NSArray<NSNumber *> *a = [c getEmpty]; a = [c getEmpty2]; }
void nestedCollections(NSArray<NSArray<NSNumber *> *> *mat, NSArray<NSString *> *row) {
id temp = row;
[mat contains: temp]; }
void testMistmatchedTypeCast(MutableArray<NSMutableString *> *a) {
MutableArray *b = (MutableArray<NSNumber *> *)a;
[b addObject: [[NSNumber alloc] init]];
id c = (UnrelatedType *)a;
[c addObject: [[NSNumber alloc] init]];
[c addObject: [[NSString alloc] init]];
}
void returnCollectionToIdVariable(NSArray<NSArray<NSString *> *> *arr) {
NSArray *erased = arr;
id a = [erased firstObject];
NSArray<NSNumber *> *res = a; }
void eraseSpecialization(NSArray<NSArray<NSString *> *> *arr) {
NSArray *erased = arr;
NSArray* a = [erased firstObject];
NSArray<NSNumber *> *res = a; }
void returnToUnrelatedType(NSArray<NSArray<NSString *> *> *arr) {
NSArray *erased = arr;
NSSet* a = [erased firstObject]; (void)a;
}
void returnToIdVariable(NSArray<NSString *> *arr) {
NSArray *erased = arr;
id a = [erased firstObject];
NSNumber *res = a; }
@interface UnrelatedTypeGeneric<T> : NSObject<NSCopying>
- (void)takesType:(T)v;
@end
void testGetMostInformativeDerivedForId(NSArray<NSString *> *a,
UnrelatedTypeGeneric<NSString *> *b) {
id idB = b;
a = idB;
id x = a; [x takesType:[[NSNumber alloc] init]]; }
void testArgumentAfterUpcastToRootWithCovariantTypeParameter(NSArray<NSString *> *allStrings, NSNumber *number) {
NSArray<NSObject *> *allObjects = allStrings; NSArray<NSObject *> *moreObjects = [allObjects arrayByAddingObject:number]; }
void testArgumentAfterUpcastWithCovariantTypeParameter(NSArray<NSMutableString *> *allMutableStrings, NSNumber *number) {
NSArray<NSString *> *allStrings = allMutableStrings; id numberAsId = number;
NSArray<NSString *> *moreStrings = [allStrings arrayByAddingObject:numberAsId]; }
void testArgumentAfterCastToUnspecializedWithCovariantTypeParameter(NSArray<NSMutableString *> *allMutableStrings, NSNumber *number) {
NSArray *allStrings = allMutableStrings; id numberAsId = number;
NSArray *moreStringsUnspecialized = [allStrings arrayByAddingObject:numberAsId];
NSArray<NSString *> *moreStringsSpecialized = [allStrings arrayByAddingObject:numberAsId];
}
void testCallToMethodWithCovariantParameterOnInstanceOfSubclassWithInvariantParameter(NSMutableArray<NSMutableString *> *mutableArrayOfMutableStrings, NSString *someString) {
NSArray<NSString *> *arrayOfStrings = mutableArrayOfMutableStrings;
[arrayOfStrings containsObject:someString]; }