cuelang.org/go@v0.10.1/internal/core/adt/equality.go (about) 1 // Copyright 2020 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package adt 16 17 type Flag uint16 18 19 const ( 20 // IgnoreOptional allows optional information to be ignored. This only 21 // applies when CheckStructural is given. 22 IgnoreOptional Flag = 1 << iota 23 24 // CheckStructural indicates that closedness information should be 25 // considered for equality. Equal may return false even when values are 26 // equal. 27 CheckStructural Flag = 1 << iota 28 ) 29 30 func Equal(ctx *OpContext, v, w Value, flags Flag) bool { 31 if x, ok := v.(*Vertex); ok { 32 return equalVertex(ctx, x, w, flags) 33 } 34 if y, ok := w.(*Vertex); ok { 35 return equalVertex(ctx, y, v, flags) 36 } 37 return equalTerminal(ctx, v, w, flags) 38 } 39 40 func equalVertex(ctx *OpContext, x *Vertex, v Value, flags Flag) bool { 41 y, ok := v.(*Vertex) 42 if !ok { 43 return false 44 } 45 46 // Note that the arc type of an originating node may be different than 47 // the one we are sharing. So do this check before dereferencing. 48 // For instance: 49 // 50 // a?: #B // ArcOptional 51 // #B: {} // ArcMember 52 if x.ArcType != y.ArcType { 53 return false 54 } 55 56 x = x.DerefValue() 57 y = y.DerefValue() 58 59 if x == y { 60 return true 61 } 62 63 xk := x.Kind() 64 yk := y.Kind() 65 66 if xk != yk { 67 return false 68 } 69 70 maxArcType := ArcMember 71 if flags&CheckStructural != 0 { 72 // Do not ignore optional fields 73 // TODO(required): consider making this unconditional 74 maxArcType = ArcOptional 75 } 76 77 // TODO: this really should be subsumption. 78 if flags != 0 { 79 if x.IsClosedStruct() != y.IsClosedStruct() { 80 return false 81 } 82 if x.IsClosedList() != y.IsClosedList() { 83 return false 84 } 85 if !equalClosed(ctx, x, y, flags) { 86 return false 87 } 88 } 89 90 loop1: 91 for _, a := range x.Arcs { 92 if a.ArcType > maxArcType { 93 continue 94 } 95 for _, b := range y.Arcs { 96 if a.Label == b.Label { 97 if a.ArcType != b.ArcType || !Equal(ctx, a, b, flags) { 98 return false 99 } 100 continue loop1 101 } 102 } 103 return false 104 } 105 106 loop2: 107 for _, b := range y.Arcs { 108 if b.ArcType > maxArcType { 109 continue 110 } 111 for _, a := range x.Arcs { 112 if a.Label == b.Label { 113 if a.ArcType > maxArcType { 114 // No need to continue: arc with label not found. 115 break 116 } 117 // Label found. Equality was already tested in loop 1. 118 continue loop2 119 } 120 } 121 // Arc with same label not found. 122 return false 123 } 124 125 v, ok1 := x.BaseValue.(Value) 126 w, ok2 := y.BaseValue.(Value) 127 if !ok1 && !ok2 { 128 return true // both are struct or list. 129 } 130 131 return equalTerminal(ctx, v, w, flags) 132 } 133 134 // equalClosed tests if x and y have the same set of close information. 135 // TODO: the following refinements are possible: 136 // - unify optional fields and equate the optional fields 137 // - do the same for pattern constraints, where the pattern constraints 138 // are collated by pattern equality. 139 // - a further refinement would collate patterns by ranges. 140 // 141 // For all these refinements it would be necessary to have well-working 142 // structure sharing so as to not repeatedly recompute optional arcs. 143 func equalClosed(ctx *OpContext, x, y *Vertex, flags Flag) bool { 144 return verifyStructs(x, y, flags) && verifyStructs(y, x, flags) 145 } 146 147 func verifyStructs(x, y *Vertex, flags Flag) bool { 148 outer: 149 for _, s := range x.Structs { 150 if (flags&IgnoreOptional != 0) && !s.StructLit.HasOptional() { 151 continue 152 } 153 if s.span()&DefinitionSpan == 0 { 154 if !s.StructLit.HasOptional() { 155 continue 156 } 157 } 158 for _, t := range y.Structs { 159 if s.StructLit == t.StructLit { 160 continue outer 161 } 162 } 163 return false 164 } 165 return true 166 } 167 168 func equalTerminal(ctx *OpContext, v, w Value, flags Flag) bool { 169 if v == w { 170 return true 171 } 172 173 switch x := v.(type) { 174 case *Bottom: 175 // All errors are logically the same. 176 _, ok := w.(*Bottom) 177 return ok 178 179 case *Top: 180 _, ok := w.(*Top) 181 return ok 182 183 case *Num, *String, *Bool, *Bytes, *Null: 184 if b, ok := BinOp(ctx, EqualOp, v, w).(*Bool); ok { 185 return b.B 186 } 187 return false 188 189 // TODO: for the remainder we are dealing with non-concrete values, so we 190 // could also just not bother. 191 192 case *BoundValue: 193 if y, ok := w.(*BoundValue); ok { 194 return x.Op == y.Op && Equal(ctx, x.Value, y.Value, flags) 195 } 196 197 case *BasicType: 198 if y, ok := w.(*BasicType); ok { 199 return x.K == y.K 200 } 201 202 case *Conjunction: 203 y, ok := w.(*Conjunction) 204 if !ok || len(x.Values) != len(y.Values) { 205 return false 206 } 207 // always ordered the same 208 for i, xe := range x.Values { 209 if !Equal(ctx, xe, y.Values[i], flags) { 210 return false 211 } 212 } 213 return true 214 215 case *Disjunction: 216 // The best way to compute this is with subsumption, but even that won't 217 // be too accurate. Assume structural equivalence for now. 218 y, ok := w.(*Disjunction) 219 if !ok || len(x.Values) != len(y.Values) { 220 return false 221 } 222 for i, xe := range x.Values { 223 if !Equal(ctx, xe, y.Values[i], flags) { 224 return false 225 } 226 } 227 return true 228 229 case *BuiltinValidator: 230 } 231 232 return false 233 }