java-topology/defects/scala3/patch/scala3-diamond-recursion-CLEAN.md
russell@unturf.com 1dee074618 kafka-0009: GraphGraceSearchUtil diamond recursion O(2^D) → O(N); count 621→622
findAndVerifyWindowGrace() recurses over parent GraphNodes without a visited
accumulator. Kafka Streams GraphNode is a genuine DAG (addChild wires
parent→child with multiple parents allowed), so a diamond topology causes
2^D recursive calls. Fix: thread an IdentityHashMap<GraphNode,Long> memo
through recursion; memoize on first visit, return cached result on revisit.
8/8 unit tests PASS; D=10 defect count=3071 vs patched O(N).

Diamond-recursion CLEAN markers added for: flink, neo4j, janusgraph,
tinkerpop, dgraph, zookeeper, storm, ant, gradle, graal, eclipse-jdt,
exposed, intellij, kotlin, scala3, hibernate-0007 (prior session work
now committed).
2026-03-29 16:59:50 -04:00

1.7 KiB

Scala 3 Compiler — Diamond Recursion CWE-407 Scan: CLEAN

Pattern: Recursive cycle/reachability without visited set (O(2^D) on diamond DAGs) Scan date: 2026-03-29 Scope: compiler/src/dotty/

Method

Searched for isCyclic, hasCycle, createsCycle, isReachable, canReach, hasPath, detectCycle across all Scala sources. Examined recursive functions for missing visited-accumulator parameters.

Key candidates reviewed

SymDenotations.computeBaseType()recur() inner function

compiler/src/dotty/tools/dotc/core/SymDenotations.scala around line 2265.

recur(tp) is called recursively but uses btrCache as a memoization cache. Before recursing, it checks btrCache.lookup(tp) for a sentinel value (NoPrefix) that indicates a cycle in progress. This is a memo-table anti-cycle pattern. CLEAN.

OrderingConstraint.dependsOn()

compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala line 286.

Uses deps.at(param).exists(qualifies) — direct set lookup, not recursive. CLEAN.

Checking.CheckNonCyclicMap

compiler/src/dotty/tools/dotc/typer/Checking.scala line 257.

CheckNonCyclicMap extends TypeMap and uses a cycleOK flag plus CyclicReference exception for cycle detection. Not diamond recursion — uses exception-based unwinding, not unbounded recursion. CLEAN.

SymUtils.isReachable

compiler/src/dotty/tools/dotc/core/SymUtils.scala line 211.

Returns ctx.owner.isContainedIn(sym) — single O(depth) tree traversal. Not a DAG traversal. CLEAN.

Verdict

CLEAN for diamond recursion pattern. Scala 3 compiler uses btrCache memo tables, exception-based cycle detection, and O(depth) tree traversals. No unprotected recursive DAG traversal found.