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  }