Senocico Stelian
Senocico Stelian

Reputation: 1697

Overridden method has generic signature which is incompatible with base method's generic signature

I just updated to Xcode 11.4. I'm receiving the following error:

Overridden method 'equals' has generic signature <T where T : Gradient> which is incompatible with base method's generic signature <T where T : Fill>; expected generic signature to be <T where T : Fill>

enter image description here

class Fill: Equatable {
    func equals<T>(other: T) -> Bool where T: Fill { }
}

func ==<T> (lhs: T, rhs: T) -> Bool where T: Fill {
    return lhs.equals(other: rhs)
}

class Gradient: Fill {
    override func equals<T>(other: T) -> Bool where T: Gradient { }
}

How this changed?

Upvotes: 1

Views: 980

Answers (3)

Suyash Srijan
Suyash Srijan

Reputation: 719

The reason why you cannot change constraints like that is because doing so would violate Liskov substitution principle. The compiler has never checked the generic signature of overridden functions and this led to various runtime crashes, so I implemented this error in the Swift 5.2 compiler.

Let's take a look at your own example to understand what's wrong. One can write the following code:

let fill1: Fill = Fill()
let fill2: Fill = Gradient()
let isEqual = fill2.equals(other: fill1)

This is not correct, because Gradient.equals(other:) requires other to inherit from Gradient. However, because fill2 has a static type of Fill, I am able to bypass that constraint and pass a value of type Fill instead.

If Gradient.equals(other:) tries to access a property or a function on other which only exists on an instance of Gradient, your code would simply crash on runtime, because that property or function wouldn't be available on Fill:

class Fill: Equatable {
  func equals<T>(other: T) -> Bool where T: Fill { ... }
}

class Gradient: Fill {
  private(set) var id: String = UUID().uuidString
  override func equals<T>(other: T) -> Bool where T: Gradient {
    return id == other.id // crash if `other` is value of type `Fill`
  }
}

So, the compiler now prohibits you from adding incompatible constraints when overriding a function.

Now, there are basically two ways to fix the problem - change your code and avoid adding incompatible constraints in the overridden function or do a runtime check in the overridden function using as? or type(of:) to check if the passed value indeed satisfies the new constraints and then try using it:

override func equals<T>(other: T) -> Bool where T: Gradient {
  if type(of: other) == Fill.self { return false }
  return id == other.id // okay
}

Upvotes: 0

ProgrammingProton
ProgrammingProton

Reputation: 39

In my case I just fix this error by this:-

override func equals<T>(other: T) -> Bool where T: Fill {
    guard let other = other as? Gradient else { 
        return false 
    }
    ...
}

But there are some similar errors of Macaw, So just replace Gradient with your error issue and it fix.

Upvotes: 0

Andrew Kochulab
Andrew Kochulab

Reputation: 325

Please look at this thread https://forums.swift.org/t/method-override-with-a-generic-signature-with-requirements-not-imposed-by-the-base-method/33593

This compilation error prevents you from future crashes.

Upvotes: 1

Related Questions