1// RUN: %clang_cc1 -fsyntax-only -verify %s
2
3#if !__has_feature(objc_instancetype)
4# error Missing 'instancetype' feature macro.
5#endif
6
7@interface Root
8+ (instancetype)alloc;
9- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
10- (instancetype)self; // expected-note {{explicitly declared 'instancetype'}}
11- (Class)class;
12
13@property (assign) Root *selfProp;
14- (instancetype)selfProp;
15@end
16
17@protocol Proto1
18@optional
19- (instancetype)methodInProto1;
20@end
21
22@protocol Proto2
23@optional
24- (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}}
25- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
26@end
27
28@interface Subclass1 : Root // expected-note 4 {{receiver is instance of class declared here}}
29- (instancetype)initSubclass1;
30- (void)methodOnSubclass1;
31+ (instancetype)allocSubclass1;
32@end
33
34@interface Subclass2 : Root
35- (instancetype)initSubclass2;
36- (void)methodOnSubclass2;
37@end
38
39// Sanity check: the basic initialization pattern.
40void test_instancetype_alloc_init_simple() {
41  Root *r1 = [[Root alloc] init];
42  Subclass1 *sc1 = [[Subclass1 alloc] init];
43}
44
45// Test that message sends to instancetype methods have the right type.
46void test_instancetype_narrow_method_search() {
47  // instancetype on class methods
48  Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
49  Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay
50
51  // instancetype on instance methods
52  [[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}}
53  [[[Subclass2 alloc] init] methodOnSubclass2];
54  
55  // instancetype on class methods using protocols
56  typedef Subclass1<Proto1> SC1Proto1;
57  typedef Subclass1<Proto2> SC1Proto2;
58  [[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
59  [[SC1Proto2 alloc] methodInProto2];
60
61  // instancetype on instance methods
62  Subclass1<Proto1> *sc1proto1 = 0;
63  [[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
64  Subclass1<Proto2> *sc1proto2 = 0;
65  [[sc1proto2 self] methodInProto2];
66
67  // Exact type checks
68  typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0;
69  typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0;
70
71  // Message sends to Class.
72  Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init];
73
74  // Property access
75  [sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
76  [sc1proto2.self methodInProto2];
77  [Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
78  [Subclass2.alloc initSubclass2];
79
80  [sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
81  [sc1proto2.selfProp methodInProto2];
82}
83
84// Test that message sends to super methods have the right type.
85@interface Subsubclass1 : Subclass1
86- (instancetype)initSubclass1;
87+ (instancetype)allocSubclass1;
88
89- (void)onlyInSubsubclass1;
90@end
91
92@implementation Subsubclass1
93- (instancetype)initSubclass1 {
94  // Check based on method search.
95  [[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
96  [super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
97
98  self = [super init]; // common pattern
99
100  // Exact type check.
101  typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0;
102
103  return self;
104}
105
106+ (instancetype)allocSubclass1 {
107  // Check based on method search.
108  [[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
109
110  // The ASTs don't model super property accesses well enough to get this right
111  [super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
112
113  // Exact type check.
114  typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0;
115  
116  return [super allocSubclass1];
117}
118
119- (void)onlyInSubsubclass1 {}
120@end
121
122// Check compatibility rules for inheritance of related return types.
123@class Subclass4;
124
125@interface Subclass3 <Proto1, Proto2>
126- (Subclass3 *)methodInProto1;
127- (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}}
128@end
129
130@interface Subclass4 : Root
131+ (Subclass4 *)alloc; // okay
132- (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
133- (id)self; // expected-note{{overridden method is part of the 'self' method family}}
134- (instancetype)initOther;
135@end
136
137@protocol Proto3 <Proto1, Proto2>
138@optional
139- (id)methodInProto1;
140- (Subclass1 *)methodInProto2;
141- (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
142@end
143
144@implementation Subclass4
145+ (id)alloc {
146  return self; // FIXME: we accept this in ObjC++ but not ObjC?
147}
148
149- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
150
151- (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
152
153- (Subclass4 *)initOther { return 0; }
154
155@end
156
157// Check that inherited related return types influence the types of
158// message sends.
159void test_instancetype_inherited() {
160  [[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}}
161  [[Subclass4 alloc] initOther];
162}
163
164// Check that related return types tighten up the semantics of
165// Objective-C method implementations.
166@implementation Subclass2
167- (instancetype)initSubclass2 { // expected-note {{explicitly declared 'instancetype'}}
168  Subclass1 *sc1 = [[Subclass1 alloc] init];
169  return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}}
170}
171- (void)methodOnSubclass2 {}
172- (id)self {
173  Subclass1 *sc1 = [[Subclass1 alloc] init];
174  return sc1; // expected-error{{cannot initialize return object of type 'Subclass2 *' with an lvalue of type 'Subclass1 *'}}
175}
176@end
177
178@interface MyClass : Root
179+ (int)myClassMethod;
180@end
181
182@implementation MyClass
183+ (int)myClassMethod { return 0; }
184
185- (void)blah {
186  int i = [[MyClass self] myClassMethod];
187}
188
189@end
190
191// rdar://12493140
192@protocol P4
193- (instancetype) foo; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
194@end
195@interface A4 : Root <P4>
196- (instancetype) bar; // expected-note {{current method is explicitly declared 'instancetype' and is expected to return an instance of its class type}}
197- (instancetype) baz; // expected-note {{overridden method returns an instance of its class type}} expected-note {{previous definition is here}}
198@end
199@interface B4 : Root @end
200
201@implementation A4 {
202  B4 *_b;
203}
204- (id) foo {
205  return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}}
206}
207- (id) bar {
208  return _b; // expected-error {{cannot initialize return object of type 'A4 *' with an lvalue of type 'B4 *'}}
209}
210
211// This is really just to ensure that we don't crash.
212// FIXME: only one diagnostic, please
213- (float) baz { // expected-warning {{method is expected to return an instance of its class type 'A4', but is declared to return 'float'}} expected-warning {{conflicting return type in implementation}}
214  return 0;
215}
216@end
217