cuelang.org/go@v0.10.1/internal/core/subsume/value.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  	"bytes"
    19  
    20  	"cuelang.org/go/cue/errors"
    21  	"cuelang.org/go/internal/core/adt"
    22  )
    23  
    24  func (s *subsumer) values(a, b adt.Value) (result bool) {
    25  	defer func() {
    26  		if !result && s.gt == nil && s.lt == nil {
    27  			s.gt = a
    28  			s.lt = b
    29  		}
    30  	}()
    31  
    32  	if a == b {
    33  		return true
    34  	}
    35  
    36  	if s.Defaults {
    37  		b = adt.Default(b)
    38  	}
    39  
    40  	switch b := b.(type) {
    41  	case *adt.Bottom:
    42  		// If the value is incomplete, the error is not final. So either check
    43  		// structural equivalence or return an error.
    44  		return !b.IsIncomplete()
    45  
    46  	case *adt.Vertex:
    47  		if a, ok := a.(*adt.Vertex); ok {
    48  			return s.vertices(a, b)
    49  		}
    50  		if v, ok := b.BaseValue.(adt.Value); ok {
    51  			// Safe to ignore arcs of w.
    52  			return s.values(a, v)
    53  		}
    54  		// Check based on first value.
    55  
    56  	case *adt.Conjunction:
    57  		if _, ok := a.(*adt.Conjunction); ok {
    58  			break
    59  		}
    60  		for _, y := range b.Values {
    61  			if s.values(a, y) {
    62  				return true
    63  			}
    64  		}
    65  		return false
    66  
    67  	case *adt.Disjunction:
    68  		if _, ok := a.(*adt.Disjunction); ok {
    69  			break
    70  		}
    71  
    72  		for _, y := range b.Values {
    73  			if !s.values(a, y) {
    74  				return false
    75  			}
    76  		}
    77  		return true
    78  
    79  	case *adt.NodeLink:
    80  		// Do not descend into NodeLinks to avoid processing cycles.
    81  		// TODO: this would work better if all equal nodes shared the same
    82  		// node link.
    83  		return deref(a) == deref(b)
    84  	}
    85  
    86  	switch x := a.(type) {
    87  	case *adt.Top:
    88  		return true
    89  
    90  	case *adt.Bottom:
    91  		// isBottom(b) was already tested above.
    92  		return false
    93  
    94  	case *adt.BasicType:
    95  		k := b.Kind()
    96  		return x.K&k == k
    97  
    98  	case *adt.BoundValue:
    99  		return s.bound(x, b)
   100  
   101  	case *adt.Builtin:
   102  		return x == b
   103  
   104  	case *adt.BuiltinValidator:
   105  		state := s.ctx.PushState(s.ctx.Env(0), b.Source())
   106  		b1 := s.ctx.Validate(x, b)
   107  		if b1 != nil {
   108  			s.errs = errors.Append(s.errs, b1.Err)
   109  		}
   110  		b2 := s.ctx.PopState(state)
   111  		if b2 != nil {
   112  			s.errs = errors.Append(s.errs, b2.Err)
   113  		}
   114  		return b1 == nil && b2 == nil
   115  
   116  	case *adt.Null:
   117  		return b.Kind() == adt.NullKind
   118  
   119  	case *adt.Bool:
   120  		y, ok := b.(*adt.Bool)
   121  		return ok && x.B == y.B
   122  
   123  	case *adt.Num:
   124  		y, ok := b.(*adt.Num)
   125  		return ok && x.K&y.K == y.K && test(s.ctx, x, adt.EqualOp, x, y)
   126  
   127  	case *adt.String:
   128  		y, ok := b.(*adt.String)
   129  		return ok && x.Str == y.Str
   130  
   131  	case *adt.Bytes:
   132  		y, ok := b.(*adt.Bytes)
   133  		return ok && bytes.Equal(x.B, y.B)
   134  
   135  	case *adt.Vertex:
   136  		y, ok := b.(*adt.Vertex)
   137  		if ok {
   138  			return s.vertices(x, y)
   139  		}
   140  
   141  		// TODO: Under what conditions can we cast to the value?
   142  		if v, _ := x.BaseValue.(adt.Value); v != nil {
   143  			return s.values(v, b)
   144  		}
   145  		return false
   146  
   147  	case *adt.Conjunction:
   148  		if y, ok := b.(*adt.Conjunction); ok {
   149  			// A Conjunction subsumes another Conjunction if for all values a in
   150  			// x there is a value b in y such that a subsumes b.
   151  			//
   152  			// This assumes overlapping ranges in disjunctions are merged.If
   153  			// this is not the case, subsumes will return a false negative,
   154  			// which is allowed.
   155  		outerC:
   156  			for _, a := range x.Values {
   157  				for _, b := range y.Values {
   158  					if s.values(a, b) {
   159  						continue outerC
   160  					}
   161  				}
   162  				// TODO: should this be marked as inexact?
   163  				return false
   164  			}
   165  			return true
   166  		}
   167  		subsumed := true
   168  		for _, a := range x.Values {
   169  			subsumed = subsumed && s.values(a, b)
   170  		}
   171  		return subsumed
   172  
   173  	case *adt.Disjunction:
   174  
   175  		if s.LeftDefault {
   176  			a = adt.Default(a)
   177  			var ok bool
   178  			x, ok = a.(*adt.Disjunction)
   179  			if !ok {
   180  				return s.values(a, b)
   181  			}
   182  		}
   183  
   184  		// A Disjunction subsumes another Disjunction if all values of y are
   185  		// subsumed by any of the values of x, and default values in y are
   186  		// subsumed by the default values of x.
   187  		//
   188  		// This assumes that overlapping ranges in x are merged. If this is not
   189  		// the case, subsumes will return a false negative, which is allowed.
   190  		if y, ok := b.(*adt.Disjunction); ok {
   191  			// at least one value in x should subsume each value in d.
   192  		outerD:
   193  			for i, b := range y.Values {
   194  				bDefault := i < y.NumDefaults
   195  				// v is subsumed if any value in x subsumes v.
   196  				for j, a := range x.Values {
   197  					aDefault := j < x.NumDefaults
   198  					if (aDefault || !bDefault) && s.values(a, b) {
   199  						continue outerD
   200  					}
   201  				}
   202  				return false
   203  			}
   204  			return true
   205  		}
   206  		// b is subsumed if any value in x subsumes b.
   207  		for _, a := range x.Values {
   208  			if s.values(a, b) {
   209  				return true
   210  			}
   211  		}
   212  		// TODO: should this be marked as inexact?
   213  		return false
   214  
   215  	case *adt.NodeLink:
   216  		return deref(x) == deref(b)
   217  	}
   218  	return false
   219  }
   220  
   221  func deref(v adt.Expr) *adt.Vertex {
   222  	switch x := v.(type) {
   223  	case *adt.Vertex:
   224  		return x
   225  	case *adt.NodeLink:
   226  		return x.Node
   227  	}
   228  	return nil
   229  }
   230  
   231  func (s *subsumer) bound(x *adt.BoundValue, v adt.Value) bool {
   232  	ctx := s.ctx
   233  	if isBottom(v) {
   234  		return true
   235  	}
   236  
   237  	switch y := v.(type) {
   238  	case *adt.BoundValue:
   239  		if !adt.IsConcrete(y.Value) {
   240  			return false
   241  		}
   242  
   243  		kx := x.Kind()
   244  		ky := y.Kind()
   245  		if (kx&ky)&^kx != 0 {
   246  			return false
   247  		}
   248  		// x subsumes y if
   249  		// x: >= a, y: >= b ==> a <= b
   250  		// x: >= a, y: >  b ==> a <= b
   251  		// x: >  a, y: >  b ==> a <= b
   252  		// x: >  a, y: >= b ==> a < b
   253  		//
   254  		// x: <= a, y: <= b ==> a >= b
   255  		//
   256  		// x: != a, y: != b ==> a != b
   257  		//
   258  		// false if types or op direction doesn't match
   259  
   260  		xv := x.Value
   261  		yv := y.Value
   262  		switch x.Op {
   263  		case adt.GreaterThanOp:
   264  			if y.Op == adt.GreaterEqualOp {
   265  				return test(ctx, x, adt.LessThanOp, xv, yv)
   266  			}
   267  			fallthrough
   268  		case adt.GreaterEqualOp:
   269  			if y.Op == adt.GreaterThanOp || y.Op == adt.GreaterEqualOp {
   270  				return test(ctx, x, adt.LessEqualOp, xv, yv)
   271  			}
   272  		case adt.LessThanOp:
   273  			if y.Op == adt.LessEqualOp {
   274  				return test(ctx, x, adt.GreaterThanOp, xv, yv)
   275  			}
   276  			fallthrough
   277  		case adt.LessEqualOp:
   278  			if y.Op == adt.LessThanOp || y.Op == adt.LessEqualOp {
   279  				return test(ctx, x, adt.GreaterEqualOp, xv, yv)
   280  			}
   281  		case adt.NotEqualOp:
   282  			switch y.Op {
   283  			case adt.NotEqualOp:
   284  				return test(ctx, x, adt.EqualOp, xv, yv)
   285  			case adt.GreaterEqualOp:
   286  				return test(ctx, x, adt.LessThanOp, xv, yv)
   287  			case adt.GreaterThanOp:
   288  				return test(ctx, x, adt.LessEqualOp, xv, yv)
   289  			case adt.LessThanOp:
   290  				return test(ctx, x, adt.GreaterEqualOp, xv, yv)
   291  			case adt.LessEqualOp:
   292  				return test(ctx, x, adt.GreaterThanOp, xv, yv)
   293  			}
   294  
   295  		case adt.MatchOp, adt.NotMatchOp:
   296  			// these are just approximations
   297  			if y.Op == x.Op {
   298  				return test(ctx, x, adt.EqualOp, xv, yv)
   299  			}
   300  
   301  		default:
   302  			// adt.NotEqualOp already handled above.
   303  			panic("cue: undefined bound mode")
   304  		}
   305  
   306  	case *adt.Num, *adt.String, *adt.Bool:
   307  		return test(ctx, x, x.Op, y, x.Value)
   308  	}
   309  	return false
   310  }
   311  
   312  func test(ctx *adt.OpContext, src adt.Node, op adt.Op, gt, lt adt.Value) bool {
   313  	x := adt.BinOp(ctx, op, gt, lt)
   314  	b, ok := x.(*adt.Bool)
   315  	return ok && b.B
   316  }