Marco Speziali
Marco Speziali

Reputation: 170

Command failed due to signal: Segmentation fault: 11 after using generics in graph classes - swift3

I was trying to create a generic Graph structure in swift 3. The problem is that the compiler fails with the following message:

While emitting IR SIL function ... for 'init' at .../Graph.swift:48:21

The line the compiler points at is the init method of Edge class:

public class Edge<T: Hashable, V: Vertex<T>> {
    public var source: V
    public var destination: V
    public let weight: Double?

    required public init(source: V, destination: V, weight: Double? = nil) {
        self.source = source
        self.destination = destination
        self.weight = weight
    }
}

I think I might be a problem with the usage of generics. Here are the classes involved:

public class Vertex<T: Hashable> {
    var data: T

    required public init(data: T) {
        self.data = data
    }
}

extension Vertex: Hashable {
    public var hashValue: Int {
        return "\(data)".hashValue
    }

    static public func ==(lhs: Vertex, rhs: Vertex) -> Bool {
        return lhs.data == rhs.data
    }
}

extension Vertex: CustomStringConvertible {
    public var description: String {
        return "\(data)"
    }
}

// MARK: - Edge

public enum EdgeType {
    case directed, undirected
}

public class Edge<T: Hashable, V: Vertex<T>> {
    public var source: V
    public var destination: V
    public let weight: Double?

    required public init(source: V, destination: V, weight: Double? = nil) {
        self.source = source
        self.destination = destination
        self.weight = weight
    }
}

extension Edge: Hashable {
    public var hashValue: Int {
        return "\(source)\(destination)\(weight)".hashValue
    }

    // We need to overload the equals operator because Hashable implements Equatable
    static public func ==(lhs: Edge<T, V>, rhs: Edge<T, V>) -> Bool {
        return lhs.source == rhs.source && lhs.destination == rhs.destination && lhs.weight == rhs.weight
    }
}

Those two classes are used by a generic AdjacencyList<T: Hashable, V: Vertex<T>, E: Edge<T, V>>

Thank you

Upvotes: 1

Views: 237

Answers (1)

Alexey Matjuk
Alexey Matjuk

Reputation: 4301

Can't tell you why your code is crashing. You'd better send a bug report for this issue. But I have a workaround for you:

public protocol VertexType: Hashable {
    associatedtype DataType
    var data: DataType { get set }
}

public class Vertex<T: Hashable>: VertexType {
    public var data: T

    required public init(data: T) {
        self.data = data
    }
}

extension Vertex {
    public var hashValue: Int {
        return "\(data)".hashValue
    }

    static public func ==(lhs: Vertex, rhs: Vertex) -> Bool {
        return lhs.data == rhs.data
    }
}

extension Vertex: CustomStringConvertible {
    public var description: String {
        return "\(data)"
    }
}

// MARK: - Edge

public class Edge<V: VertexType> {
    public var source: V
    public var destination: V
    public let weight: Double?

    required public init(source: V, destination: V, weight: Double? = nil) {
        self.source = source
        self.destination = destination
        self.weight = weight
    }
}

extension Edge: Hashable {
    public var hashValue: Int {
        return "\(source)\(destination)\(weight)".hashValue
    }

    // We need to overload the equals operator because Hashable implements Equatable
    static public func ==(lhs: Edge<V>, rhs: Edge<V>) -> Bool {
        return lhs.source == rhs.source && lhs.destination == rhs.destination && lhs.weight == rhs.weight
    }
}

And now you can use Vertex subclasses as you wanted:

public class IntVertex: Vertex<Int> {}

Edge(source: IntVertex(data: 1), destination: IntVertex(data: 2))

UPDATE:

Looks like this was fixed in Swift 3.1. At least similar bug not crashing Xcode 8.3 anymore. So probably it will be enough to update your Xcode.

Upvotes: 1

Related Questions