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  }