Skip to content

Commit ee85bb9

Browse files
committed
cue/errors: avoid simple duplication when gathering errors
The (benchmark) test case added caused immense duplication of errors (over 43 million). The cause is unclear, but it's suspected a bug in comprehensions. The solution here is to detect, in errors.Append, that the two errors are the same, and if so, avoid creating a list of both. Fixes #3307 Signed-off-by: Matthew Sackman <[email protected]> Change-Id: I1cb3baf00888072c5a4811f9acc95fac9ed49d4b Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1199401 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 93670d7 commit ee85bb9

File tree

6 files changed

+93
-208
lines changed

6 files changed

+93
-208
lines changed

cue/errors/errors.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,22 @@ func (e *posError) Position() token.Pos { return e.pos }
274274

275275
// Append combines two errors, flattening Lists as necessary.
276276
func Append(a, b Error) Error {
277-
switch x := a.(type) {
277+
switch a := a.(type) {
278278
case nil:
279279
return b
280280
case list:
281-
return appendToList(x, b)
281+
return appendToList(a, b)
282282
}
283-
// Preserve order of errors.
284-
list := appendToList(nil, a)
285-
list = appendToList(list, b)
286-
return list
283+
switch b := b.(type) {
284+
case nil:
285+
return a
286+
case list:
287+
return appendToList(list{a}, b)
288+
}
289+
if a == b {
290+
return a
291+
}
292+
return list{a, b}
287293
}
288294

289295
// Errors reports the individual errors associated with an error, which is
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
-- in.cue --
2+
if _request.enabled {
3+
r1: {
4+
k1: 0
5+
k2: 0
6+
k3: 0
7+
k4: 0
8+
k5: 0
9+
k6: 0
10+
k7: 0
11+
k8: 0
12+
k9: 0
13+
k10: 0
14+
k11: 0
15+
k12: 0
16+
k13: 0
17+
k14: 0
18+
k15: 0
19+
k16: 0
20+
k17: 0
21+
}
22+
}
23+
24+
_request: enabled: _
25+
-- out/eval/stats --
26+
Leaks: 0
27+
Freed: 21
28+
Reused: 16
29+
Allocs: 5
30+
Retain: 72
31+
32+
Unifications: 21
33+
Conjuncts: 3
34+
Disjuncts: 93
35+
-- out/eval --
36+
(_|_){
37+
// [incomplete] incomplete bool: _
38+
_request: (struct){
39+
enabled: (_){ _ }
40+
}
41+
}
42+
-- out/compile --
43+
--- in.cue
44+
{
45+
if 〈0;_request〉.enabled {
46+
r1: {
47+
k1: 0
48+
k2: 0
49+
k3: 0
50+
k4: 0
51+
k5: 0
52+
k6: 0
53+
k7: 0
54+
k8: 0
55+
k9: 0
56+
k10: 0
57+
k11: 0
58+
k12: 0
59+
k13: 0
60+
k14: 0
61+
k15: 0
62+
k16: 0
63+
k17: 0
64+
}
65+
}
66+
_request: {
67+
enabled: _
68+
}
69+
}

cue/testdata/eval/dynamic_field.txtar

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ Result:
164164
// [incomplete] noCycleError.foo.baz.#ID: invalid interpolation: non-concrete value string (type string):
165165
// ./in.cue:59:8
166166
// ./in.cue:59:11
167-
// noCycleError.foo.bar.entries: key value of dynamic field must be concrete, found _|_(invalid interpolation: noCycleError.foo.baz.#ID: non-concrete value string (type string) (and 1 more errors)):
167+
// noCycleError.foo.bar.entries: key value of dynamic field must be concrete, found _|_(invalid interpolation: noCycleError.foo.baz.#ID: non-concrete value string (type string)):
168168
// ./in.cue:61:22
169169
}
170170
#ID: (_|_){
@@ -201,7 +201,7 @@ diff old new
201201
// [incomplete] noCycleError.foo.baz.#ID: invalid interpolation: non-concrete value string (type string):
202202
// ./in.cue:59:8
203203
// ./in.cue:59:11
204-
+ // noCycleError.foo.bar.entries: key value of dynamic field must be concrete, found _|_(invalid interpolation: noCycleError.foo.baz.#ID: non-concrete value string (type string) (and 1 more errors)):
204+
+ // noCycleError.foo.bar.entries: key value of dynamic field must be concrete, found _|_(invalid interpolation: noCycleError.foo.baz.#ID: non-concrete value string (type string)):
205205
+ // ./in.cue:61:22
206206
}
207207
#ID: (_|_){

internal/core/export/testdata/main/adt.txtar

