github.com/solo-io/cue@v0.4.7/internal/core/subsume/value.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 subsume 16 17 import ( 18 "bytes" 19 20 "github.com/solo-io/cue/cue/errors" 21 "github.com/solo-io/cue/internal/core/adt" 22 ) 23 24 func (s *subsumer) values(a, b adt.Value) (result bool) { 25 defer func() { 26 if !result && s.gt == nil && s.lt == nil { 27 s.gt = a 28 s.lt = b 29 } 30 }() 31 32 if a == b { 33 return true 34 } 35 36 if s.Defaults { 37 b = adt.Default(b) 38 } 39 40 switch b := b.(type) { 41 case *adt.Bottom: 42 // If the value is incomplete, the error is not final. So either check 43 // structural equivalence or return an error. 44 return !b.IsIncomplete() 45 46 case *adt.Vertex: 47 if a, ok := a.(*adt.Vertex); ok { 48 return s.vertices(a, b) 49 } 50 if v, ok := b.BaseValue.(adt.Value); ok { 51 // Safe to ignore arcs of w. 52 return s.values(a, v) 53 } 54 // Check based on first value. 55 56 case *adt.Conjunction: 57 if _, ok := a.(*adt.Conjunction); ok { 58 break 59 } 60 for _, y := range b.Values { 61 if s.values(a, y) { 62 return true 63 } 64 } 65 return false 66 67 case *adt.Disjunction: 68 if _, ok := a.(*adt.Disjunction); ok { 69 break 70 } 71 72 for _, y := range b.Values { 73 if !s.values(a, y) { 74 return false 75 } 76 } 77 return true 78 79 case *adt.NodeLink: 80 // Do not descend into NodeLinks to avoid processing cycles. 81 // TODO: this would work better if all equal nodes shared the same 82 // node link. 83 return deref(a) == deref(b) 84 } 85 86 switch x := a.(type) { 87 case *adt.Top: 88 return true 89 90 case *adt.Bottom: 91 // isBottom(b) was already tested above. 92 return false 93 94 case *adt.BasicType: 95 k := b.Kind() 96 return x.K&k == k 97 98 case *adt.BoundValue: 99 return s.bound(x, b) 100 101 case *adt.Builtin: 102 return x == b 103 104 case *adt.BuiltinValidator: 105 if y := s.ctx.Validate(x, b); y != nil { 106 s.errs = errors.Append(s.errs, y.Err) 107 return false 108 } 109 return true 110 111 case *adt.Null: 112 return b.Kind() == adt.NullKind 113 114 case *adt.Bool: 115 y, ok := b.(*adt.Bool) 116 return ok && x.B == y.B 117 118 case *adt.Num: 119 y, ok := b.(*adt.Num) 120 return ok && x.K&y.K == y.K && test(s.ctx, x, adt.EqualOp, x, y) 121 122 case *adt.String: 123 y, ok := b.(*adt.String) 124 return ok && x.Str == y.Str 125 126 case *adt.Bytes: 127 y, ok := b.(*adt.Bytes) 128 return ok && bytes.Equal(x.B, y.B) 129 130 case *adt.Vertex: 131 y, ok := b.(*adt.Vertex) 132 if ok { 133 return s.vertices(x, y) 134 } 135 136 // TODO: Under what conditions can we cast to the value? 137 if v, _ := x.BaseValue.(adt.Value); v != nil { 138 return s.values(v, b) 139 } 140 return false 141 142 case *adt.Conjunction: 143 if y, ok := b.(*adt.Conjunction); ok { 144 // A Conjunction subsumes another Conjunction if for all values a in 145 // x there is a value b in y such that a subsumes b. 146 // 147 // This assumes overlapping ranges in disjunctions are merged.If 148 // this is not the case, subsumes will return a false negative, 149 // which is allowed. 150 outerC: 151 for _, a := range x.Values { 152 for _, b := range y.Values { 153 if s.values(a, b) { 154 continue outerC 155 } 156 } 157 // TODO: should this be marked as inexact? 158 return false 159 } 160 return true 161 } 162 subsumed := true 163 for _, a := range x.Values { 164 subsumed = subsumed && s.values(a, b) 165 } 166 return subsumed 167 168 case *adt.Disjunction: 169 // A Disjunction subsumes another Disjunction if all values of y are 170 // subsumed by any of the values of x, and default values in y are 171 // subsumed by the default values of x. 172 // 173 // This assumes that overlapping ranges in x are merged. If this is not 174 // the case, subsumes will return a false negative, which is allowed. 175 if y, ok := b.(*adt.Disjunction); ok { 176 // at least one value in x should subsume each value in d. 177 outerD: 178 for i, b := range y.Values { 179 bDefault := i < y.NumDefaults 180 // v is subsumed if any value in x subsumes v. 181 for j, a := range x.Values { 182 aDefault := j < x.NumDefaults 183 if (aDefault || !bDefault) && s.values(a, b) { 184 continue outerD 185 } 186 } 187 return false 188 } 189 return true 190 } 191 // b is subsumed if any value in x subsumes b. 192 for _, a := range x.Values { 193 if s.values(a, b) { 194 return true 195 } 196 } 197 // TODO: should this be marked as inexact? 198 return false 199 200 case *adt.NodeLink: 201 return deref(x) == deref(b) 202 } 203 return false 204 } 205 206 func deref(v adt.Expr) *adt.Vertex { 207 switch x := v.(type) { 208 case *adt.Vertex: 209 return x 210 case *adt.NodeLink: 211 return x.Node 212 } 213 return nil 214 } 215 216 func (s *subsumer) bound(x *adt.BoundValue, v adt.Value) bool { 217 ctx := s.ctx 218 if isBottom(v) { 219 return true 220 } 221 222 switch y := v.(type) { 223 case *adt.BoundValue: 224 if !adt.IsConcrete(y.Value) { 225 return false 226 } 227 228 kx := x.Kind() 229 ky := y.Kind() 230 if (kx&ky)&^kx != 0 { 231 return false 232 } 233 // x subsumes y if 234 // x: >= a, y: >= b ==> a <= b 235 // x: >= a, y: > b ==> a <= b 236 // x: > a, y: > b ==> a <= b 237 // x: > a, y: >= b ==> a < b 238 // 239 // x: <= a, y: <= b ==> a >= b 240 // 241 // x: != a, y: != b ==> a != b 242 // 243 // false if types or op direction doesn't match 244 245 xv := x.Value 246 yv := y.Value 247 switch x.Op { 248 case adt.GreaterThanOp: 249 if y.Op == adt.GreaterEqualOp { 250 return test(ctx, x, adt.LessThanOp, xv, yv) 251 } 252 fallthrough 253 case adt.GreaterEqualOp: 254 if y.Op == adt.GreaterThanOp || y.Op == adt.GreaterEqualOp { 255 return test(ctx, x, adt.LessEqualOp, xv, yv) 256 } 257 case adt.LessThanOp: 258 if y.Op == adt.LessEqualOp { 259 return test(ctx, x, adt.GreaterThanOp, xv, yv) 260 } 261 fallthrough 262 case adt.LessEqualOp: 263 if y.Op == adt.LessThanOp || y.Op == adt.LessEqualOp { 264 return test(ctx, x, adt.GreaterEqualOp, xv, yv) 265 } 266 case adt.NotEqualOp: 267 switch y.Op { 268 case adt.NotEqualOp: 269 return test(ctx, x, adt.EqualOp, xv, yv) 270 case adt.GreaterEqualOp: 271 return test(ctx, x, adt.LessThanOp, xv, yv) 272 case adt.GreaterThanOp: 273 return test(ctx, x, adt.LessEqualOp, xv, yv) 274 case adt.LessThanOp: 275 return test(ctx, x, adt.GreaterEqualOp, xv, yv) 276 case adt.LessEqualOp: 277 return test(ctx, x, adt.GreaterThanOp, xv, yv) 278 } 279 280 case adt.MatchOp, adt.NotMatchOp: 281 // these are just approximations 282 if y.Op == x.Op { 283 return test(ctx, x, adt.EqualOp, xv, yv) 284 } 285 286 default: 287 // adt.NotEqualOp already handled above. 288 panic("cue: undefined bound mode") 289 } 290 291 case *adt.Num, *adt.String, *adt.Bool: 292 return test(ctx, x, x.Op, y, x.Value) 293 } 294 return false 295 } 296 297 func test(ctx *adt.OpContext, src adt.Node, op adt.Op, gt, lt adt.Value) bool { 298 x := adt.BinOp(ctx, op, gt, lt) 299 b, ok := x.(*adt.Bool) 300 return ok && b.B 301 }