Search code examples
swiftgenericsrecursiontypes

How can I fix an error the error `Cannot build rewrite system for generic signature; rule length limit exceeded` in swift?


I'm pretty sure it's a recursive error, it's Cannot build rewrite system for generic signature; rule length limit exceeded, and it occurs because of this bits of my code.

extension GenericBuilder where T == SomeUseCase<T.AssociatedEntity> { // <- Error here on this line.
    // Do thing, no errors here
}

struct SomeUseCase<T: Entity>: Model {
    typealias AssociatedEntity = T
    // Do thing, no errors here
}

protocol Entity: Model {
    // Do thing, no errors here
}

protocol Model: Equatable, Hashable, Codable {
    /// The entity associated with that specific model.
    associatedtype AssociatedEntity: Entity

    // Do thing, no errors here
}

I'm not really sure how to approach this, I want the GenericBuilder to have a function only when it's associatedType T is of type SomeUseCase regardless of the associated entity. I don't want to list out an extension for the GenericBuilder for every possible entity that could be used. I was hoping that by adding an AssociatedEntity to the Model, I could just pass the type in, but now it blows up.

If I switch to using a protocol for type T in the GenericBuilder, it tells me that any SomeProtocol doesn't conform to Codable, Hashable, or Equatable, which it doesn't, specific implementations do, but I want it to work for every version of this.

Any advice?


Solution

  • Instead of writing the constraint in the extension declaration, you can write the constraint in each of methods that you are going to write in the extension. This way, you can introduce another type parameter U, which resolves this recursive constraint problem.

    Assuming GenericBuilder is:

    protocol GenericBuilder {
        associatedtype T: Model
    }
    

    You can write the extension like this:

    extension GenericBuilder {
        func foo<U: Entity>() where 
            T == SomeUseCase<U>,
            U.AssociatedEntity == T.AssociatedEntity {
            
        }
    }
    

    This won't work for properties, but properties can be easily rewritten as a getter (and setter) function, unless you need to get KeyPaths from those properties.