Clang: type checking of `__kindof id<SomeProtocol>` is too loose
| Originator: | daniel | ||
| Number: | rdar://22782165 | Date Originated: | 2015-09-21 |
| Status: | open | Resolved: | |
| Product: | Developer Tools | Product Version: | Xcode Version 7.0 (7A220) |
| Classification: | Other Bug | Reproducible: | Always |
Summary:
When annotating API using the construct mentioned above, Clang’s type checker appears to be too lax:
It looks as if the `__kindof` keyword effectively removes the protocol constraint.
An example of a scenario where this matters can be found in the Dummy.m file of the attached sample project.
Steps to Reproduce:
Build the attached sample project, and open the file Dummy.m.
Expected Results:
Compiling results in the following warning:
${PROJECT_DIR}/Dummy.m:32:20: warning: initializing 'NSArray *const __strong' with an expression of incompatible type 'id<D12DBColumnRepresentable> _Nullable'
NSArray *const array = row[@"bogus"];
^ ~~~~~~~~~~~~~
Actual Results:
*crickets*
No really: the build completes without any diagnostics
Version:
Xcode Version 7.0 (7A220)
Notes:
The warning provided in “Expected Results” section is the diagnostic obtained when removing the `__kindof` in the typedef.
In that case, however, there’s also a warning on the line that gets the number.
That’s okay because there’s no guarantee that an arbitrary id<SomeProtocol> is some concrete type that conforms to said protocol, but that means one needs to rely on `__kindof` not removing the protocol requirement.
Configuration:
Attachments:
'WarningSign.zip' was successfully uploaded.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
Contents of Dummy.m -- add as source file to a new framework or library project
@import Foundation; // Empty protocol to say get an “any of …” type @protocol D12DBColumnRepresentable <NSObject> @end // Convenience that uses this “any of …” type typedef NSDictionary<NSString *, id<D12DBColumnRepresentable>> D12DBRowDictionary; // “Populating” the list of that makes up the “any of …” type @interface NSData (D12DBColumnRepresentable) <D12DBColumnRepresentable> @end @interface NSNull (D12DBColumnRepresentable) <D12DBColumnRepresentable> @end @interface NSNumber (D12DBColumnRepresentable) <D12DBColumnRepresentable> @end @interface NSString (D12DBColumnRepresentable) <D12DBColumnRepresentable> @end static inline void ExemplaryFunction(NSString *columnName, D12DBRowDictionary *row) { // Good: NSNumber has been marked as <D12DBColumnRepresentable> // Therefore, this line shouldn’t warn NSNumber *const number = row[columnName]; NSCParameterAssert([number isKindOfClass:[NSNumber class]]); // Bad: NSArray clearly doesn’t conform to <D12DBColumnRepresentable> // Therefore, this line **must** warn since the protocol constraint isn’t satisfied NSArray *const array = row[@"bogus"]; NSCParameterAssert([array isKindOfClass:[NSArray class]]); }