cuelang.org/go@v0.10.1/internal/core/subsume/vertex.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 "fmt" 19 20 "cuelang.org/go/internal" 21 "cuelang.org/go/internal/core/adt" 22 "cuelang.org/go/internal/core/export" 23 ) 24 25 // Notes: 26 // - Can optional fields of y can always be ignored here? Maybe not in the 27 // schema case. 28 // - Definitions of y can be ignored in data mode. 29 // 30 // TODO(perf): use merge sort where possible. 31 func (s *subsumer) vertices(x, y *adt.Vertex) bool { 32 if s.ctx.Version == internal.DevVersion { 33 return s.verticesDev(x, y) 34 } 35 if x == y { 36 return true 37 } 38 if x.ArcType < y.ArcType { 39 return false 40 } 41 42 if s.Defaults { 43 y = y.Default() 44 } 45 46 if b := y.Bottom(); b != nil { 47 // If the value is incomplete, the error is not final. So either check 48 // structural equivalence or return an error. 49 return !b.IsIncomplete() 50 } 51 52 ctx := s.ctx 53 54 final := y.IsData() || s.Final 55 56 switch v := x.BaseValue.(type) { 57 case *adt.Bottom: 58 return false 59 60 case *adt.ListMarker: 61 if !y.IsList() { 62 s.errf("list does not subsume %v (type %s)", y, y.Kind()) 63 return false 64 } 65 if !s.listVertices(x, y) { 66 return false 67 } 68 // TODO: allow other arcs alongside list arc. 69 return true 70 71 case *adt.StructMarker: 72 _, ok := y.BaseValue.(*adt.StructMarker) 73 if !ok { 74 return false 75 } 76 77 case adt.Value: 78 if !s.values(v, y.Value()) { 79 return false 80 } 81 82 // Embedded scalars could still have arcs. 83 if final { 84 return true 85 } 86 87 default: 88 panic(fmt.Sprintf("unexpected type %T", v)) 89 } 90 91 xClosed := x.IsClosedStruct() && !s.IgnoreClosedness 92 // TODO: this should not close for taking defaults. Do a more principled 93 // makeover of this package before making it public, though. 94 yClosed := s.Final || s.Defaults || 95 (y.IsClosedStruct() && !s.IgnoreClosedness) 96 97 if xClosed && !yClosed && !final { 98 return false 99 } 100 101 types := x.OptionalTypes() 102 if !final && !s.IgnoreOptional && types&(adt.HasPattern|adt.HasAdditional) != 0 { 103 // TODO: there are many cases where pattern constraints can be checked. 104 s.inexact = true 105 return false 106 } 107 108 // All arcs in x must exist in y and its values must subsume. 109 xFeatures := export.VertexFeatures(s.ctx, x) 110 for _, f := range xFeatures { 111 if s.Final && !f.IsRegular() { 112 continue 113 } 114 115 a := x.Lookup(f) 116 aOpt := false 117 if a == nil { 118 // x.f is optional 119 if s.IgnoreOptional { 120 continue 121 } 122 123 a = &adt.Vertex{Label: f} 124 x.MatchAndInsert(ctx, a) 125 a.Finalize(ctx) 126 127 // If field a is optional and has value top, neither the 128 // omission of the field nor the field defined with any value 129 // may cause unification to fail. 130 if a.Kind() == adt.TopKind { 131 continue 132 } 133 134 aOpt = true 135 } else if a.IsConstraint() { 136 if s.IgnoreOptional { 137 continue 138 } 139 // If field a is optional and has value top, neither the 140 // omission of the field nor the field defined with any value 141 // may cause unification to fail. 142 if a.Kind() == adt.TopKind { 143 continue 144 } 145 aOpt = true 146 } 147 148 b := y.Lookup(f) 149 if b == nil { 150 // y.f is optional 151 if !aOpt { 152 s.errf("required field is optional in subsumed value: %v", f) 153 return false 154 } 155 156 // If f is undefined for y and if y is closed, the field is 157 // implicitly defined as _|_ and thus subsumed. Technically, this is 158 // even true if a is not optional, but in that case it means that y 159 // is invalid, so return false regardless 160 if !y.Accept(ctx, f) || y.IsData() || s.Final { 161 continue 162 } 163 164 b = &adt.Vertex{Label: f} 165 y.MatchAndInsert(ctx, b) 166 b.Finalize(ctx) 167 } 168 169 if s.values(a, b) { 170 continue 171 } 172 173 s.missing = f 174 s.gt = a 175 s.lt = y 176 177 s.errf("field %v not present in %v", f, y) 178 return false 179 } 180 181 if xClosed && !yClosed && !s.Final { 182 s.errf("closed struct does not subsume open struct") 183 return false 184 } 185 186 yFeatures := export.VertexFeatures(s.ctx, y) 187 outer: 188 for _, f := range yFeatures { 189 if s.Final && !f.IsRegular() { 190 continue 191 } 192 193 for _, g := range xFeatures { 194 if g == f { 195 // already validated 196 continue outer 197 } 198 } 199 200 b := y.Lookup(f) 201 if b == nil { 202 if s.IgnoreOptional || s.Final { 203 continue 204 } 205 206 b = &adt.Vertex{Label: f} 207 y.MatchAndInsert(ctx, b) 208 } else if b.IsConstraint() { 209 if s.IgnoreOptional || s.Final { 210 continue 211 } 212 } 213 214 if !x.Accept(ctx, f) { 215 if s.Profile.IgnoreClosedness { 216 continue 217 } 218 s.errf("field not allowed in closed struct: %v", f) 219 return false 220 } 221 222 a := &adt.Vertex{Label: f} 223 x.MatchAndInsert(ctx, a) 224 if len(a.Conjuncts) == 0 { 225 // It is accepted and has no further constraints, so all good. 226 continue 227 } 228 229 a.Finalize(ctx) 230 b.Finalize(ctx) 231 232 if !s.vertices(a, b) { 233 return false 234 } 235 } 236 237 return true 238 } 239 240 // verticesDev replaces vertices with the implementation of the new evaluator. 241 func (s *subsumer) verticesDev(x, y *adt.Vertex) bool { 242 if x == y { 243 return true 244 } 245 if a, b := x.ArcType, y.ArcType; a < b { 246 return false 247 } 248 249 if s.Defaults { 250 y = y.Default() 251 } 252 253 if b := y.Bottom(); b != nil { 254 // If the value is incomplete, the error is not final. So either check 255 // structural equivalence or return an error. 256 return !b.IsIncomplete() 257 } 258 259 ctx := s.ctx 260 261 final := y.IsData() || s.Final 262 263 switch v := x.BaseValue.(type) { 264 case *adt.Bottom: 265 return false 266 267 case *adt.ListMarker: 268 if !y.IsList() { 269 s.errf("list does not subsume %v (type %s)", y, y.Kind()) 270 return false 271 } 272 if !s.listVertices(x, y) { 273 return false 274 } 275 // TODO: allow other arcs alongside list arc. 276 return true 277 278 case *adt.StructMarker: 279 _, ok := y.BaseValue.(*adt.StructMarker) 280 if !ok { 281 return false 282 } 283 284 case adt.Value: 285 if !s.values(v, y.Value()) { 286 return false 287 } 288 289 // Embedded scalars could still have arcs. 290 if final { 291 return true 292 } 293 294 default: 295 panic(fmt.Sprintf("unexpected type %T", v)) 296 } 297 298 xClosed := x.IsClosedStruct() && !s.IgnoreClosedness 299 // TODO: this should not close for taking defaults. Do a more principled 300 // makeover of this package before making it public, though. 301 yClosed := s.Final || s.Defaults || 302 (y.IsClosedStruct() && !s.IgnoreClosedness) 303 304 if xClosed && !yClosed && !final { 305 return false 306 } 307 308 // From here, verticesDev differs significantly from vertices. 309 310 for _, a := range x.Arcs { 311 f := a.Label 312 if s.Final && !f.IsRegular() { 313 continue 314 } 315 316 isConstraint := false 317 switch a.ArcType { 318 case adt.ArcOptional: 319 if s.IgnoreOptional { 320 continue 321 } 322 323 if a.Kind() == adt.TopKind { 324 continue 325 } 326 327 isConstraint = true 328 329 case adt.ArcRequired: 330 // TODO: what to do with required fields. Logically they should be 331 // ignored if subsuming at the value level. OTOH, they represent an 332 // (incomplete) error at the value level. 333 // Mimic the old evaluator for now. 334 if s.IgnoreOptional { 335 continue 336 } 337 // If field a is optional and has value top, neither the 338 // omission of the field nor the field defined with any value 339 // may cause unification to fail. 340 if a.Kind() == adt.TopKind { 341 continue 342 } 343 344 isConstraint = true 345 } 346 347 b := y.Lookup(f) 348 if b == nil { 349 if !isConstraint { 350 s.errf("regular field is constraint in subsumed value: %v", f) 351 return false 352 } 353 354 // If f is undefined for y and if y is closed, the field is 355 // implicitly defined as _|_ and thus subsumed. Technically, this is 356 // even true if a is not optional, but in that case it means that y 357 // is invalid, so return false regardless 358 if !y.Accept(ctx, f) || y.IsData() || s.Final { 359 continue 360 } 361 362 // There is no explicit field, but the values of pattern constraints 363 // may still be relevant. 364 b = &adt.Vertex{Label: f} 365 y.MatchAndInsert(ctx, b) 366 b.Finalize(ctx) 367 } 368 369 if s.values(a, b) { 370 continue 371 } 372 373 s.missing = f 374 s.gt = a 375 s.lt = y 376 377 s.errf("field %v not present in %v", f, y) 378 return false 379 } 380 381 if xClosed && !yClosed && !s.Final { 382 s.errf("closed struct does not subsume open struct") 383 return false 384 } 385 386 outer: 387 for _, b := range y.Arcs { 388 f := b.Label 389 390 if s.Final && !f.IsRegular() { 391 continue 392 } 393 394 if b.IsConstraint() && (s.IgnoreOptional || s.Final) { 395 continue 396 } 397 398 for _, a := range x.Arcs { 399 g := a.Label 400 if g == f { 401 // already validated 402 continue outer 403 } 404 } 405 406 if !x.Accept(ctx, f) { 407 if s.Profile.IgnoreClosedness { 408 continue 409 } 410 s.errf("field not allowed in closed struct: %v", f) 411 return false 412 } 413 414 a := &adt.Vertex{Label: f} 415 x.MatchAndInsert(ctx, a) 416 if len(a.Conjuncts) == 0 { 417 // It is accepted and has no further constraints, so all good. 418 continue 419 } 420 421 a.Finalize(ctx) 422 423 if !s.vertices(a, b) { 424 return false 425 } 426 } 427 428 // Now compare pattern constraints. 429 apc := x.PatternConstraints 430 bpc := y.PatternConstraints 431 if bpc == nil { 432 if apc == nil { 433 return true 434 } 435 if y.IsClosedList() || y.IsClosedList() || final { 436 // This is a special case where know that any allowed optional field 437 // in a must be bottom in y, which is strictly more specific. 438 return true 439 } 440 return false 441 } 442 if apc == nil { 443 return true 444 } 445 if len(apc.Pairs) > len(bpc.Pairs) { 446 // Theoretically it is still possible for a to subsume b, but it will 447 // somewhat tricky and expensive to compute and it is probably not worth 448 // it. 449 s.inexact = true 450 return false 451 } 452 453 outerConstraint: 454 for _, p := range apc.Pairs { 455 for _, q := range bpc.Pairs { 456 if adt.Equal(s.ctx, p.Pattern, q.Pattern, 0) { 457 if !s.values(p.Constraint, q.Constraint) { 458 return false 459 } 460 continue outerConstraint 461 } 462 } 463 // We have a pattern in a that does not exist in b. Theoretically a 464 // could still subsume b if the values of the patterns in b combined 465 // subsume this value. 466 // TODO: consider whether it is worth computing this. 467 s.inexact = true 468 return false 469 } 470 471 return true 472 } 473 474 func (s *subsumer) listVertices(x, y *adt.Vertex) bool { 475 ctx := s.ctx 476 477 if !y.IsData() && x.IsClosedList() && !y.IsClosedList() { 478 return false 479 } 480 481 xElems := x.Elems() 482 yElems := y.Elems() 483 484 switch { 485 case len(xElems) == len(yElems): 486 case len(xElems) > len(yElems): 487 return false 488 case x.IsClosedList(): 489 return false 490 default: 491 a := &adt.Vertex{Label: adt.AnyIndex} 492 x.MatchAndInsert(ctx, a) 493 a.Finalize(ctx) 494 495 // x must be open 496 for _, b := range yElems[len(xElems):] { 497 if !s.vertices(a, b) { 498 return false 499 } 500 } 501 502 if !y.IsClosedList() { 503 b := &adt.Vertex{Label: adt.AnyIndex} 504 y.MatchAndInsert(ctx, b) 505 b.Finalize(ctx) 506 } 507 } 508 509 for i, a := range xElems { 510 if !s.vertices(a, yElems[i]) { 511 return false 512 } 513 } 514 515 return true 516 }