Lines changed: 0 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -337,119 +337,6 @@ Reordering.
337337
[errorListDef #Def]
338338
[errorListDef 0]
339339
[errorListDef 1]
340-
-- out/value-v3 --
341-
== Simplified
342-
_|_ // e3: index out of range [2] with length 2
343-
== Raw
344-
_|_ // e3: index out of range [2] with length 2
345-
== Final
346-
_|_ // e3: index out of range [2] with length 2
347-
== All
348-
{
349-
@foo(bar)
350-
p1: {}
351-
d1: {
352-
foobar: int
353-
}
354-
bar: "bar"
355-
d2: {
356-
foobar: {
357-
name: "xx"
358-
foo: "xx"
359-
}
360-
}
361-
362-
// Issue #1910
363-
a: _
364-
comp: {
365-
for k, v in [0]
366-
let w = v {
367-
"\(a)": w
368-
"bar": w
369-
}
370-
}
371-
bytes: '\xeb \x1a\xf5\xaa\xf0\xd6\x06)'
372-
c1: true
373-
s1: """
374-
multi
375-
bar
376-
line
377-
"""
378-
l1: [3, ...int]
379-
l2: [...int]
380-
l3: []
381-
l4: [1, 2]
382-
l5: {
383-
#foo: int
384-
[1, 3]
385-
}
386-
#foo: int
387-
l6: {
388-
#foo: int
389-
[1, 3]
390-
}
391-
n1: 1.0
392-
n10: 10
393-
394-
// t is true
395-
t: true
396-
e1: <1.0
397-
e2: >1.0 & <10
398-
e3: _|_ // e3: index out of range [2] with length 2
399-
e4: _|_ // e4: index 3 out of range (and 1 more errors)
400-
e5: _|_ // e3: index out of range [2] with length 2 (and 1 more errors)
401-
e6: false
402-
e7: true
403-
e8?: true
404-
m1: {
405-
// foo is an optional field
406-
foo?: 3
407-
408-
// bar is a field
409-
bar: 4
410-
411-
// baz is a required field.
412-
baz!: 5
413-
}
414-
y1: {
415-
src: [1, 2, 3]
416-
foo0: 1
417-
bar1: 2
418-
bar2: 3
419-
foo1: 2
420-
x: [1, 2, 3]
421-
foo2: 3
422-
}
423-
preserveKeyFieldInComprehension: 1
424-
errorStructDef: {
425-
a: 1
426-
b: _|_ // errorStructDef.b: conflicting values 2 and 1
427-
#Def: 1
428-
}
429-
errorList: [1, _|_]
430-
x: int
431-
errorListDef: {
432-
#Def: 1
433-
[1, _|_]
434-
}
435-
}
436-
== Eval
437-
_|_ // e3: index out of range [2] with length 2
438-
-- diff/-out/value-v3<==>+out/value --
439-
diff old new
440-
--- old
441-
+++ new
442-
@@ -56,8 +56,8 @@
443-
e1: <1.0
444-
e2: >1.0 & <10
445-
e3: _|_ // e3: index out of range [2] with length 2
446-
- e4: _|_ // e4: index 3 out of range
447-
- e5: _|_ // e3: index out of range [2] with length 2
448-
+ e4: _|_ // e4: index 3 out of range (and 1 more errors)
449-
+ e5: _|_ // e3: index out of range [2] with length 2 (and 1 more errors)
450-
e6: false
451-
e7: true
452-
e8?: true
453340
-- diff/value/todo/p3 --
454341
Error message change.
455342
-- out/value --

internal/core/export/testdata/main/let.txtar

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ y: Y & Y_1
583583
}
584584
== Final
585585
{
586-
comprehension: _|_ // comprehension: key value of dynamic field must be concrete, found _|_(invalid interpolation: invalid interpolation: comprehension.filepath: undefined field: name (and 1 more errors)) (and 2 more errors)
586+
comprehension: _|_ // comprehension: key value of dynamic field must be concrete, found _|_(invalid interpolation: invalid interpolation: comprehension.filepath: undefined field: name) (and 1 more errors)
587587
complete: {
588588
x: "a foo z"
589589
run: {
@@ -599,7 +599,7 @@ y: Y & Y_1
599599
name: "two"
600600
}
601601
}]
602-
files: _|_ // files: key value of dynamic field must be concrete, found _|_(invalid interpolation: invalid interpolation: filepath: undefined field: name (and 1 more errors)) (and 5 more errors)
602+
files: _|_ // files: key value of dynamic field must be concrete, found _|_(invalid interpolation: invalid interpolation: filepath: undefined field: name) (and 3 more errors)
603603
scoped: {
604604
direct: {
605605
a: 1
@@ -625,20 +625,20 @@ y: Y & Y_1
625625
x: "foo"
626626
incomplete: {
627627
a: {
628-
x: _|_ // invalid interpolation: incomplete.a.x: non-concrete value string (type string) (and 1 more errors)
628+
x: _|_ // invalid interpolation: incomplete.a.x: non-concrete value string (type string)
629629
run: {
630630
a: string
631631
}
632632
}
633633
b: {
634-
x: _|_ // invalid interpolation: incomplete.b.x: non-concrete value string (type string) (and 1 more errors)
634+
x: _|_ // invalid interpolation: incomplete.b.x: non-concrete value string (type string)
635635
run: {
636636
a: string
637637
}
638638
}
639639
c: {
640-
x: _|_ // invalid interpolation: incomplete.c.x: non-concrete value string (type string) (and 1 more errors)
641-
x2: _|_ // invalid interpolation: incomplete.c.x2: non-concrete value string (type string) (and 1 more errors)
640+
x: _|_ // invalid interpolation: incomplete.c.x: non-concrete value string (type string)
641+
x2: _|_ // invalid interpolation: incomplete.c.x2: non-concrete value string (type string)
642642
run: {
643643
a: string
644644
}
@@ -647,8 +647,8 @@ y: Y & Y_1
647647
}
648648
}
649649
d: {
650-
x: _|_ // invalid interpolation: incomplete.d.x: non-concrete value string (type string) (and 1 more errors)
651-
x2: _|_ // invalid interpolation: incomplete.d.x2: non-concrete value string (type string) (and 1 more errors)
650+
x: _|_ // invalid interpolation: incomplete.d.x: non-concrete value string (type string)
651+
x2: _|_ // invalid interpolation: incomplete.d.x2: non-concrete value string (type string)
652652
run: {
653653
a: string
654654
}
@@ -895,7 +895,7 @@ y: Y & Y_1
895895
diff old new
896896
--- old
897897
+++ new
898-
@@ -216,72 +216,72 @@
898+
@@ -216,23 +216,23 @@
899899
}
900900
== Final
901901
{

internal/core/export/testdata/main/simplify.txtar

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -39,83 +39,6 @@ additional: {
3939
[additional]
4040
[additional env]
4141
[additional confs]
42-
-- out/value-v3 --
43-
== Simplified
44-
{
45-
x: {
46-
y: int64
47-
}
48-
s: strings.MinRunes(4) & strings.MaxRunes(7)
49-
additional: {
50-
env: _
51-
confs: {
52-
if env {}
53-
}
54-
}
55-
}
56-
== Raw
57-
{
58-
x: {
59-
y: >=-9223372036854775808 & <=9223372036854775807 & int
60-
}
61-
s: strings.MinRunes(4) & strings.MaxRunes(7)
62-
additional: {
63-
env: _
64-
confs: {
65-
if env {}
66-
}
67-
}
68-
}
69-
== Final
70-
{
71-
x: {
72-
y: int64
73-
}
74-
s: strings.MinRunes(4) & strings.MaxRunes(7)
75-
additional: {
76-
env: _
77-
confs: _|_ // additional.confs: incomplete bool: _ (and 1 more errors)
78-
}
79-
}
80-
== All
81-
{
82-
x: {
83-
y: int64
84-
}
85-
s: strings.MinRunes(4) & strings.MaxRunes(7)
86-
additional: {
87-
env: _
88-
confs: {
89-
if env {}
90-
}
91-
}
92-
}
93-
== Eval
94-
{
95-
x: {
96-
y: >=-9223372036854775808 & <=9223372036854775807 & int
97-
}
98-
s: strings.MinRunes(4) & strings.MaxRunes(7)
99-
additional: {
100-
env: _
101-
confs: {
102-
if env {}
103-
}
104-
}
105-
}
106-
-- diff/-out/value-v3<==>+out/value --
107-
diff old new
108-
--- old
109-
+++ new
110-
@@ -32,7 +32,7 @@
111-
s: strings.MinRunes(4) & strings.MaxRunes(7)
112-
additional: {
113-
env: _
114-
- confs: _|_ // additional.confs: incomplete bool: _ (and 2 more errors)
115-
+ confs: _|_ // additional.confs: incomplete bool: _ (and 1 more errors)
116-
}
117-
}
118-
== All
11942
-- diff/value/explanation --
12043
Benign change in error message.
12144
-- out/value --
@@ -153,7 +76,7 @@ Benign change in error message.
15376
s: strings.MinRunes(4) & strings.MaxRunes(7)
15477
additional: {
15578
env: _
156-
confs: _|_ // additional.confs: incomplete bool: _ (and 2 more errors)
79+
confs: _|_ // additional.confs: incomplete bool: _
15780
}
15881
}
15982
== All

0 commit comments

Comments
 (0)