diff --git a/cue/testdata/eval/closed_disjunction.txtar b/cue/testdata/eval/closed_disjunction.txtar index 3bab47533..b0c2132c5 100644 --- a/cue/testdata/eval/closed_disjunction.txtar +++ b/cue/testdata/eval/closed_disjunction.txtar @@ -32,8 +32,11 @@ b: field `d` not allowed: Result: (_|_){ // [eval] - #A: (#struct){ - } + #A: (struct){ |(*(#struct){ + }, (#struct){ + }, (#struct){ + }, (#struct){ + }) } a: (#struct){ b: (int){ 3 } c: (int){ 3 } diff --git a/cue/testdata/eval/issue353.txtar b/cue/testdata/eval/issue353.txtar index 10216af82..9b26d24f6 100644 --- a/cue/testdata/eval/issue353.txtar +++ b/cue/testdata/eval/issue353.txtar @@ -13,12 +13,16 @@ e: a: "hello" } -- out/eval -- (struct){ - e: (#struct){ - a: (string){ "hello" } - } - #Example: (#struct){ - a: (string){ string } - } + e: (struct){ |((#struct){ + a: (string){ "hello" } + }, (#struct){ + a: (string){ "hello" } + }) } + #Example: (struct){ |((#struct){ + a: (string){ string } + }, (#struct){ + a: (string){ string } + }) } } -- out/compile -- --- in.cue diff --git a/internal/core/adt/equality.go b/internal/core/adt/equality.go index c8a7d9c43..ca7b41ff4 100644 --- a/internal/core/adt/equality.go +++ b/internal/core/adt/equality.go @@ -47,6 +47,9 @@ func equalVertex(ctx *OpContext, x *Vertex, v Value) bool { if x.IsClosed(ctx) != y.IsClosed(ctx) { return false } + if !equalOptional(ctx, x, y) { + return false + } loop1: for _, a := range x.Arcs { @@ -81,6 +84,37 @@ loop1: return equalTerminal(ctx, v, w) } +// equalOptional tests if x and y have the same set of close information. +// Right now this just checks if it has the same source structs that +// define optional fields. +// TODO: the following refinements are possible: +// - unify optional fields and equate the optional fields +// - do the same for pattern constraints, where the pattern constraints +// are collated by pattern equality. +// - a further refinement would collate patterns by ranges. +// +// For all these refinements it would be necessary to have well-working +// structure sharing so as to not repeatedly recompute optional arcs. +func equalOptional(ctx *OpContext, x, y *Vertex) bool { + return verifyStructs(x, y) && verifyStructs(y, x) +} + +func verifyStructs(x, y *Vertex) bool { +outer: + for _, s := range x.Structs { + if !s.StructLit.HasOptional() { + continue + } + for _, t := range y.Structs { + if s.StructLit == t.StructLit { + continue outer + } + } + return false + } + return true +} + func equalTerminal(ctx *OpContext, v, w Value) bool { if v == w { return true