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}`},