cue: fix optional handling in subsumption
Note that it is overly conservative for bulk optionals.
At some point we should endeavor to relax this.
Change-Id: Ia6908619add410dfd3230e683c720f0171320fe3
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4241
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/subsume.go b/cue/subsume.go
index 83cd174..d9a2257 100644
--- a/cue/subsume.go
+++ b/cue/subsume.go
@@ -87,7 +87,7 @@
if o, ok := v.(*structLit); ok {
// TODO: consider what to do with templates. Perhaps we should always
// do subsumption on fully evaluated structs.
- if len(x.comprehensions) > 0 { //|| x.template != nil {
+ if len(x.comprehensions) > 0 || x.optionals != nil {
return false
}
if x.emit != nil {
@@ -114,6 +114,9 @@
}
// For closed structs, all arcs in b must exist in a.
if x.closeStatus.shouldClose() {
+ if !o.closeStatus.shouldClose() {
+ return false
+ }
for _, b := range o.arcs {
a := x.lookup(ctx, b.feature)
if a.val() == nil {
diff --git a/cue/subsume_test.go b/cue/subsume_test.go
index b95dd72..decf340 100644
--- a/cue/subsume_test.go
+++ b/cue/subsume_test.go
@@ -364,8 +364,14 @@
// The one exception of the rule: there is no value of foo that can be
// added to b which would cause the unification of a and b to fail.
+ // So an optional field with a value of top is equivalent to not
+ // defining one at all.
420: {subsumes: true, in: `a: {foo?: _}, b: {}`},
+ 430: {subsumes: false, in: `a: {[_]: 4}, b: {[_]: int}`},
+ // TODO: handle optionals.
+ 431: {subsumes: false, in: `a: {[_]: int}, b: {[_]: 2}`},
+
// Lists
506: {subsumes: true, in: `a: [], b: [] `},
507: {subsumes: true, in: `a: [1], b: [1] `},
@@ -379,11 +385,13 @@
// Closed structs.
600: {subsumes: false, in: `a: close({}), b: {a: 1}`},
- 601: {subsumes: true, in: `a: close({a: 1}), b: {a: 1}`},
+ 601: {subsumes: false, in: `a: close({a: 1}), b: {a: 1}`},
602: {subsumes: false, in: `a: close({a: 1, b: 1}), b: {a: 1}`},
603: {subsumes: false, in: `a: {a: 1}, b: close({})`},
604: {subsumes: true, in: `a: {a: 1}, b: close({a: 1})`},
605: {subsumes: true, in: `a: {a: 1}, b: close({a: 1, b: 1})`},
+ 606: {subsumes: true, in: `a: close({b?: 1}), b: close({b: 1})`},
+ 607: {subsumes: false, in: `a: close({b: 1}), b: close({b?: 1})`},
// Definitions are not values.
610: {subsumes: false, in: `a: {a :: 1}, b: {a: 1}`},