cuelang.org/go@v0.13.0/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 28 29 // RegularOnly indicates that only regular fields should be considered, 30 // thus excluding hidden and definition fields. 31 RegularOnly 32 ) 33 34 func Equal(ctx *OpContext, v, w Value, flags Flag) bool { 35 if x, ok := v.(*Vertex); ok { 36 return equalVertex(ctx, x, w, flags) 37 } 38 if y, ok := w.(*Vertex); ok { 39 return equalVertex(ctx, y, v, flags) 40 } 41 return equalTerminal(ctx, v, w, flags) 42 } 43 44 func equalVertex(ctx *OpContext, x *Vertex, v Value, flags Flag) bool { 45 y, ok := v.(*Vertex) 46 if !ok { 47 return false 48 } 49 50 // Note that the arc type of an originating node may be different than 51 // the one we are sharing. So do this check before dereferencing. 52 // For instance: 53 // 54 // a?: #B // ArcOptional 55 // #B: {} // ArcMember 56 if x.ArcType != y.ArcType { 57 return false 58 } 59 60 x = x.DerefValue() 61 y = y.DerefValue() 62 63 if x == y { 64 return true 65 } 66 67 xk := x.Kind() 68 yk := y.Kind() 69 70 if xk != yk { 71 return false 72 } 73 74 maxArcType := ArcMember 75 if flags&CheckStructural != 0 { 76 // Do not ignore optional fields 77 // TODO(required): consider making this unconditional 78 maxArcType = ArcOptional 79 } 80 81 // TODO: this really should be subsumption. 82 if flags != 0 { 83 if x.IsClosedStruct() != y.IsClosedStruct() { 84 return false 85 } 86 if x.IsClosedList() != y.IsClosedList() { 87 return false 88 } 89 if !equalClosed(ctx, x, y, flags) { 90 return false 91 } 92 } 93 94 skipRegular := flags&RegularOnly != 0 95 96 loop1: 97 for _, a := range x.Arcs { 98 if (skipRegular && !a.Label.IsRegular()) || a.ArcType > maxArcType { 99 continue 100 } 101 for _, b := range y.Arcs { 102 if a.Label == b.Label { 103 if a.ArcType != b.ArcType || !Equal(ctx, a, b, flags) { 104 return false 105 } 106 continue loop1 107 } 108 } 109 return false 110 } 111 112 loop2: 113 for _, b := range y.Arcs { 114 if (skipRegular && !b.Label.IsRegular()) || b.ArcType > maxArcType { 115 continue 116 } 117 for _, a := range x.Arcs { 118 if a.Label == b.Label { 119 if a.ArcType > maxArcType { 120 // No need to continue: arc with label not found. 121 break 122 } 123 // Label found. Equality was already tested in loop 1. 124 continue loop2 125 } 126 } 127 // Arc with same label not found. 128 return false 129 } 130 131 v, ok1 := x.BaseValue.(Value) 132 w, ok2 := y.BaseValue.(Value) 133 if !ok1 && !ok2 { 134 return true // both are struct or list. 135 } 136 137 return equalTerminal(ctx, v, w, flags) 138 } 139 140 // equalClosed tests if x and y have the same set of close information. 141 // TODO: the following refinements are possible: 142 // - unify optional fields and equate the optional fields 143 // - do the same for pattern constraints, where the pattern constraints 144 // are collated by pattern equality. 145 // - a further refinement would collate patterns by ranges. 146 // 147 // For all these refinements it would be necessary to have well-working 148 // structure sharing so as to not repeatedly recompute optional arcs. 149 func equalClosed(ctx *OpContext, x, y *Vertex, flags Flag) bool { 150 return verifyStructs(x, y, flags) && verifyStructs(y, x, flags) 151 } 152 153 func verifyStructs(x, y *Vertex, flags Flag) bool { 154 outer: 155 for _, s := range x.Structs { 156 if (flags&IgnoreOptional != 0) && !s.StructLit.HasOptional() { 157 continue 158 } 159 if s.span()&DefinitionSpan == 0 { 160 if !s.StructLit.HasOptional() { 161 continue 162 } 163 } 164 for _, t := range y.Structs { 165 if s.StructLit == t.StructLit { 166 continue outer 167 } 168 } 169 return false 170 } 171 return true 172 } 173 174 func equalTerminal(ctx *OpContext, v, w Value, flags Flag) bool { 175 if v == w { 176 return true 177 } 178 179 switch x := v.(type) { 180 case *Bottom: 181 // All errors are logically the same. 182 _, ok := w.(*Bottom) 183 return ok 184 185 case *Top: 186 _, ok := w.(*Top) 187 return ok 188 189 case *Num, *String, *Bool, *Bytes, *Null: 190 if b, ok := BinOp(ctx, EqualOp, v, w).(*Bool); ok { 191 return b.B 192 } 193 return false 194 195 // TODO: for the remainder we are dealing with non-concrete values, so we 196 // could also just not bother. 197 198 case *BoundValue: 199 if y, ok := w.(*BoundValue); ok { 200 return x.Op == y.Op && Equal(ctx, x.Value, y.Value, flags) 201 } 202 203 case *BasicType: 204 if y, ok := w.(*BasicType); ok { 205 return x.K == y.K 206 } 207 208 case *Conjunction: 209 y, ok := w.(*Conjunction) 210 if !ok || len(x.Values) != len(y.Values) { 211 return false 212 } 213 // always ordered the same 214 for i, xe := range x.Values { 215 if !Equal(ctx, xe, y.Values[i], flags) { 216 return false 217 } 218 } 219 return true 220 221 case *Disjunction: 222 // The best way to compute this is with subsumption, but even that won't 223 // be too accurate. Assume structural equivalence for now. 224 y, ok := w.(*Disjunction) 225 if !ok || len(x.Values) != len(y.Values) { 226 return false 227 } 228 for i, xe := range x.Values { 229 if !Equal(ctx, xe, y.Values[i], flags) { 230 return false 231 } 232 } 233 return true 234 235 case *BuiltinValidator: 236 } 237 238 return false 239 }