java-topology/defects/scala3/patch/scala3-0001-ordering-constraint-set.patch

103 lines
5.7 KiB
Diff

# UNDF: UNDF-2026-000000271
diff --git a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
index 0154c70..c88a321 100644
--- a/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
+++ b/compiler/src/dotty/tools/dotc/core/OrderingConstraint.scala
@@ -41,8 +41,9 @@ object OrderingConstraint {
/** The type of `OrderingConstraint#boundsMap` */
private type ParamBounds = ArrayValuedMap[Type]
- /** The type of `OrderingConstraint#lowerMap`, `OrderingConstraint#upperMap` */
- private type ParamOrdering = ArrayValuedMap[List[TypeParamRef]]
+ /** The type of `OrderingConstraint#lowerMap`, `OrderingConstraint#upperMap`.
+ * Each entry is a Set for O(1) membership tests in `isLess` (CWE-407 fix). */
+ private type ParamOrdering = ArrayValuedMap[Set[TypeParamRef]]
/** A lens for updating a single entry array in one of the three constraint maps */
private abstract class ConstraintLens[T <: AnyRef: ClassTag] {
@@ -106,20 +107,20 @@ object OrderingConstraint {
def initial = NoType
}
- private val lowerLens: ConstraintLens[List[TypeParamRef]] = new ConstraintLens[List[TypeParamRef]] {
- def entries(c: OrderingConstraint, poly: TypeLambda): Array[List[TypeParamRef]] | Null =
+ private val lowerLens: ConstraintLens[Set[TypeParamRef]] = new ConstraintLens[Set[TypeParamRef]] {
+ def entries(c: OrderingConstraint, poly: TypeLambda): Array[Set[TypeParamRef]] | Null =
c.lowerMap(poly)
- def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[List[TypeParamRef]])(using Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[Set[TypeParamRef]])(using Context): OrderingConstraint =
c.newConstraint(lowerMap = c.lowerMap.updated(poly, entries))
- def initial = Nil
+ def initial = Set.empty
}
- private val upperLens: ConstraintLens[List[TypeParamRef]] = new ConstraintLens[List[TypeParamRef]] {
- def entries(c: OrderingConstraint, poly: TypeLambda): Array[List[TypeParamRef]] | Null =
+ private val upperLens: ConstraintLens[Set[TypeParamRef]] = new ConstraintLens[Set[TypeParamRef]] {
+ def entries(c: OrderingConstraint, poly: TypeLambda): Array[Set[TypeParamRef]] | Null =
c.upperMap(poly)
- def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[List[TypeParamRef]])(using Context): OrderingConstraint =
+ def updateEntries(c: OrderingConstraint, poly: TypeLambda, entries: Array[Set[TypeParamRef]])(using Context): OrderingConstraint =
c.newConstraint(upperMap = c.upperMap.updated(poly, entries))
- def initial = Nil
+ def initial = Set.empty
}
@sharable
@@ -207,8 +208,12 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ---------- Dependency handling ----------------------------------------------
- def lower(param: TypeParamRef): List[TypeParamRef] = lowerLens(this, param.binder, param.paramNum)
- def upper(param: TypeParamRef): List[TypeParamRef] = upperLens(this, param.binder, param.paramNum)
+ // Private O(1)-membership set accessors (internal use only, avoids .toList cost in isLess)
+ private def lowerSet(param: TypeParamRef): Set[TypeParamRef] = lowerLens(this, param.binder, param.paramNum)
+ private def upperSet(param: TypeParamRef): Set[TypeParamRef] = upperLens(this, param.binder, param.paramNum)
+
+ def lower(param: TypeParamRef): List[TypeParamRef] = lowerSet(param).toList
+ def upper(param: TypeParamRef): List[TypeParamRef] = upperSet(param).toList
def minLower(param: TypeParamRef): List[TypeParamRef] = {
val all = lower(param)
@@ -240,7 +245,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// ---------- Info related to TypeParamRefs -------------------------------------------
def isLess(param1: TypeParamRef, param2: TypeParamRef): Boolean =
- upper(param1).contains(param2)
+ upperSet(param1).contains(param2) // O(1) hash lookup; was O(n) List.contains (CWE-407)
def nonParamBounds(param: TypeParamRef)(using Context): TypeBounds =
entry(param).bounds
@@ -624,8 +629,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
else
param1 :: lower
}
- val current1 = newLower.foldLeft(current)(upperLens.map(this, _, _, newUpper ::: _))
- val current2 = newUpper.foldLeft(current1)(lowerLens.map(this, _, _, newLower ::: _))
+ val current1 = newLower.foldLeft(current)(upperLens.map(this, _, _, _ ++ newUpper))
+ val current2 = newUpper.foldLeft(current1)(lowerLens.map(this, _, _, _ ++ newLower))
current2
end if
end order
@@ -697,8 +702,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
// dependency adjustment, we need to pretend that `param` is still unbound.
// We achieve that by passing a `ignoreBinding = param` to `adjustDeps` below.
- def removeParamFrom(ps: List[TypeParamRef]) =
- ps.filterConserve(param ne _)
+ def removeParamFrom(ps: Set[TypeParamRef]) =
+ ps - param
for lo <- lower(param) do
current = upperLens.map(this, current, lo, removeParamFrom)
@@ -764,8 +769,8 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
def remove(pt: TypeLambda)(using Context): This = {
def removeFromOrdering(po: ParamOrdering) = {
- def removeFromBoundss(key: TypeLambda, bndss: Array[List[TypeParamRef]]): Array[List[TypeParamRef]] = {
- val bndss1 = bndss.map(_.filterConserve(_.binder ne pt))
+ def removeFromBoundss(key: TypeLambda, bndss: Array[Set[TypeParamRef]]): Array[Set[TypeParamRef]] = {
+ val bndss1 = bndss.map(_.filterNot(_.binder eq pt))
if (bndss.corresponds(bndss1)(_ eq _)) bndss else bndss1
}
po.remove(pt).mapValuesNow(removeFromBoundss)