cuelang.org/go@v0.13.0/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.VertexFeaturesUnsorted(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.VertexFeaturesUnsorted(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 !a.HasConjuncts() { 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 case nil: 295 return false 296 297 default: 298 panic(fmt.Sprintf("unexpected type %T", v)) 299 } 300 301 xClosed := x.IsClosedStruct() && !s.IgnoreClosedness 302 // TODO: this should not close for taking defaults. Do a more principled 303 // makeover of this package before making it public, though. 304 yClosed := s.Final || s.Defaults || 305 (y.IsClosedStruct() && !s.IgnoreClosedness) 306 307 if xClosed && !yClosed && !final { 308 return false 309 } 310 311 // From here, verticesDev differs significantly from vertices. 312 313 for _, a := range x.Arcs { 314 f := a.Label 315 if s.Final && !f.IsRegular() { 316 continue 317 } 318 319 isConstraint := false 320 switch a.ArcType { 321 case adt.ArcOptional: 322 if s.IgnoreOptional { 323 continue 324 } 325 326 if a.Kind() == adt.TopKind { 327 continue 328 } 329 330 isConstraint = true 331 332 case adt.ArcRequired: 333 // TODO: what to do with required fields. Logically they should be 334 // ignored if subsuming at the value level. OTOH, they represent an 335 // (incomplete) error at the value level. 336 // Mimic the old evaluator for now. 337 if s.IgnoreOptional { 338 continue 339 } 340 // If field a is optional and has value top, neither the 341 // omission of the field nor the field defined with any value 342 // may cause unification to fail. 343 if a.Kind() == adt.TopKind { 344 continue 345 } 346 347 isConstraint = true 348 } 349 350 b := y.Lookup(f) 351 if b == nil { 352 if !isConstraint { 353 s.errf("regular field is constraint in subsumed value: %v", f) 354 return false 355 } 356 357 // If f is undefined for y and if y is closed, the field is 358 // implicitly defined as _|_ and thus subsumed. Technically, this is 359 // even true if a is not optional, but in that case it means that y 360 // is invalid, so return false regardless 361 if !y.Accept(ctx, f) || y.IsData() || s.Final { 362 continue 363 } 364 365 // There is no explicit field, but the values of pattern constraints 366 // may still be relevant. 367 b = &adt.Vertex{Label: f} 368 y.MatchAndInsert(ctx, b) 369 b.Finalize(ctx) 370 } 371 372 if s.values(a, b) { 373 continue 374 } 375 376 s.missing = f 377 s.gt = a 378 s.lt = y 379 380 s.errf("field %v not present in %v", f, y) 381 return false 382 } 383 384 if xClosed && !yClosed && !s.Final { 385 s.errf("closed struct does not subsume open struct") 386 return false 387 } 388 389 outer: 390 for _, b := range y.Arcs { 391 f := b.Label 392 393 if s.Final && !f.IsRegular() { 394 continue 395 } 396 397 if b.IsConstraint() && (s.IgnoreOptional || s.Final) { 398 continue 399 } 400 401 for _, a := range x.Arcs { 402 g := a.Label 403 if g == f { 404 // already validated 405 continue outer 406 } 407 } 408 409 if !x.Accept(ctx, f) { 410 if s.Profile.IgnoreClosedness { 411 continue 412 } 413 s.errf("field not allowed in closed struct: %v", f) 414 return false 415 } 416 417 a := &adt.Vertex{Label: f} 418 x.MatchAndInsert(ctx, a) 419 if !a.HasConjuncts() { 420 // It is accepted and has no further constraints, so all good. 421 continue 422 } 423 424 a.Finalize(ctx) 425 426 if !s.vertices(a, b) { 427 return false 428 } 429 } 430 431 // Now compare pattern constraints. 432 apc := x.PatternConstraints 433 bpc := y.PatternConstraints 434 if bpc == nil { 435 if apc == nil { 436 return true 437 } 438 if y.IsClosedList() || y.IsClosedList() || final { 439 // This is a special case where know that any allowed optional field 440 // in a must be bottom in y, which is strictly more specific. 441 return true 442 } 443 return false 444 } 445 if apc == nil { 446 return true 447 } 448 if len(apc.Pairs) > len(bpc.Pairs) { 449 // Theoretically it is still possible for a to subsume b, but it will 450 // somewhat tricky and expensive to compute and it is probably not worth 451 // it. 452 s.inexact = true 453 return false 454 } 455 456 outerConstraint: 457 for _, p := range apc.Pairs { 458 for _, q := range bpc.Pairs { 459 if adt.Equal(s.ctx, p.Pattern, q.Pattern, 0) { 460 if !s.values(p.Constraint, q.Constraint) { 461 return false 462 } 463 continue outerConstraint 464 } 465 } 466 // We have a pattern in a that does not exist in b. Theoretically a 467 // could still subsume b if the values of the patterns in b combined 468 // subsume this value. 469 // TODO: consider whether it is worth computing this. 470 s.inexact = true 471 return false 472 } 473 474 return true 475 } 476 477 func (s *subsumer) listVertices(x, y *adt.Vertex) bool { 478 ctx := s.ctx 479 480 if !y.IsData() && x.IsClosedList() && !y.IsClosedList() { 481 return false 482 } 483 484 xElems := x.Elems() 485 yElems := y.Elems() 486 487 switch { 488 case len(xElems) == len(yElems): 489 case len(xElems) > len(yElems): 490 return false 491 case x.IsClosedList(): 492 return false 493 default: 494 a := &adt.Vertex{Label: adt.AnyIndex} 495 x.MatchAndInsert(ctx, a) 496 a.Finalize(ctx) 497 498 // x must be open 499 for _, b := range yElems[len(xElems):] { 500 if !s.vertices(a, b) { 501 return false 502 } 503 } 504 505 if !y.IsClosedList() { 506 b := &adt.Vertex{Label: adt.AnyIndex} 507 y.MatchAndInsert(ctx, b) 508 b.Finalize(ctx) 509 } 510 } 511 512 for i, a := range xElems { 513 if !s.vertices(a, yElems[i]) { 514 return false 515 } 516 } 517 518 return true 519 }