( body: Expression, collection: Expression, ce: ComputeEngine )
| 455 | // item 52): at or below `MAX_SIZE_EAGER_COLLECTION` the distribution |
| 456 | // is materialized into a `List`; past the threshold the held `When` is |
| 457 | // kept and its `collection` handlers (see `whenCollectionHandlers`) |
| 458 | // expose the same elements lazily. The type check gates the extra |
| 459 | // `evaluate` so a scalar `When` keeps its held form unchanged. |
| 460 | // A `Tuple` is excluded: it is a fixed-arity structure (a point), not a |
| 461 | // list to broadcast over, so a restricted point must stay a point |
| 462 | // rather than degrade to a `List`. Mirrors `PointList`'s |
| 463 | // `isListComponent` predicate in `collections.ts`. |
| 464 | // A tuple-typed value is excluded before it is evaluated: evaluating |
| 465 | // it here would force every component of a value the restriction is |
| 466 | // meant to keep held, changing the lazy guard semantics for a shape |
| 467 | // that can never enter the distribution path anyway. |
| 468 | // A STRING is excluded for the same reason a tuple is: it is an |
| 469 | // indexed collection of characters, but it is atomic under |
| 470 | // element-wise distribution, so `When("ab", c)` must stay a restricted |
| 471 | // string rather than become a list of restricted characters. |
| 472 | // A CONDITION that is collection-typed but carries no value yet is a |
| 473 | // MASK that cannot be read yet, not the scalar guard this branch |
| 474 | // distributes: splicing it into every cell freezes a nested result. |
| 475 | // `When([1,2], B)` for a valueless `B: list<boolean>` gave |
| 476 | // `[1 {B}, 2 {B}]`, which re-evaluates to `[[1,Undefined],[2,Undefined]]` |
| 477 | // once `B := [True, False]` — where the same expression evaluated |
| 478 | // fresh masks to `[1, Undefined]` (Tycho item 221). Stay held; the |
| 479 | // list-condition branch above zips the mask once it resolves. |
| 480 | if ( |
| 481 | expr.type.matches('collection<any>') && |
| 482 | !isTupleShapedType(expr.type.type) && |
| 483 | !expr.type.matches('string') && |
| 484 | !isUnresolvedCollectionOperand(c) |
| 485 | ) { |
| 486 | const ev = expr.evaluate(options); |
| 487 | if (isFiniteBroadcastParticipant(ev)) { |
| 488 | const n = ev.count ?? Infinity; |
| 489 | if (n <= MAX_SIZE_EAGER_COLLECTION) { |
| 490 | const result = Array.from(ev.each()).map((elem) => |
| 491 | ce._fn('When', [elem, c]) |
| 492 | ); |
| 493 | return ce._fn('List', result); |
| 494 | } |
| 495 | // Too large to materialize: hold the (evaluated) collection so the |
| 496 | // collection handlers can walk it. |
| 497 | return ce._fn('When', [ev, c]); |
| 498 | } |
no test coverage detected