Protocol conformance stopped working in Xcode 13

All right, so there's a few things I can help with here. I could just tell you straight-up what you need to do to fix this error, but I'm going to try to do you one better by teaching you the skills you'll need to understand and address the problem yourself going forward, step by step.


First, how do you understand the error you've been given? Notice that there's a series of error messages that look similar and complain about the same missing requirement, but that not all of them refer to RangeReplaceableCollection.

Yes, Swift could certainly do much better in this respect—you can file a bug if you'd like—but for your part you can try to figure out which protocol is really at issue here by searching for the least refined in the hierarchy.

In this case, you'll notice that there's also an error message saying that you didn't satisfy a requirement of Collection. That's helpful: if you had nothing else to go on, you could then go through the requirements of Collection one-by-one and find your answer that way.


Second, what's the protocol requirement that's missing? When there's a lot of errors, sometimes you don't notice the notes that go with the errors, perhaps because the IDE makes them less noticeable. You can reduce the file further, as you allude to—but how?

Well, a common style that people adopt for Swift conformances is to add them one-by-one in extensions. This isn't just an arbitrary choice. When you adopt conformances in that way, you can ensure that your protocol fully conforms to the requirements of the least refined protocol (here, Collection) before you build up conformance to the next protocol in the hierarchy. If you've missed a step, you'll notice right then and there, instead of having to sort through multiple problematic protocols.

Here, you can go back and do something like that by taking the first type that's causing problems and conforming it to the least refined protocol that's causing problems. That is, _ListSlice conforming to Collection. Of course, if we delete all the other types, we'll need to substitute something for your use of List<Element> in _ListSlice, but fortunately just using Array will do. So here's my reduced version of your reduced version:

public struct _ListSlice<Element>: Collection {
  public typealias Index = Int
  public typealias SubSequence = _ListSlice<Element>

  let list: [Element]
  let range: Range<Int>

  public var startIndex: Int {
    return range.startIndex
  }

  public var endIndex: Int {
    return range.endIndex
  }

  public subscript(position: Int) -> Element {
    get { return list[position] }
  }

  public func index(after i: Int) -> Int {
    return list.index(after: i)
  }

  public init() {
    self.list = []
    self.range = 0..<0
  }
}

You'll see that it still presents you with the same error regarding your protocol conformance. So we can figure out the rest using this reduced version. Inspect the diagnostics you now get:

error: ConformancePlayground.playground:1:15: error: type '_ListSlice<Element>' does not conform to protocol 'Collection'
public struct _ListSlice<Element>: Collection {
              ^

error: ConformancePlayground.playground:1:15: error: unavailable subscript 'subscript(_:)' was used to satisfy a requirement of protocol 'Collection'
public struct _ListSlice<Element>: Collection {
              ^

Swift.Collection:3:12: note: 'subscript(_:)' declared here
    public subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get }
           ^

Swift.Collection:12:5: note: requirement 'subscript(_:)' declared here
    subscript(bounds: Range<Self.Index>) -> Self.SubSequence { get }
    ^

Aha! Now we can clearly see not only the protocol that's problematic, but the specific requirement that's missing. Your type was relying on a default implementation of subscript(bounds: Range<Self.Index) -> Self.SubSequence, but that implementation has been marked as unavailable.

You can now stop here and just implement this requirement. But you seem to be the curious type—so, how do we figure out why this requirement isn't fulfilled already, and why was it fulfilled before? Read on...


There can't be a more authoritative source for the requirement than the source itself! Indeed, the diagnostics even reference the standard library source code. Fortunately, the standard library is part of an open source project, and we can open up the referenced source file itself—in this case, Collection.swift.

Now, what are we looking for here?

Well, it's unlikely we'll find much that we don't already know by examining the requirement declaration itself, but you can certainly find it in that file.

But we already know that there's some default requirement that's declared unavailable which you've unintentionally relied on—so let's look for that to see if there's some explanation of the unavailability. While we're here, let's also see if there's some other default implementation that's available (since after all, many people conform to Collection without implementing their own version of that subscript).

Here's what we find:

First, there is this default implementation for conforming types where SubSequence == Slice<Self>. So that explains why most people don't need to write their own implementation, but why you do: you've declared a different SubSequence type (namely, Self). That solves that mystery.

Next, there is the following default implementation for all other conforming types, and it contains a note explaining exactly why it's there and why it's unavailable:

extension Collection {
  // This unavailable default implementation of `subscript(bounds: Range<_>)`
  // prevents incomplete Collection implementations from satisfying the
  // protocol through the use of the generic convenience implementation
  // `subscript<R: RangeExpression>(r: R)`. If that were the case, at
  // runtime the generic implementation would call itself
  // in an infinite recursion because of the absence of a better option.
  @available(*, unavailable)
  @_alwaysEmitIntoClient
  public subscript(bounds: Range<Index>) -> SubSequence { fatalError() }
}

And if you use the "blame" function (either on GitHub or in your local copy of the repository), you can see that this code was added 4 months ago. Aha. Now we have the complete picture:

  • Your implementation used to compile just fine only because Swift allowed you to use a default implementation of a Collection requirement that calls itself, infinitely recursing—if users of your type actually tried to call that method, bad things would happen at runtime.
  • In the last few months, we've figured out a way to teach the Swift compiler to call out this problem at compile time. And thanks to that, you've now found a latent bug in your code, and you're now all set to fix it!

Hope this helps.

56 Likes