cuelang.org/go@v0.10.1/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 "cuelang.org/go/cue/errors" 21 "cuelang.org/go/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 state := s.ctx.PushState(s.ctx.Env(0), b.Source()) 106 b1 := s.ctx.Validate(x, b) 107 if b1 != nil { 108 s.errs = errors.Append(s.errs, b1.Err) 109 } 110 b2 := s.ctx.PopState(state) 111 if b2 != nil { 112 s.errs = errors.Append(s.errs, b2.Err) 113 } 114 return b1 == nil && b2 == nil 115 116 case *adt.Null: 117 return b.Kind() == adt.NullKind 118 119 case *adt.Bool: 120 y, ok := b.(*adt.Bool) 121 return ok && x.B == y.B 122 123 case *adt.Num: 124 y, ok := b.(*adt.Num) 125 return ok && x.K&y.K == y.K && test(s.ctx, x, adt.EqualOp, x, y) 126 127 case *adt.String: 128 y, ok := b.(*adt.String) 129 return ok && x.Str == y.Str 130 131 case *adt.Bytes: 132 y, ok := b.(*adt.Bytes) 133 return ok && bytes.Equal(x.B, y.B) 134 135 case *adt.Vertex: 136 y, ok := b.(*adt.Vertex) 137 if ok { 138 return s.vertices(x, y) 139 } 140 141 // TODO: Under what conditions can we cast to the value? 142 if v, _ := x.BaseValue.(adt.Value); v != nil { 143 return s.values(v, b) 144 } 145 return false 146 147 case *adt.Conjunction: 148 if y, ok := b.(*adt.Conjunction); ok { 149 // A Conjunction subsumes another Conjunction if for all values a in 150 // x there is a value b in y such that a subsumes b. 151 // 152 // This assumes overlapping ranges in disjunctions are merged.If 153 // this is not the case, subsumes will return a false negative, 154 // which is allowed. 155 outerC: 156 for _, a := range x.Values { 157 for _, b := range y.Values { 158 if s.values(a, b) { 159 continue outerC 160 } 161 } 162 // TODO: should this be marked as inexact? 163 return false 164 } 165 return true 166 } 167 subsumed := true 168 for _, a := range x.Values { 169 subsumed = subsumed && s.values(a, b) 170 } 171 return subsumed 172 173 case *adt.Disjunction: 174 175 if s.LeftDefault { 176 a = adt.Default(a) 177 var ok bool 178 x, ok = a.(*adt.Disjunction) 179 if !ok { 180 return s.values(a, b) 181 } 182 } 183 184 // A Disjunction subsumes another Disjunction if all values of y are 185 // subsumed by any of the values of x, and default values in y are 186 // subsumed by the default values of x. 187 // 188 // This assumes that overlapping ranges in x are merged. If this is not 189 // the case, subsumes will return a false negative, which is allowed. 190 if y, ok := b.(*adt.Disjunction); ok { 191 // at least one value in x should subsume each value in d. 192 outerD: 193 for i, b := range y.Values { 194 bDefault := i < y.NumDefaults 195 // v is subsumed if any value in x subsumes v. 196 for j, a := range x.Values { 197 aDefault := j < x.NumDefaults 198 if (aDefault || !bDefault) && s.values(a, b) { 199 continue outerD 200 } 201 } 202 return false 203 } 204 return true 205 } 206 // b is subsumed if any value in x subsumes b. 207 for _, a := range x.Values { 208 if s.values(a, b) { 209 return true 210 } 211 } 212 // TODO: should this be marked as inexact? 213 return false 214 215 case *adt.NodeLink: 216 return deref(x) == deref(b) 217 } 218 return false 219 } 220 221 func deref(v adt.Expr) *adt.Vertex { 222 switch x := v.(type) { 223 case *adt.Vertex: 224 return x 225 case *adt.NodeLink: 226 return x.Node 227 } 228 return nil 229 } 230 231 func (s *subsumer) bound(x *adt.BoundValue, v adt.Value) bool { 232 ctx := s.ctx 233 if isBottom(v) { 234 return true 235 } 236 237 switch y := v.(type) { 238 case *adt.BoundValue: 239 if !adt.IsConcrete(y.Value) { 240 return false 241 } 242 243 kx := x.Kind() 244 ky := y.Kind() 245 if (kx&ky)&^kx != 0 { 246 return false 247 } 248 // x subsumes y if 249 // x: >= a, y: >= b ==> a <= b 250 // x: >= a, y: > b ==> a <= b 251 // x: > a, y: > b ==> a <= b 252 // x: > a, y: >= b ==> a < b 253 // 254 // x: <= a, y: <= b ==> a >= b 255 // 256 // x: != a, y: != b ==> a != b 257 // 258 // false if types or op direction doesn't match 259 260 xv := x.Value 261 yv := y.Value 262 switch x.Op { 263 case adt.GreaterThanOp: 264 if y.Op == adt.GreaterEqualOp { 265 return test(ctx, x, adt.LessThanOp, xv, yv) 266 } 267 fallthrough 268 case adt.GreaterEqualOp: 269 if y.Op == adt.GreaterThanOp || y.Op == adt.GreaterEqualOp { 270 return test(ctx, x, adt.LessEqualOp, xv, yv) 271 } 272 case adt.LessThanOp: 273 if y.Op == adt.LessEqualOp { 274 return test(ctx, x, adt.GreaterThanOp, xv, yv) 275 } 276 fallthrough 277 case adt.LessEqualOp: 278 if y.Op == adt.LessThanOp || y.Op == adt.LessEqualOp { 279 return test(ctx, x, adt.GreaterEqualOp, xv, yv) 280 } 281 case adt.NotEqualOp: 282 switch y.Op { 283 case adt.NotEqualOp: 284 return test(ctx, x, adt.EqualOp, xv, yv) 285 case adt.GreaterEqualOp: 286 return test(ctx, x, adt.LessThanOp, xv, yv) 287 case adt.GreaterThanOp: 288 return test(ctx, x, adt.LessEqualOp, xv, yv) 289 case adt.LessThanOp: 290 return test(ctx, x, adt.GreaterEqualOp, xv, yv) 291 case adt.LessEqualOp: 292 return test(ctx, x, adt.GreaterThanOp, xv, yv) 293 } 294 295 case adt.MatchOp, adt.NotMatchOp: 296 // these are just approximations 297 if y.Op == x.Op { 298 return test(ctx, x, adt.EqualOp, xv, yv) 299 } 300 301 default: 302 // adt.NotEqualOp already handled above. 303 panic("cue: undefined bound mode") 304 } 305 306 case *adt.Num, *adt.String, *adt.Bool: 307 return test(ctx, x, x.Op, y, x.Value) 308 } 309 return false 310 } 311 312 func test(ctx *adt.OpContext, src adt.Node, op adt.Op, gt, lt adt.Value) bool { 313 x := adt.BinOp(ctx, op, gt, lt) 314 b, ok := x.(*adt.Bool) 315 return ok && b.B 316 }