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

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]]);
}

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!