Skip to content

Commit 8c6cd67

Browse files
Try to fix spurious circular task errors (#6062)
Fixes #6060 My guess is that the problem is the `LinkedHashSet` in `Cacher.taskEvaluationStack` is actually a mutable collection shared between different threads. That could potentially cause all sorts of problems, so this replaces it with a immutable `VectorMap` to preserve ordering and provide lookups in an immutable fashion --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 28ae756 commit 8c6cd67

File tree

1 file changed

+6
-8
lines changed

1 file changed

+6
-8
lines changed

core/api/src/mill/api/internal/Cacher.scala

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package mill.api.internal
22

3-
import collection.mutable.LinkedHashSet
3+
import scala.collection.immutable.VectorMap
44
import scala.collection.mutable
55
import scala.util.DynamicVariable
66
import scala.quoted.*
@@ -12,7 +12,8 @@ trait Cacher extends mill.moduledefs.Cacher {
1212
if (Cacher.taskEvaluationStack.value.contains((c, this))) {
1313
sys.error(
1414
"Circular task dependency detected:\n" +
15-
(Cacher.taskEvaluationStack.value.toList ++ Seq((c, this)))
15+
16+
(Cacher.taskEvaluationStack.value.keys ++ Seq((c, this)))
1617
.map { case (c, o) =>
1718
val taskName = c.value.split("\\.|#| ").filter(!_.startsWith("$anon")).last
1819
o.toString match {
@@ -24,19 +25,16 @@ trait Cacher extends mill.moduledefs.Cacher {
2425
)
2526
}
2627

27-
try {
28-
Cacher.taskEvaluationStack.value.add((c, this))
28+
Cacher.taskEvaluationStack.withValue(Cacher.taskEvaluationStack.value ++ Seq((c, this) -> ())) {
2929
cacherLazyMap.getOrElseUpdate(c, t).asInstanceOf[T]
30-
} finally {
31-
Cacher.taskEvaluationStack.value.remove((c, this))
3230
}
3331
}
3432
}
3533

3634
private[mill] object Cacher {
37-
// Use a LinkedHashSet for fast contains checking while preserving insertion order
35+
// Use a VectorMap for fast contains checking while preserving insertion order
3836
private[mill] val taskEvaluationStack =
39-
DynamicVariable[LinkedHashSet[(sourcecode.Enclosing, Any)]](LinkedHashSet())
37+
DynamicVariable[VectorMap[(sourcecode.Enclosing, Any), Unit]](VectorMap())
4038
private[mill] def withMacroOwner[T](using Quotes)(op: quotes.reflect.Symbol => T): T = {
4139
import quotes.reflect.*
4240
// In Scala 3, the top level splice of a macro is owned by a symbol called "macro" with the macro flag set,

0 commit comments

Comments
 (0)