From e8e86822227006b796849d9bf16bccbd652ccfc8 Mon Sep 17 00:00:00 2001 From: Marcel van Lohuizen Date: Sat, 14 Jun 2025 23:59:55 +0200 Subject: [PATCH] internal/core/adt: limit closedness check in Equal The closedness check only makes sense for CheckStructural . The flags != 0 test was used before some of the other options were introduced. We now only check closedness if CheckStructural is enabled. Note that this currently only impacts evalv2 behavior. The resulting changes are correct. Issue #2583 Signed-off-by: Marcel van Lohuizen Change-Id: I32a188f2d092469f043f6ae047cf914ffef90708 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1217007 Unity-Result: CUE porcuepine TryBot-Result: CUEcueckoo Reviewed-by: Roger Peppe --- internal/core/adt/equality.go | 2 +- pkg/list/testdata/unique.txtar | 53 +++++++++------------------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/internal/core/adt/equality.go b/internal/core/adt/equality.go index e808f1798..0e0cbfb75 100644 --- a/internal/core/adt/equality.go +++ b/internal/core/adt/equality.go @@ -79,7 +79,7 @@ func equalVertex(ctx *OpContext, x *Vertex, v Value, flags Flag) bool { } // TODO: this really should be subsumption. - if flags != 0 { + if flags&CheckStructural != 0 { if x.IsClosedStruct() != y.IsClosedStruct() { return false } diff --git a/pkg/list/testdata/unique.txtar b/pkg/list/testdata/unique.txtar index b7a993925..fc1bc3bac 100644 --- a/pkg/list/testdata/unique.txtar +++ b/pkg/list/testdata/unique.txtar @@ -196,17 +196,16 @@ fail: { diff old new --- old +++ new -@@ -2,6 +2,9 @@ +@@ -2,7 +2,7 @@ fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1: ./in.cue:3:21 ./in.cue:48:16 +-fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1: +fail.ignoreOptError: invalid value [~(#a),~(#abErr)] (does not satisfy list.UniqueItems): equal values at position 0 and 1: -+ ./in.cue:3:21 -+ ./in.cue:52:18 - fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2: ./in.cue:3:21 - ./in.cue:44:8 -@@ -8,7 +11,7 @@ + ./in.cue:52:18 + fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2: +@@ -11,7 +11,7 @@ fail.structOrderIrrelevant: invalid value [{b:1,a:0},{a:0,b:1}] (does not satisfy list.UniqueItems): equal values at position 0 and 1: ./in.cue:3:21 ./in.cue:72:30 @@ -215,21 +214,7 @@ diff old new ./in.cue:3:21 ./in.cue:45:11 -@@ -67,12 +70,7 @@ - }] - - // Ditto. This time with actually closed fields. -- withOptional3: [{ -- a: 1 -- }, { -- a: 1 -- b?: int -- }] -+ withOptional3: list.UniqueItems() & [#a, #ab] - - // Ditto. There are not optional fields, but the structs are open. - openSpecific: list.UniqueItems() & [{ -@@ -100,7 +98,7 @@ +@@ -98,7 +98,7 @@ } fail: { ints: _|_ // fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2 @@ -238,16 +223,11 @@ diff old new // Hidden values do not play a role in the comparisson. ignoreHidden: _|_ // fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1 -@@ -107,12 +105,7 @@ +@@ -105,7 +105,7 @@ // This can be a permanent error, as the optional field of the second // element is erroneous an cannot match. -- ignoreOptError: [{ -- a: 1 -- }, { -- a: 1 -- b?: int & string -- }] +- ignoreOptError: _|_ // fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1 + ignoreOptError: _|_ // fail.ignoreOptError: invalid value [~(#a),~(#abErr)] (does not satisfy list.UniqueItems): equal values at position 0 and 1 // Struct field order is irrelevant. We simulate finalising @@ -257,6 +237,9 @@ Errors: fail.ignoreHidden: invalid value [1,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 1: ./in.cue:3:21 ./in.cue:48:16 +fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1: + ./in.cue:3:21 + ./in.cue:52:18 fail.ints: invalid value [1,2,1] (does not satisfy list.UniqueItems): equal value (1) at position 0 and 2: ./in.cue:3:21 ./in.cue:44:8 @@ -322,12 +305,7 @@ incomplete: { }] // Ditto. This time with actually closed fields. - withOptional3: [{ - a: 1 - }, { - a: 1 - b?: int - }] + withOptional3: list.UniqueItems() & [#a, #ab] // Ditto. There are not optional fields, but the structs are open. openSpecific: list.UniqueItems() & [{ @@ -362,12 +340,7 @@ fail: { // This can be a permanent error, as the optional field of the second // element is erroneous an cannot match. - ignoreOptError: [{ - a: 1 - }, { - a: 1 - b?: int & string - }] + ignoreOptError: _|_ // fail.ignoreOptError: invalid value [{a:1},{a:1,b?:_|_(fail.ignoreOptError.1.b: conflicting values int and string (mismatched types int and string))}] (does not satisfy list.UniqueItems): equal values at position 0 and 1 // Struct field order is irrelevant. We simulate finalising // these values here via close(), which gives the same behaviour -- 2.51.2