Module-Swift.h: Property type 'Type2Details * _Nonnull' is incompatible with type 'Type1Details * _Nonnull' inherited from 'Type1'

I have following code in Swift:

@objc
class Type1: NSObject {
  @objc var details: Details {
     fatalError("placeholder for actual implementation")
  }

  @objc(Type1Details)
  class Details: NSObject {}
}

@objc
class Type2: Type1 {
  @objc override var details: Details {
     fatalError("placeholder for actual implementation")
  }

  @objc(Type2Details)
  class Details: Type1.Details {}
}

The generated Swift Generated header gives following warning in such case:

Module-Swift.h: Property type 'Type2Details * _Nonnull' is incompatible with type 'Type1Details * _Nonnull' inherited from 'Type1'

This warning doesn’t make sense as Type2Details inherits Type1Details. From what I have found out from developers facing such errors the header file needs to be modified to prevent this error:

  1. By ordering the Type2Details definition above its usage
  2. Or by ignoring this diagnostic.

For point 1, I couldn’t find any way to achieve ordering definitions in the generated header. So I went with option 2 with custom script phase that modifies the generated header to ignore the diagnostics.

In my opinion this diagnostic doesn’t make sense in Swift generated header since Swift compiler does the type checking, allowing issues with type safety being caught during compile time.

It's unsafe in general because someone could say:

void setType2DetailsToType1Details(Type2* t2) {
    Type1* t1 = t2; // Safe because Type1 is a superclass of Type2
    Type1Details* t1d = [[Type1Details alloc] init];
    [t1 setDetails:t1d];
}

and set the Details on an instance of Type2 to an instance of Type1Details (that is not an instance of Type2Details).

1 Like

@bbrk24 the provided example assumes details property settable but in my usage it is only a gettable property.

Ah okay, it isn't in the example code you provided in the original post. I don't know for sure then.

Looking at the code sample you provided, it looks like you're declaring a second property with the exact same name rather than an actual override, and it's possible that's confusing the compiler?

I have updated my sample to more closely match to my actual code (except the actual implementation of the gettable details property). Apologies for creating the confusion, I created the post in a hurry and didn’t validate my reproducing snippet first. I am trying to share a sample project as well but not able to upload zip file here. Please allow me some time to upload the project.

Meanwhile, you can test using the sample snippet provided. You can place the snippet in a Swift framework and import the Swift generated header in another Objective C framework to see the warning.

Looking at the code sample you provided, it looks like you're declaring a second property with the exact same name rather than an actual override, and it's possible that's confusing the compiler?

In my actual code, it is an override. I have updated the snippet I have provided.

There's indeed some unfortunate order that Swift is using when generating obj-c header.

You may workaround it by shuffling the stuff around until the order is good:

@objc class AType1Details: NSObject {}

@objc class Type1: NSObject {
    @objc var details: AType1Details {
        fatalError("placeholder for actual implementation")
    }
}

@objc class AType2Details: AType1Details {}

@objc class Type2: Type1 {
    @objc override var details: AType2Details {
        fatalError("placeholder for actual implementation")
    }
}

or, perhaps the easiest would be to return the same type (i.e. Type1Details) in the overridden details method instead of a subtype (i.e. Type2Details).