Skip to content

Commit 2b7dfbd

Browse files
committed
internal/core/adt: support comparsion of structs
This is now trivial given the recent changes. Issue #2583 Signed-off-by: Marcel van Lohuizen <[email protected]> Change-Id: I72ab33e689f0db0b546bf3d64482edb6d4a4826a Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1217114 Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Roger Peppe <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent 665f697 commit 2b7dfbd

File tree

9 files changed

+327
-803
lines changed

9 files changed

+327
-803
lines changed

cue/testdata/basicrewrite/016_comparison.txtar

Lines changed: 287 additions & 795 deletions
Large diffs are not rendered by default.

internal/core/adt/binop.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,35 @@ package adt
1717
import (
1818
"bytes"
1919
"strings"
20+
21+
"cuelang.org/go/cue/token"
2022
)
2123

2224
var checkConcrete = &ValidateConfig{
2325
Concrete: true,
2426
Final: true,
2527
}
2628

29+
// errOnDiffType is a special value that is used as a source to BinOp to
30+
// indicate that the operation is not supported for the operands of different
31+
// kinds.
32+
var errOnDiffType = &UnaryExpr{}
33+
2734
// BinOp handles all operations except AndOp and OrOp. This includes processing
2835
// unary comparators such as '<4' and '=~"foo"'.
2936
//
37+
// The node argument is the adt node corresponding to the binary expression. It
38+
// is used to determine the source position of the operation, which in turn is
39+
// used to determine the experiment context.
40+
//
3041
// BinOp returns nil if not both left and right are concrete.
31-
func BinOp(c *OpContext, op Op, left, right Value) Value {
42+
func BinOp(c *OpContext, node Node, op Op, left, right Value) Value {
43+
var p token.Pos
44+
if node != nil {
45+
if src := node.Source(); src != nil {
46+
p = src.Pos()
47+
}
48+
}
3249
leftKind := left.Kind()
3350
rightKind := right.Kind()
3451

@@ -75,6 +92,10 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {
7592

7693
case leftKind == ListKind && rightKind == ListKind:
7794
return c.newBool(Equal(c, left, right, RegularOnly|IgnoreOptional))
95+
96+
case !p.Experiment().StructCmp:
97+
case leftKind == StructKind && rightKind == StructKind:
98+
return c.newBool(Equal(c, left, right, RegularOnly|IgnoreOptional))
7899
}
79100

80101
case NotEqualOp:
@@ -101,6 +122,10 @@ func BinOp(c *OpContext, op Op, left, right Value) Value {
101122

102123
case leftKind == ListKind && rightKind == ListKind:
103124
return c.newBool(!Equal(c, left, right, RegularOnly|IgnoreOptional))
125+
126+
case !p.Experiment().StructCmp:
127+
case leftKind == StructKind && rightKind == StructKind:
128+
return c.newBool(!Equal(c, left, right, RegularOnly|IgnoreOptional))
104129
}
105130

106131
case LessThanOp, LessEqualOp, GreaterEqualOp, GreaterThanOp:

internal/core/adt/conjunct.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ func (n *nodeContext) insertValueConjunct(env *Environment, v Value, id CloseInf
653653
n.updateCyclicStatusV3(id)
654654

655655
if y := n.scalar; y != nil {
656-
if b, ok := BinOp(ctx, EqualOp, x, y).(*Bool); !ok || !b.B {
656+
if b, ok := BinOp(ctx, errOnDiffType, EqualOp, x, y).(*Bool); !ok || !b.B {
657657
n.reportConflict(x, y, x.Kind(), y.Kind(), n.scalarID, id)
658658
}
659659
break

internal/core/adt/equality.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ func equalTerminal(ctx *OpContext, v, w Value, flags Flag) bool {
191191
return ok
192192

193193
case *Num, *String, *Bool, *Bytes, *Null:
194-
if b, ok := BinOp(ctx, EqualOp, v, w).(*Bool); ok {
194+
if b, ok := BinOp(ctx, errOnDiffType, EqualOp, v, w).(*Bool); ok {
195195
return b.B
196196
}
197197
return false

internal/core/adt/eval.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2134,7 +2134,7 @@ func (n *nodeContext) addValueConjunct(env *Environment, v Value, id CloseInfo)
21342134

21352135
case Value: // *NullLit, *BoolLit, *NumLit, *StringLit, *BytesLit, *Builtin
21362136
if y := n.scalar; y != nil {
2137-
if b, ok := BinOp(ctx, EqualOp, x, y).(*Bool); !ok || !b.B {
2137+
if b, ok := BinOp(ctx, errOnDiffType, EqualOp, x, y).(*Bool); !ok || !b.B {
21382138
n.reportConflict(x, y, x.Kind(), y.Kind(), n.scalarID, id)
21392139
}
21402140
// TODO: do we need to explicitly add again?

internal/core/adt/expr.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ func (x *BoundValue) validate(c *OpContext, y Value) *Bottom {
657657
return c.Err()
658658
}
659659

660-
switch v := BinOp(c, x.Op, a, b).(type) {
660+
switch v := BinOp(c, x, x.Op, a, b).(type) {
661661
case *Bottom:
662662
return v
663663

@@ -1379,7 +1379,7 @@ func (x *BinaryExpr) evaluate(c *OpContext, state combinedFlags) Value {
13791379
return err
13801380
}
13811381

1382-
return BinOp(c, x.Op, left, right)
1382+
return BinOp(c, x, x.Op, left, right)
13831383
}
13841384

13851385
func (c *OpContext) validate(env *Environment, src ast.Node, x Expr, op Op, flags combinedFlags) (r Value) {

internal/core/adt/simplify.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ func opInfo(op Op) (cmp Op, norm int) {
279279
}
280280

281281
func test(ctx *OpContext, op Op, a, b Value) bool {
282-
if b, ok := BinOp(ctx, op, a, b).(*Bool); ok {
282+
if b, ok := BinOp(ctx, nil, op, a, b).(*Bool); ok {
283283
return b.B
284284
}
285285
return false

internal/core/subsume/value.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func (s *subsumer) bound(x *adt.BoundValue, v adt.Value) bool {
312312
}
313313

314314
func test(ctx *adt.OpContext, src adt.Node, op adt.Op, gt, lt adt.Value) bool {
315-
x := adt.BinOp(ctx, op, gt, lt)
315+
x := adt.BinOp(ctx, src, op, gt, lt)
316316
b, ok := x.(*adt.Bool)
317317
return ok && b.B
318318
}

internal/cueexperiment/file.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ type File struct {
4444
// TODO: we could later use it for enabling testing features, such as
4545
// testing-specific builtins.
4646
Testing bool `experiment:"since:v0.13.0"`
47+
48+
// StructCmp enables comparison of structs. This also defines the ==
49+
// operator to be defined on all values. For instance, comparing `1` and
50+
// "foo" will return false, whereas previously it would return an error.
51+
//
52+
// Proposal was defined in https://cuelang.org/issue/2358.
53+
StructCmp bool `experiment:"since:v0.14.0"`
4754
}
4855

4956
// NewFile parses the given comma-separated list of experiments for

0 commit comments

Comments
 (0)