cuelang.org/go@v0.10.1/internal/core/subsume/structural_test.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_test
    16  
    17  import (
    18  	"regexp"
    19  	"strconv"
    20  	"strings"
    21  	"testing"
    22  
    23  	"cuelang.org/go/cue/parser"
    24  	"cuelang.org/go/internal/core/adt"
    25  	"cuelang.org/go/internal/core/compile"
    26  	"cuelang.org/go/internal/core/eval"
    27  	"cuelang.org/go/internal/core/subsume"
    28  	"cuelang.org/go/internal/cuetdtest"
    29  )
    30  
    31  func TestStructural(t *testing.T) {
    32  	// TODO: all these tests should pass for structural subsumption.
    33  	t.Skip()
    34  
    35  	// Do not inline: the named struct is used as a marker in
    36  	// testdata/gen.go.
    37  	type subsumeTest struct {
    38  		// the result of b ⊑ a, where a and b are defined in "in"
    39  		subsumes bool
    40  		in       string
    41  		// mode     subsumeMode
    42  	}
    43  	testCases := []subsumeTest{
    44  		// Top subsumes everything
    45  		0: {subsumes: true, in: `a: _, b: _ `},
    46  		1: {subsumes: true, in: `a: _, b: null `},
    47  		2: {subsumes: true, in: `a: _, b: int `},
    48  		3: {subsumes: true, in: `a: _, b: 1 `},
    49  		4: {subsumes: true, in: `a: _, b: float `},
    50  		5: {subsumes: true, in: `a: _, b: "s" `},
    51  		6: {subsumes: true, in: `a: _, b: {} `},
    52  		7: {subsumes: true, in: `a: _, b: []`},
    53  		8: {subsumes: true, in: `a: _, b: _|_ `},
    54  
    55  		// Nothing besides top subsumed top
    56  		9:  {subsumes: false, in: `a: null,    b: _`},
    57  		10: {subsumes: false, in: `a: int, b: _`},
    58  		11: {subsumes: false, in: `a: 1,       b: _`},
    59  		12: {subsumes: false, in: `a: float, b: _`},
    60  		13: {subsumes: false, in: `a: "s",     b: _`},
    61  		14: {subsumes: false, in: `a: {},      b: _`},
    62  		15: {subsumes: false, in: `a: [],      b: _`},
    63  		16: {subsumes: false, in: `a: _|_ ,      b: _`},
    64  
    65  		// Bottom subsumes nothing except bottom itself.
    66  		17: {subsumes: false, in: `a: _|_, b: null `},
    67  		18: {subsumes: false, in: `a: _|_, b: int `},
    68  		19: {subsumes: false, in: `a: _|_, b: 1 `},
    69  		20: {subsumes: false, in: `a: _|_, b: float `},
    70  		21: {subsumes: false, in: `a: _|_, b: "s" `},
    71  		22: {subsumes: false, in: `a: _|_, b: {} `},
    72  		23: {subsumes: false, in: `a: _|_, b: [] `},
    73  		24: {subsumes: true, in: ` a: _|_, b: _|_ `},
    74  
    75  		// All values subsume bottom
    76  		25: {subsumes: true, in: `a: null,    b: _|_`},
    77  		26: {subsumes: true, in: `a: int, b: _|_`},
    78  		27: {subsumes: true, in: `a: 1,       b: _|_`},
    79  		28: {subsumes: true, in: `a: float, b: _|_`},
    80  		29: {subsumes: true, in: `a: "s",     b: _|_`},
    81  		30: {subsumes: true, in: `a: {},      b: _|_`},
    82  		31: {subsumes: true, in: `a: [],      b: _|_`},
    83  		32: {subsumes: true, in: `a: true,    b: _|_`},
    84  		33: {subsumes: true, in: `a: _|_,       b: _|_`},
    85  
    86  		// null subsumes only null
    87  		34: {subsumes: true, in: ` a: null, b: null `},
    88  		35: {subsumes: false, in: `a: null, b: 1 `},
    89  		36: {subsumes: false, in: `a: 1,    b: null `},
    90  
    91  		37: {subsumes: true, in: ` a: true, b: true `},
    92  		38: {subsumes: false, in: `a: true, b: false `},
    93  
    94  		39: {subsumes: true, in: ` a: "a",    b: "a" `},
    95  		40: {subsumes: false, in: `a: "a",    b: "b" `},
    96  		41: {subsumes: true, in: ` a: string, b: "a" `},
    97  		42: {subsumes: false, in: `a: "a",    b: string `},
    98  
    99  		// Number typing (TODO)
   100  		//
   101  		// In principle, an "int" cannot assume an untyped "1", as "1" may
   102  		// still by typed as a float. They are two different type aspects. When
   103  		// considering, keep in mind that:
   104  		//   Key requirement: if A subsumes B, it must not be possible to
   105  		//   specialize B further such that A does not subsume B. HOWEVER,
   106  		//   The type conversion rules for conversion are INDEPENDENT of the
   107  		//   rules for subsumption!
   108  		// Consider:
   109  		// - only having number, but allowing user-defined types.
   110  		//   Subsumption would still work the same, but it may be somewhat
   111  		//   less weird.
   112  		// - making 1 always an int and 1.0 always a float.
   113  		//   - the int type would subsume any derived type from int.
   114  		//   - arithmetic would allow implicit conversions, but maybe not for
   115  		//     types.
   116  		//
   117  		// TODO: irrational numbers: allow untyped, but require explicit
   118  		//       trunking when assigning to float.
   119  		//
   120  		// a: number; cue.IsInteger(a) && a > 0
   121  		// t: (x) -> number; cue.IsInteger(a) && a > 0
   122  		// type x number: cue.IsInteger(x) && x > 0
   123  		// x: typeOf(number); cue.IsInteger(x) && x > 0
   124  		43: {subsumes: true, in: `a: 1, b: 1 `},
   125  		44: {subsumes: true, in: `a: 1.0, b: 1.0 `},
   126  		45: {subsumes: true, in: `a: 3.0, b: 3.0 `},
   127  		46: {subsumes: false, in: `a: 1.0, b: 1 `},
   128  		47: {subsumes: false, in: `a: 1, b: 1.0 `},
   129  		48: {subsumes: false, in: `a: 3, b: 3.0`},
   130  		49: {subsumes: true, in: `a: int, b: 1`},
   131  		50: {subsumes: true, in: `a: int, b: int & 1`},
   132  		51: {subsumes: true, in: `a: float, b: 1.0`},
   133  		52: {subsumes: false, in: `a: float, b: 1`},
   134  		53: {subsumes: false, in: `a: int, b: 1.0`},
   135  		54: {subsumes: true, in: `a: int, b: int`},
   136  		55: {subsumes: true, in: `a: number, b: int`},
   137  
   138  		// Structs
   139  		64: {subsumes: true, in: `a: {}, b: {}`},
   140  		65: {subsumes: true, in: `a: {}, b: {a: 1}`},
   141  		66: {subsumes: true, in: `a: {a:1}, b: {a:1, b:1}`},
   142  		67: {subsumes: true, in: `a: {s: { a:1} }, b: { s: { a:1, b:2 }}`},
   143  		68: {subsumes: true, in: `a: {}, b: {}`},
   144  		// TODO: allow subsumption of unevaluated values?
   145  		// ref not yet evaluated and not structurally equivalent
   146  		69: {subsumes: true, in: `a: {}, b: {} & c, c: {}`},
   147  
   148  		70: {subsumes: false, in: `a: {a:1}, b: {}`},
   149  		71: {subsumes: false, in: `a: {a:1, b:1}, b: {a:1}`},
   150  		72: {subsumes: false, in: `a: {s: { a:1} }, b: { s: {}}`},
   151  
   152  		84: {subsumes: true, in: `a: 1 | 2, b: 2 | 1`},
   153  		85: {subsumes: true, in: `a: 1 | 2, b: 1 | 2`},
   154  
   155  		86: {subsumes: true, in: `a: number, b: 2 | 1`},
   156  		87: {subsumes: true, in: `a: number, b: 2 | 1`},
   157  		88: {subsumes: false, in: `a: int, b: 1 | 2 | 3.1`},
   158  
   159  		89: {subsumes: true, in: `a: float | number, b: 1 | 2 | 3.1`},
   160  
   161  		90: {subsumes: false, in: `a: int, b: 1 | 2 | 3.1`},
   162  		91: {subsumes: true, in: `a: 1 | 2, b: 1`},
   163  		92: {subsumes: true, in: `a: 1 | 2, b: 2`},
   164  		93: {subsumes: false, in: `a: 1 | 2, b: 3`},
   165  
   166  		// Structural
   167  		94: {subsumes: false, in: `a: int + int, b: int`},
   168  		95: {subsumes: true, in: `a: int + int, b: int + int`},
   169  		96: {subsumes: true, in: `a: int + number, b: int + int`},
   170  		97: {subsumes: true, in: `a: number + number, b: int + int`},
   171  		// TODO: allow subsumption of unevaluated values?
   172  		// TODO: may be false if we allow arithmetic on incomplete values.
   173  		98: {subsumes: false, in: `a: int + int, b: int * int`},
   174  
   175  		// TODO: allow subsumption of unevaluated values?
   176  		// true because both evaluate to bottom
   177  		99:  {subsumes: true, in: `a: !int, b: !int`},
   178  		100: {subsumes: true, in: `a: !number, b: !int`},
   179  		101: {subsumes: true, in: `a: !int, b: !number`},
   180  
   181  		// TODO: allow subsumption of unevaluated values?
   182  		102: {subsumes: false, in: `a: int + int, b: !number`},
   183  		// TODO: allow subsumption of unevaluated values?
   184  		103: {subsumes: false, in: `a: !bool, b: bool`},
   185  		104: {subsumes: true, in: `a: !bool, b: !bool`},
   186  
   187  		// Call
   188  		113: {subsumes: true, in: `
   189  			a: fn()
   190  			b: fn()
   191  			fn: _`,
   192  		},
   193  		114: {subsumes: false, in: `
   194  			a: fn(),
   195  			b: fn(1)
   196  			fn: _`,
   197  		},
   198  		115: {subsumes: true, in: `
   199  			a: fn(2)
   200  			b: fn(2)
   201  			fn: _`,
   202  		},
   203  		116: {subsumes: true, in: `
   204  			a: fn(number)
   205  			b: fn(2)
   206  			fn: _`,
   207  		},
   208  		117: {subsumes: false, in: `
   209  			a: fn(2)
   210  			b: fn(number)
   211  			fn: _`,
   212  		},
   213  
   214  		// TODO: allow subsumption of unevaluated values?
   215  		// TODO: okay, but why false?
   216  		121: {subsumes: false, in: `a: c + d, b: int, c: int, d: int`},
   217  		// TODO: allow subsumption of unevaluated values?
   218  		122: {subsumes: true, in: `a: {}, b: c & {}, c: {}`},
   219  
   220  		// references
   221  		123: {subsumes: true, in: `a: c, b: c, c: {}`},
   222  		// TODO: allow subsumption of unevaluated values?
   223  		124: {subsumes: true, in: `a: c, b: d, c: {}, d: {}`},
   224  		125: {subsumes: false, in: `a: c, b: d, c: {a:1}, d: {}`},
   225  		// TODO: allow subsumption of unevaluated values?
   226  		126: {subsumes: true, in: `a: c, b: d, c: {a:1}, d: c & {b:1}`},
   227  		127: {subsumes: false, in: `a: d, b: c, c: {a:1}, d: c & {b:1}`},
   228  		128: {subsumes: false, in: `a: c.c, b: c, c: { d: number}`},
   229  
   230  		// type unification catches a reference error.
   231  		129: {subsumes: false, in: `a: c, b: d, c: 1, d: 2`},
   232  
   233  		130: {subsumes: true, in: ` a: [1][1], b: [1][1]`},
   234  		131: {subsumes: true, in: ` a: [1][number], b: [1][1]`},
   235  		132: {subsumes: true, in: ` a: [number][1], b: [1][1]`},
   236  		133: {subsumes: true, in: ` a: [number][number], b: [1][1]`},
   237  		134: {subsumes: false, in: ` a: [1][0], b: [1][number]`},
   238  		135: {subsumes: false, in: ` a: [1][0], b: [number][0]`},
   239  		136: {subsumes: true, in: ` a: [number][number], b: [1][number]`},
   240  		137: {subsumes: true, in: ` a: [number][number], b: [number][1]`},
   241  		// purely structural:
   242  		138: {subsumes: false, in: ` a: [number][number], b: number`},
   243  
   244  		// interpolations
   245  		139: {subsumes: true, in: ` a: "\(d)", b: "\(d)", d: _`},
   246  		// TODO: allow subsumption of unevaluated values?
   247  		140: {subsumes: true, in: ` a: "\(d)", b: "\(e)", d: _, e: _`},
   248  
   249  		141: {subsumes: true, in: ` a: "\(string)", b: "\("foo")"`},
   250  		// TODO: allow subsumption of unevaluated values?
   251  		142: {subsumes: true, in: ` a: "\(string)", b: "\(d)", d: "foo"`},
   252  		143: {subsumes: true, in: ` a: "\("foo")", b: "\("foo")"`},
   253  		144: {subsumes: false, in: ` a: "\("foo")", b: "\(1) \(2)"`},
   254  
   255  		145: {subsumes: false, in: ` a: "s \(d) e", b: "s a e", d: _`},
   256  		146: {subsumes: false, in: ` a: "s \(d)m\(d) e", b: "s a e", d: _`},
   257  
   258  		// 147: {subsumes: true, in: ` a: 7080, b: *7080 | int`, mode: subChoose},
   259  
   260  		// Defaults
   261  		150: {subsumes: false, in: `a: number | *1, b: number | *2`},
   262  		151: {subsumes: true, in: `a: number | *2, b: number | *2`},
   263  		152: {subsumes: true, in: `a: int | *float, b: int | *2.0`},
   264  		153: {subsumes: false, in: `a: int | *2, b: int | *2.0`},
   265  		154: {subsumes: true, in: `a: number | *2 | *3, b: number | *2`},
   266  		155: {subsumes: true, in: `a: number, b: number | *2`},
   267  
   268  		// Bounds
   269  		170: {subsumes: true, in: `a: >=2, b: >=2`},
   270  		171: {subsumes: true, in: `a: >=1, b: >=2`},
   271  		172: {subsumes: true, in: `a: >0, b: >=2`},
   272  		173: {subsumes: true, in: `a: >1, b: >1`},
   273  		174: {subsumes: true, in: `a: >=1, b: >1`},
   274  		175: {subsumes: false, in: `a: >1, b: >=1`},
   275  		176: {subsumes: true, in: `a: >=1, b: >=1`},
   276  		177: {subsumes: true, in: `a: <1, b: <1`},
   277  		178: {subsumes: true, in: `a: <=1, b: <1`},
   278  		179: {subsumes: false, in: `a: <1, b: <=1`},
   279  		180: {subsumes: true, in: `a: <=1, b: <=1`},
   280  
   281  		181: {subsumes: true, in: `a: !=1, b: !=1`},
   282  		182: {subsumes: false, in: `a: !=1, b: !=2`},
   283  
   284  		183: {subsumes: false, in: `a: !=1, b: <=1`},
   285  		184: {subsumes: true, in: `a: !=1, b: <1`},
   286  		185: {subsumes: false, in: `a: !=1, b: >=1`},
   287  		186: {subsumes: true, in: `a: !=1, b: <1`},
   288  
   289  		187: {subsumes: true, in: `a: !=1, b: <=0`},
   290  		188: {subsumes: true, in: `a: !=1, b: >=2`},
   291  		189: {subsumes: true, in: `a: !=1, b: >1`},
   292  
   293  		195: {subsumes: false, in: `a: >=2, b: !=2`},
   294  		196: {subsumes: false, in: `a: >2, b: !=2`},
   295  		197: {subsumes: false, in: `a: <2, b: !=2`},
   296  		198: {subsumes: false, in: `a: <=2, b: !=2`},
   297  
   298  		200: {subsumes: true, in: `a: =~"foo", b: =~"foo"`},
   299  		201: {subsumes: false, in: `a: =~"foo", b: =~"bar"`},
   300  		202: {subsumes: false, in: `a: =~"foo1", b: =~"foo"`},
   301  
   302  		203: {subsumes: true, in: `a: !~"foo", b: !~"foo"`},
   303  		204: {subsumes: false, in: `a: !~"foo", b: !~"bar"`},
   304  		205: {subsumes: false, in: `a: !~"foo", b: !~"foo1"`},
   305  
   306  		// The following is could be true, but we will not go down the rabbit
   307  		// hold of trying to prove subsumption of regular expressions.
   308  		210: {subsumes: false, in: `a: =~"foo", b: =~"foo1"`},
   309  		211: {subsumes: false, in: `a: !~"foo1", b: !~"foo"`},
   310  
   311  		220: {subsumes: true, in: `a: <5, b: 4`},
   312  		221: {subsumes: false, in: `a: <5, b: 5`},
   313  		222: {subsumes: true, in: `a: <=5, b: 5`},
   314  		223: {subsumes: false, in: `a: <=5.0, b: 5.00000001`},
   315  		224: {subsumes: true, in: `a: >5, b: 6`},
   316  		225: {subsumes: false, in: `a: >5, b: 5`},
   317  		226: {subsumes: true, in: `a: >=5, b: 5`},
   318  		227: {subsumes: false, in: `a: >=5, b: 4`},
   319  		228: {subsumes: true, in: `a: !=5, b: 6`},
   320  		229: {subsumes: false, in: `a: !=5, b: 5`},
   321  		230: {subsumes: false, in: `a: !=5.0, b: 5.0`},
   322  		231: {subsumes: false, in: `a: !=5.0, b: 5`},
   323  
   324  		250: {subsumes: true, in: `a: =~ #"^\d{3}$"#, b: "123"`},
   325  		251: {subsumes: false, in: `a: =~ #"^\d{3}$"#, b: "1234"`},
   326  		252: {subsumes: true, in: `a: !~ #"^\d{3}$"#, b: "1234"`},
   327  		253: {subsumes: false, in: `a: !~ #"^\d{3}$"#, b: "123"`},
   328  
   329  		// Conjunctions
   330  		300: {subsumes: true, in: `a: >0, b: >=2 & <=100`},
   331  		301: {subsumes: false, in: `a: >0, b: >=0 & <=100`},
   332  
   333  		310: {subsumes: true, in: `a: >=0 & <=100, b: 10`},
   334  		311: {subsumes: true, in: `a: >=0 & <=100, b: >=0 & <=100`},
   335  		312: {subsumes: false, in: `a: !=2 & !=4, b: >3`},
   336  		313: {subsumes: true, in: `a: !=2 & !=4, b: >5`},
   337  
   338  		314: {subsumes: false, in: `a: >=0 & <=100, b: >=0 & <=150`},
   339  		315: {subsumes: true, in: `a: >=0 & <=150, b: >=0 & <=100`},
   340  
   341  		// Disjunctions
   342  		330: {subsumes: true, in: `a: >5, b: >10 | 8`},
   343  		331: {subsumes: false, in: `a: >8, b: >10 | 8`},
   344  
   345  		// Optional fields
   346  		// Optional fields defined constraints on fields that are not yet
   347  		// defined. So even if such a field is not part of the output, it
   348  		// influences the lattice structure.
   349  		// For a given A and B, where A and B unify and where A has an optional
   350  		// field that is not defined in B, the addition of an incompatible
   351  		// value of that field in B can cause A and B to no longer unify.
   352  		//
   353  		400: {subsumes: false, in: `a: {foo: 1}, b: {}`},
   354  		401: {subsumes: false, in: `a: {foo?: 1}, b: {}`},
   355  		402: {subsumes: true, in: `a: {}, b: {foo: 1}`},
   356  		403: {subsumes: true, in: `a: {}, b: {foo?: 1}`},
   357  
   358  		404: {subsumes: true, in: `a: {foo: 1}, b: {foo: 1}`},
   359  		405: {subsumes: true, in: `a: {foo?: 1}, b: {foo: 1}`},
   360  		406: {subsumes: true, in: `a: {foo?: 1}, b: {foo?: 1}`},
   361  		407: {subsumes: false, in: `a: {foo: 1}, b: {foo?: 1}`},
   362  
   363  		408: {subsumes: false, in: `a: {foo: 1}, b: {foo: 2}`},
   364  		409: {subsumes: false, in: `a: {foo?: 1}, b: {foo: 2}`},
   365  		410: {subsumes: false, in: `a: {foo?: 1}, b: {foo?: 2}`},
   366  		411: {subsumes: false, in: `a: {foo: 1}, b: {foo?: 2}`},
   367  
   368  		412: {subsumes: true, in: `a: {foo: number}, b: {foo: 2}`},
   369  		413: {subsumes: true, in: `a: {foo?: number}, b: {foo: 2}`},
   370  		414: {subsumes: true, in: `a: {foo?: number}, b: {foo?: 2}`},
   371  		415: {subsumes: false, in: `a: {foo: number}, b: {foo?: 2}`},
   372  
   373  		416: {subsumes: false, in: `a: {foo: 1}, b: {foo: number}`},
   374  		417: {subsumes: false, in: `a: {foo?: 1}, b: {foo: number}`},
   375  		418: {subsumes: false, in: `a: {foo?: 1}, b: {foo?: number}`},
   376  		419: {subsumes: false, in: `a: {foo: 1}, b: {foo?: number}`},
   377  
   378  		// The one exception of the rule: there is no value of foo that can be
   379  		// added to b which would cause the unification of a and b to fail.
   380  		// So an optional field with a value of top is equivalent to not
   381  		// defining one at all.
   382  		420: {subsumes: true, in: `a: {foo?: _}, b: {}`},
   383  
   384  		430: {subsumes: false, in: `a: {[_]: 4}, b: {[_]: int}`},
   385  		// TODO: handle optionals.
   386  		431: {subsumes: false, in: `a: {[_]: int}, b: {[_]: 2}`},
   387  
   388  		// 440: {subsumes: true, in: `a: {foo?: 1}, b: {}`, mode: subNoOptional},
   389  		// 441: {subsumes: true, in: `a: {}, b: {foo?: 1}`, mode: subNoOptional},
   390  		// 442: {subsumes: true, in: `a: {foo?: 1}, b: {foo: 1}`, mode: subNoOptional},
   391  		// 443: {subsumes: true, in: `a: {foo?: 1}, b: {foo?: 1}`, mode: subNoOptional},
   392  		// 444: {subsumes: false, in: `a: {foo: 1}, b: {foo?: 1}`, mode: subNoOptional},
   393  		// 445: {subsumes: true, in: `a: close({}), b: {foo?: 1}`, mode: subNoOptional},
   394  		// 446: {subsumes: true, in: `a: close({}), b: close({foo?: 1})`, mode: subNoOptional},
   395  		// 447: {subsumes: true, in: `a: {}, b: close({})`, mode: subNoOptional},
   396  		// 448: {subsumes: true, in: `a: {}, b: close({foo?: 1})`, mode: subNoOptional},
   397  
   398  		// Lists
   399  		506: {subsumes: true, in: `a: [], b: [] `},
   400  		507: {subsumes: true, in: `a: [1], b: [1] `},
   401  		508: {subsumes: false, in: `a: [1], b: [2] `},
   402  		509: {subsumes: false, in: `a: [1], b: [2, 3] `},
   403  		510: {subsumes: true, in: `a: [{b: string}], b: [{b: "foo"}] `},
   404  		511: {subsumes: true, in: `a: [...{b: string}], b: [{b: "foo"}] `},
   405  		512: {subsumes: false, in: `a: [{b: "foo"}], b: [{b: string}] `},
   406  		513: {subsumes: false, in: `a: [{b: string}], b: [{b: "foo"}, ...{b: "foo"}] `},
   407  		520: {subsumes: false, in: `a: [_, int, ...], b: [int, string, ...string] `},
   408  
   409  		// Closed structs.
   410  		600: {subsumes: false, in: `a: close({}), b: {a: 1}`},
   411  		601: {subsumes: false, in: `a: close({a: 1}), b: {a: 1}`},
   412  		602: {subsumes: false, in: `a: close({a: 1, b: 1}), b: {a: 1}`},
   413  		603: {subsumes: false, in: `a: {a: 1}, b: close({})`},
   414  		604: {subsumes: true, in: `a: {a: 1}, b: close({a: 1})`},
   415  		605: {subsumes: true, in: `a: {a: 1}, b: close({a: 1, b: 1})`},
   416  		606: {subsumes: true, in: `a: close({b?: 1}), b: close({b: 1})`},
   417  		607: {subsumes: false, in: `a: close({b: 1}), b: close({b?: 1})`},
   418  		608: {subsumes: true, in: `a: {}, b: close({})`},
   419  		609: {subsumes: true, in: `a: {}, b: close({foo?: 1})`},
   420  		610: {subsumes: true, in: `a: {foo?:1}, b: close({})`},
   421  
   422  		// Definitions are not regular fields.
   423  		630: {subsumes: false, in: `a: {#a: 1}, b: {a: 1}`},
   424  		631: {subsumes: false, in: `a: {a: 1}, b: {#a: 1}`},
   425  
   426  		// // Subsuming final values.
   427  		// 700: {subsumes: true, in: `a: {[string]: 1}, b: {foo: 1}`, mode: subFinal},
   428  		// 701: {subsumes: true, in: `a: {[string]: int}, b: {foo: 1}`, mode: subFinal},
   429  		// 702: {subsumes: true, in: `a: {["foo"]: int}, b: {foo: 1}`, mode: subFinal},
   430  		// 703: {subsumes: false, in: `a: close({["foo"]: 1}), b: {bar: 1}`, mode: subFinal},
   431  		// 704: {subsumes: false, in: `a: {foo: 1}, b: {foo?: 1}`, mode: subFinal},
   432  		// 705: {subsumes: true, in: `a: close({}), b: {foo?: 1}`, mode: subFinal},
   433  		// 706: {subsumes: true, in: `a: close({}), b: close({foo?: 1})`, mode: subFinal},
   434  		// 707: {subsumes: true, in: `a: {}, b: close({})`, mode: subFinal},
   435  		// 708: {subsumes: false, in: `a: {[string]: 1}, b: {foo: 2}`, mode: subFinal},
   436  		// 709: {subsumes: true, in: `a: {}, b: close({foo?: 1})`, mode: subFinal},
   437  		// 710: {subsumes: false, in: `a: {foo: [...string]}, b: {}`, mode: subFinal},
   438  
   439  		// // Schema values
   440  		// 800: {subsumes: true, in: `a: close({}), b: {foo: 1}`, mode: subSchema},
   441  		// // TODO(eval): FIX
   442  		// // 801: {subsumes: true, in: `a: {[string]: int}, b: {foo: 1}`, mode: subSchema},
   443  		// 804: {subsumes: false, in: `a: {foo: 1}, b: {foo?: 1}`, mode: subSchema},
   444  		// 805: {subsumes: true, in: `a: close({}), b: {foo?: 1}`, mode: subSchema},
   445  		// 806: {subsumes: true, in: `a: close({}), b: close({foo?: 1})`, mode: subSchema},
   446  		// 807: {subsumes: true, in: `a: {}, b: close({})`, mode: subSchema},
   447  		// 808: {subsumes: false, in: `a: {[string]: 1}, b: {foo: 2}`, mode: subSchema},
   448  		// 809: {subsumes: true, in: `a: {}, b: close({foo?: 1})`, mode: subSchema},
   449  	}
   450  
   451  	re := regexp.MustCompile(`a: (.*).*b: ([^\n]*)`)
   452  	for i, tc := range testCases {
   453  		if tc.in == "" {
   454  			continue
   455  		}
   456  		m := re.FindStringSubmatch(strings.Join(strings.Split(tc.in, "\n"), ""))
   457  		const cutset = "\n ,"
   458  		key := strings.Trim(m[1], cutset) + " ⊑ " + strings.Trim(m[2], cutset)
   459  
   460  		cuetdtest.FullMatrix.Run(t, strconv.Itoa(i)+"/"+key, func(t *cuetdtest.M) {
   461  			r := t.Runtime()
   462  
   463  			file, err := parser.ParseFile("subsume", tc.in)
   464  			if err != nil {
   465  				t.Fatal(err)
   466  			}
   467  
   468  			root, errs := compile.Files(nil, r, "", file)
   469  			if errs != nil {
   470  				t.Fatal(errs)
   471  			}
   472  
   473  			ctx := eval.NewContext(r, root)
   474  			root.Finalize(ctx)
   475  
   476  			// Use low-level lookup to avoid evaluation.
   477  			var a, b adt.Value
   478  			for _, arc := range root.Arcs {
   479  				switch arc.Label {
   480  				case ctx.StringLabel("a"):
   481  					a = arc
   482  				case ctx.StringLabel("b"):
   483  					b = arc
   484  				}
   485  			}
   486  
   487  			err = subsume.Value(ctx, a, b)
   488  			got := err == nil
   489  
   490  			if got != tc.subsumes {
   491  				t.Errorf("got %v; want %v (%v vs %v)", got, tc.subsumes, a.Kind(), b.Kind())
   492  			}
   493  		})
   494  	}
   495  }