]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame - vendor/github.com/zclconf/go-cty/cty/convert/compare_types.go
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / zclconf / go-cty / cty / convert / compare_types.go
CommitLineData
15c0b25d
AP
1package convert
2
3import (
4 "github.com/zclconf/go-cty/cty"
5)
6
7// compareTypes implements a preference order for unification.
8//
9// The result of this method is not useful for anything other than unification
10// preferences, since it assumes that the caller will verify that any suggested
11// conversion is actually possible and it is thus able to to make certain
12// optimistic assumptions.
13func compareTypes(a cty.Type, b cty.Type) int {
14
15 // DynamicPseudoType always has lowest preference, because anything can
16 // convert to it (it acts as a placeholder for "any type") and we want
17 // to optimistically assume that any dynamics will converge on matching
18 // their neighbors.
19 if a == cty.DynamicPseudoType || b == cty.DynamicPseudoType {
20 if a != cty.DynamicPseudoType {
21 return -1
22 }
23 if b != cty.DynamicPseudoType {
24 return 1
25 }
26 return 0
27 }
28
29 if a.IsPrimitiveType() && b.IsPrimitiveType() {
30 // String is a supertype of all primitive types, because we can
31 // represent all primitive values as specially-formatted strings.
32 if a == cty.String || b == cty.String {
33 if a != cty.String {
34 return 1
35 }
36 if b != cty.String {
37 return -1
38 }
39 return 0
40 }
41 }
42
43 if a.IsListType() && b.IsListType() {
44 return compareTypes(a.ElementType(), b.ElementType())
45 }
46 if a.IsSetType() && b.IsSetType() {
47 return compareTypes(a.ElementType(), b.ElementType())
48 }
49 if a.IsMapType() && b.IsMapType() {
50 return compareTypes(a.ElementType(), b.ElementType())
51 }
52
53 // From this point on we may have swapped the two items in order to
54 // simplify our cases. Therefore any non-zero return after this point
55 // must be multiplied by "swap" to potentially invert the return value
56 // if needed.
57 swap := 1
58 switch {
59 case a.IsTupleType() && b.IsListType():
60 fallthrough
61 case a.IsObjectType() && b.IsMapType():
62 fallthrough
63 case a.IsSetType() && b.IsTupleType():
64 fallthrough
65 case a.IsSetType() && b.IsListType():
66 a, b = b, a
67 swap = -1
68 }
69
70 if b.IsSetType() && (a.IsTupleType() || a.IsListType()) {
71 // We'll just optimistically assume that the element types are
72 // unifyable/convertible, and let a second recursive pass
73 // figure out how to make that so.
74 return -1 * swap
75 }
76
77 if a.IsListType() && b.IsTupleType() {
78 // We'll just optimistically assume that the tuple's element types
79 // can be unified into something compatible with the list's element
80 // type.
81 return -1 * swap
82 }
83
84 if a.IsMapType() && b.IsObjectType() {
85 // We'll just optimistically assume that the object's attribute types
86 // can be unified into something compatible with the map's element
87 // type.
88 return -1 * swap
89 }
90
91 // For object and tuple types, comparing two types doesn't really tell
92 // the whole story because it may be possible to construct a new type C
93 // that is the supertype of both A and B by unifying each attribute/element
94 // separately. That possibility is handled by Unify as a follow-up if
95 // type sorting is insufficient to produce a valid result.
96 //
97 // Here we will take care of the simple possibilities where no new type
98 // is needed.
99 if a.IsObjectType() && b.IsObjectType() {
100 atysA := a.AttributeTypes()
101 atysB := b.AttributeTypes()
102
103 if len(atysA) != len(atysB) {
104 return 0
105 }
106
107 hasASuper := false
108 hasBSuper := false
109 for k := range atysA {
110 if _, has := atysB[k]; !has {
111 return 0
112 }
113
114 cmp := compareTypes(atysA[k], atysB[k])
115 if cmp < 0 {
116 hasASuper = true
117 } else if cmp > 0 {
118 hasBSuper = true
119 }
120 }
121
122 switch {
123 case hasASuper && hasBSuper:
124 return 0
125 case hasASuper:
126 return -1 * swap
127 case hasBSuper:
128 return 1 * swap
129 default:
130 return 0
131 }
132 }
133 if a.IsTupleType() && b.IsTupleType() {
134 etysA := a.TupleElementTypes()
135 etysB := b.TupleElementTypes()
136
137 if len(etysA) != len(etysB) {
138 return 0
139 }
140
141 hasASuper := false
142 hasBSuper := false
143 for i := range etysA {
144 cmp := compareTypes(etysA[i], etysB[i])
145 if cmp < 0 {
146 hasASuper = true
147 } else if cmp > 0 {
148 hasBSuper = true
149 }
150 }
151
152 switch {
153 case hasASuper && hasBSuper:
154 return 0
155 case hasASuper:
156 return -1 * swap
157 case hasBSuper:
158 return 1 * swap
159 default:
160 return 0
161 }
162 }
163
164 return 0
165}