package convert import ( "github.com/hashicorp/go-cty/cty" ) // sortTypes produces an ordering of the given types that serves as a // preference order for the result of unification of the given types. // The return value is a slice of indices into the given slice, and will // thus always be the same length as the given slice. // // The goal is that the most general of the given types will appear first // in the ordering. If there are uncomparable pairs of types in the list // then they will appear in an undefined order, and the unification pass // will presumably then fail. func sortTypes(tys []cty.Type) []int { l := len(tys) // First we build a graph whose edges represent "more general than", // which we will then do a topological sort of. edges := make([][]int, l) for i := 0; i < (l - 1); i++ { for j := i + 1; j < l; j++ { cmp := compareTypes(tys[i], tys[j]) switch { case cmp < 0: edges[i] = append(edges[i], j) case cmp > 0: edges[j] = append(edges[j], i) } } } // Compute the in-degree of each node inDegree := make([]int, l) for _, outs := range edges { for _, j := range outs { inDegree[j]++ } } // The array backing our result will double as our queue for visiting // the nodes, with the queue slice moving along this array until it // is empty and positioned at the end of the array. Thus our visiting // order is also our result order. result := make([]int, l) queue := result[0:0] // Initialize the queue with any item of in-degree 0, preserving // their relative order. for i, n := range inDegree { if n == 0 { queue = append(queue, i) } } for len(queue) != 0 { i := queue[0] queue = queue[1:] for _, j := range edges[i] { inDegree[j]-- if inDegree[j] == 0 { queue = append(queue, j) } } } return result }