@@ -137,6 +137,7 @@ package toposort
137
137
138
138
import (
139
139
"fmt"
140
+ "maps"
140
141
"slices"
141
142
142
143
"cuelang.org/go/cue/token"
@@ -218,7 +219,18 @@ func (sm *structMeta) hasDynamic(dynFieldsMap map[*adt.DynamicField][]adt.Featur
218
219
// the binary expression, and mark them as explicit unification.
219
220
func analyseStructs (v * adt.Vertex , builder * GraphBuilder ) []* structMeta {
220
221
structInfos := v .Structs
221
- nodeToStructMeta := make (map [adt.Node ][]* structMeta )
222
+ // Note that it's important that nodeToStructMetas avoids duplicate entries,
223
+ // which cause significant slowness for some large configs.
224
+ nodeToStructMetas := make (map [adt.Node ]map [* structMeta ]bool )
225
+ // structMetaMap is heplful as we can't insert into a map unless we make it.
226
+ structMetaMap := func (node adt.Node ) map [* structMeta ]bool {
227
+ if m := nodeToStructMetas [node ]; m != nil {
228
+ return m
229
+ }
230
+ m := make (map [* structMeta ]bool )
231
+ nodeToStructMetas [node ] = m
232
+ return m
233
+ }
222
234
structMetas := make ([]* structMeta , 0 , len (structInfos ))
223
235
224
236
// Create all the structMetas and map to them from a StructInfo's
@@ -235,9 +247,9 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
235
247
if src := sl .Source (); src != nil {
236
248
sMeta .pos = src .Pos ()
237
249
}
238
- nodeToStructMeta [ sl ] = append ( nodeToStructMeta [ sl ], sMeta )
250
+ structMetaMap ( sl )[ sMeta ] = true
239
251
for _ , decl := range sl .Decls {
240
- nodeToStructMeta [ decl ] = append ( nodeToStructMeta [ decl ], sMeta )
252
+ structMetaMap ( decl )[ sMeta ] = true
241
253
}
242
254
}
243
255
@@ -250,12 +262,12 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
250
262
field := c .Field ()
251
263
debug ("self arc conjunct field %p :: %T, expr %p :: %T (%v)\n " ,
252
264
field , field , c .Expr (), c .Expr (), c .Expr ().Source ())
253
- sMetas , found := nodeToStructMeta [field ]
265
+ sMetas , found := nodeToStructMetas [field ]
254
266
if ! found {
255
267
return true
256
268
}
257
269
if src := field .Source (); src != nil {
258
- for _ , sMeta := range sMetas {
270
+ for sMeta := range sMetas {
259
271
sMeta .pos = src .Pos ()
260
272
}
261
273
}
@@ -270,9 +282,9 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
270
282
debug (" ref %p :: %T (%v)\n " ,
271
283
refs .Ref , refs .Ref , refs .Ref .Source ().Pos ())
272
284
}
273
- nodeToStructMeta [ refs . Ref ] = append ( nodeToStructMeta [ refs .Ref ], sMetas ... )
285
+ maps . Insert ( structMetaMap ( refs .Ref ), maps . All ( sMetas ) )
274
286
if pos := refs .Ref .Source ().Pos (); pos != token .NoPos {
275
- for _ , sMeta := range nodeToStructMeta [refs .Ref ] {
287
+ for sMeta := range nodeToStructMetas [refs .Ref ] {
276
288
sMeta .pos = pos
277
289
}
278
290
}
@@ -307,7 +319,7 @@ func analyseStructs(v *adt.Vertex, builder *GraphBuilder) []*structMeta {
307
319
continue
308
320
}
309
321
for _ , expr := range []adt.Expr {binExpr .X , binExpr .Y } {
310
- for _ , sMeta := range nodeToStructMeta [expr ] {
322
+ for sMeta := range nodeToStructMetas [expr ] {
311
323
sMeta .isExplicit = true
312
324
debug (" now explicit: %v\n " , sMeta )
313
325
}
0 commit comments