From f3d61a2106de2a700dee9b8424debcfd24e44472 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 9 May 2022 14:03:39 -0400 Subject: [PATCH] Port Settings --- .../main/scala/sbt/internal/util/AList.scala | 30 + .../sbt/internal/util/INode.scala | 149 ++-- .../sbt/internal/util/Settings.scala | 772 +++++++++--------- .../sbt/internal/util/TypeFunctions.scala | 3 +- .../{scala-2 => scala}/SettingsExample.scala | 55 +- 5 files changed, 539 insertions(+), 470 deletions(-) rename util-collection/src/main/{scala-2 => scala}/sbt/internal/util/INode.scala (55%) rename util-collection/src/main/{scala-2 => scala}/sbt/internal/util/Settings.scala (53%) rename util-collection/src/test/{scala-2 => scala}/SettingsExample.scala (67%) diff --git a/util-collection/src/main/scala/sbt/internal/util/AList.scala b/util-collection/src/main/scala/sbt/internal/util/AList.scala index 73160b6ae..6a79bdfe1 100644 --- a/util-collection/src/main/scala/sbt/internal/util/AList.scala +++ b/util-collection/src/main/scala/sbt/internal/util/AList.scala @@ -58,6 +58,36 @@ object AList: // givens for tuple map given [Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] = tuple[Tup] + type Empty = AList[[F[_]] =>> Unit] + + lazy val empty: Empty = new Empty: + override def transform[F1[_], F2[_]](value: Unit)(f: [x] => F1[x] => F2[x]): Unit = () + override def traverse[F1[_], F2[_]: Applicative](value: Unit)( + f: [a] => F1[a] => F2[a] + ): F2[Unit] = summon[Applicative[F2]].pure(()) + override def traverseX[F1[_], F2[_]: Applicative, P[_]](value: Unit)( + f: [a] => F1[a] => F2[P[a]] + ): F2[Unit] = summon[Applicative[F2]].pure(()) + override def foldr[F1[_], A2](value: Unit, init: A2)( + f: [a] => (F1[a], A2) => A2 + ): A2 = init + + def single[A1]: AList[[F[_]] =>> F[A1]] = + new AList[[F[_]] =>> F[A1]]: + override def transform[F1[_], F2[_]](value: F1[A1])(f: [x] => F1[x] => F2[x]): F2[A1] = + f(value) + override def traverse[F1[_], F2[_]: Applicative](value: F1[A1])( + f: [a] => F1[a] => F2[a] + ): F2[A1] = f(value) + override def traverseX[F1[_], F2[_]: Applicative, P[_]](value: F1[A1])( + f: [a] => F1[a] => F2[P[a]] + ): F2[P[A1]] = f(value) + override def foldr[F1[_], A2](value: F1[A1], init: A2)( + f: [a] => (F1[a], A2) => A2 + ): A2 = f(value, init) + + def tuple2[A1, A2]: AList[[F[_]] =>> Tuple.Map[(A1, A2), F]] = tuple[(A1, A2)] + def tuple[Tup <: Tuple]: AList[[F[_]] =>> Tuple.Map[Tup, F]] = new AList[[F[_]] =>> Tuple.Map[Tup, F]]: override def transform[F1[_], F2[_]](value: Tuple.Map[Tup, F1])( diff --git a/util-collection/src/main/scala-2/sbt/internal/util/INode.scala b/util-collection/src/main/scala/sbt/internal/util/INode.scala similarity index 55% rename from util-collection/src/main/scala-2/sbt/internal/util/INode.scala rename to util-collection/src/main/scala/sbt/internal/util/INode.scala index a10a52870..45bdf4158 100644 --- a/util-collection/src/main/scala-2/sbt/internal/util/INode.scala +++ b/util-collection/src/main/scala/sbt/internal/util/INode.scala @@ -10,51 +10,56 @@ package sbt.internal.util import java.lang.Runnable import java.util.concurrent.{ atomic, Executor, LinkedBlockingQueue } import atomic.{ AtomicBoolean, AtomicInteger } -import Types.{ ConstK, Id } +import Types.Id -object EvaluationState extends Enumeration { - val New, Blocked, Ready, Calling, Evaluated = Value -} +enum EvaluationState: + case New + case Blocked + case Ready + case Calling + case Evaluated -/* -abstract class EvaluateSettings[ScopeType] { +abstract class EvaluateSettings[ScopeType]: protected val init: Init[ScopeType] import init._ protected def executor: Executor protected def compiledSettings: Seq[Compiled[_]] - import EvaluationState.{ Value => EvaluationState, _ } + import EvaluationState.* private[this] val complete = new LinkedBlockingQueue[Option[Throwable]] private[this] val static = PMap.empty[ScopedKey, INode] private[this] val allScopes: Set[ScopeType] = compiledSettings.map(_.key.scope).toSet - private[this] def getStatic[T](key: ScopedKey[T]): INode[T] = - static get key getOrElse sys.error("Illegal reference to key " + key) + private[this] def getStatic[A](key: ScopedKey[A]): INode[A] = + static.get(key).getOrElse { sys.error("Illegal reference to key " + key) } - private[this] val transform: Initialize ~> INode = λ[Initialize ~> INode] { - case k: Keyed[s, A1$] @unchecked => single(getStatic(k.scopedKey), k.transform) - case a: Apply[k, A1$] @unchecked => - new MixedNode[k, A1$]( - a.alist.transform[Initialize, INode](a.inputs, transform), - a.f, - a.alist - ) - case b: Bind[s, A1$] @unchecked => new BindNode[s, A1$](transform(b.in), x => transform(b.f(x))) - case v: Value[A1$] @unchecked => constant(v.value) - case v: ValidationCapture[A1$] @unchecked => strictConstant(v.key: A1$) - case t: TransformCapture => strictConstant(t.f: A1$) - case o: Optional[s, A1$] @unchecked => - o.a match { - case None => constant(() => o.f(None)) - case Some(i) => single[s, A1$](transform(i), x => o.f(Some(x))) - } - case x if x == StaticScopes => - strictConstant(allScopes.asInstanceOf[A1$]) // can't convince scalac that StaticScopes => T == Set[Scope] - } + private[this] val transform: [A] => Initialize[A] => INode[A] = [A] => + (fa: Initialize[A]) => + fa match + case k: Keyed[s, A] @unchecked => single(getStatic(k.scopedKey), k.transform) + case a: Apply[k, A] @unchecked => + MixedNode[k, A]( + a.alist.transform[Initialize, INode](a.inputs) { transform }, + a.f, + a.alist + ) + case b: Bind[s, A] @unchecked => + new BindNode[s, A](transform(b.in), x => transform(b.f(x))) + case v: Value[A] @unchecked => constant(v.value) + case v: ValidationCapture[A] @unchecked => strictConstant(v.key: A) + case t: TransformCapture => strictConstant(t.f: A) + case o: Optional[s, A] @unchecked => + o.a match + case None => constant(() => o.f(None)) + case Some(i) => single[s, A](transform(i), x => o.f(Some(x))) + case x if x == StaticScopes => + // can't convince scalac that StaticScopes => T == Set[Scope] + strictConstant(allScopes.asInstanceOf[A]) + // allScopes.asInstanceOf[A] - private[this] lazy val roots: Seq[INode[_]] = compiledSettings flatMap { cs => + private[this] lazy val roots: Seq[INode[_]] = compiledSettings.flatMap { cs => (cs.settings map { s => val t = transform(s.init) static(s.key) = t @@ -78,54 +83,52 @@ abstract class EvaluateSettings[ScopeType] { } private[this] def getResults(implicit delegates: ScopeType => Seq[ScopeType]) = - static.toTypedSeq.foldLeft(empty) { - case (ss, static.TPair(key, node)) => - if (key.key.isLocal) ss else ss.set(key.scope, key.key, node.get) + static.toTypedSeq.foldLeft(empty) { case (ss, static.TPair(key, node)) => + if key.key.isLocal then ss + else ss.set(key.scope, key.key, node.get) } - private[this] val getValue = λ[INode ~> Id](_.get) + private[this] lazy val getValue: [A] => INode[A] => Id[A] = [A] => (fa: INode[A]) => fa.get private[this] def submitEvaluate(node: INode[_]) = submit(node.evaluate()) - private[this] def submitCallComplete[T](node: BindNode[_, T], value: T) = + private[this] def submitCallComplete[A](node: BindNode[_, A], value: A) = submit(node.callComplete(value)) - private[this] def submit(work: => Unit): Unit = { + private[this] def submit(work: => Unit): Unit = startWork() - executor.execute(new Runnable { def run = if (!cancel.get()) run0(work) }) - } + // new Runnable { def run = if (!cancel.get()) run0(work) } + executor.execute(() => if !cancel.get() then run0(work) else ()) - private[this] def run0(work: => Unit): Unit = { + private[this] def run0(work: => Unit): Unit = try { work } catch { case e: Throwable => complete.put(Some(e)) } workComplete() - } private[this] def startWork(): Unit = { running.incrementAndGet(); () } private[this] def workComplete(): Unit = - if (running.decrementAndGet() == 0) - complete.put(None) + if running.decrementAndGet() == 0 then complete.put(None) + else () - private[this] sealed abstract class INode[T] { + private[this] sealed abstract class INode[A1]: private[this] var state: EvaluationState = New - private[this] var value: T = _ + private[this] var value: A1 = _ private[this] val blocking = new collection.mutable.ListBuffer[INode[_]] private[this] var blockedOn: Int = 0 - private[this] val calledBy = new collection.mutable.ListBuffer[BindNode[_, T]] + private[this] val calledBy = new collection.mutable.ListBuffer[BindNode[_, A1]] - override def toString = + override def toString(): String = getClass.getName + " (state=" + state + ",blockedOn=" + blockedOn + ",calledBy=" + calledBy.size + ",blocking=" + blocking.size + "): " + keyString private[this] def keyString = - (static.toSeq.flatMap { - case (key, value) => - if (value eq this) init.showFullKey.show(key) :: Nil else List.empty[String] + (static.toSeq.flatMap { case (key, value) => + if (value eq this) init.showFullKey.show(key) :: Nil else List.empty[String] }).headOption getOrElse "non-static" - final def get: T = synchronized { + final def get: A1 = synchronized { assert(value != null, toString + " not evaluated") value } @@ -149,10 +152,8 @@ abstract class EvaluateSettings[ScopeType] { assert(state == New, "Already registered and: " + toString) val deps = dependsOn blockedOn = deps.size - deps.count(_.doneOrBlock(this)) - if (blockedOn == 0) - schedule() - else - state = Blocked + if blockedOn == 0 then schedule() + else state = Blocked } final def schedule(): Unit = synchronized { @@ -170,13 +171,13 @@ abstract class EvaluateSettings[ScopeType] { final def evaluate(): Unit = synchronized { evaluate0() } - protected final def makeCall(source: BindNode[_, T], target: INode[T]): Unit = { + protected final def makeCall(source: BindNode[_, A1], target: INode[A1]): Unit = { assert(state == Ready, "Invalid state for call to makeCall: " + toString) state = Calling target.call(source) } - protected final def setValue(v: T): Unit = { + protected final def setValue(v: A1): Unit = { assert( state != Evaluated, "Already evaluated (trying to set value to " + v + "): " + toString @@ -192,7 +193,7 @@ abstract class EvaluateSettings[ScopeType] { calledBy.clear() } - final def call(by: BindNode[_, T]): Unit = synchronized { + final def call(by: BindNode[_, A1]): Unit = synchronized { registerIfNew() state match { case Evaluated => submitCallComplete(by, value) @@ -204,29 +205,29 @@ abstract class EvaluateSettings[ScopeType] { protected def dependsOn: Seq[INode[_]] protected def evaluate0(): Unit - } + end INode - private[this] def strictConstant[T](v: T): INode[T] = constant(() => v) + private[this] def strictConstant[A1](v: A1): INode[A1] = constant(() => v) - private[this] def constant[T](f: () => T): INode[T] = - new MixedNode[ConstK[Unit]#l, T]((), _ => f(), AList.empty) + private[this] def constant[A1](f: () => A1): INode[A1] = + MixedNode[[F[_]] =>> Unit, A1]((), _ => f(), AList.empty) - private[this] def single[S, T](in: INode[S], f: S => T): INode[T] = - new MixedNode[λ[L[x] => L[S]], T](in, f, AList.single[S]) + private[this] def single[A1, A2](in: INode[A1], f: A1 => A2): INode[A2] = + MixedNode[[F[_]] =>> F[A1], A2](in, f, AList.single[A1]) - private[this] final class BindNode[S, T](in: INode[S], f: S => INode[T]) extends INode[T] { - protected def dependsOn = in :: Nil + private[this] final class BindNode[A1, A2](in: INode[A1], f: A1 => INode[A2]) extends INode[A2]: + protected def dependsOn: Seq[INode[_]] = in :: Nil protected def evaluate0(): Unit = makeCall(this, f(in.get)) - def callComplete(value: T): Unit = synchronized { + def callComplete(value: A2): Unit = synchronized { assert(isCalling, "Invalid state for callComplete(" + value + "): " + toString) setValue(value) } - } + end BindNode - private[this] final class MixedNode[K[L[x]], T](in: K[INode], f: K[Id] => T, alist: AList[K]) - extends INode[T] { - protected def dependsOn = alist.toList(in) - protected def evaluate0(): Unit = setValue(f(alist.transform(in, getValue))) - } -} - */ + private[this] final class MixedNode[K[L[x]], A1](in: K[INode], f: K[Id] => A1, alist: AList[K]) + extends INode[A1]: + protected override def dependsOn: Seq[INode[_]] = alist.toList(in) + protected override def evaluate0(): Unit = setValue(f(alist.transform(in) { getValue })) + end MixedNode + +end EvaluateSettings diff --git a/util-collection/src/main/scala-2/sbt/internal/util/Settings.scala b/util-collection/src/main/scala/sbt/internal/util/Settings.scala similarity index 53% rename from util-collection/src/main/scala-2/sbt/internal/util/Settings.scala rename to util-collection/src/main/scala/sbt/internal/util/Settings.scala index 4541980cd..22e3291f0 100644 --- a/util-collection/src/main/scala-2/sbt/internal/util/Settings.scala +++ b/util-collection/src/main/scala/sbt/internal/util/Settings.scala @@ -7,68 +7,74 @@ package sbt.internal.util -import Types._ +import Types.* import sbt.util.Show import Util.{ nil, nilSeq } -sealed trait Settings[ScopeType] { +sealed trait Settings[ScopeType]: def data: Map[ScopeType, AttributeMap] def keys(scope: ScopeType): Set[AttributeKey[_]] def scopes: Set[ScopeType] def definingScope(scope: ScopeType, key: AttributeKey[_]): Option[ScopeType] - def allKeys[T](f: (ScopeType, AttributeKey[_]) => T): Seq[T] - def get[T](scope: ScopeType, key: AttributeKey[T]): Option[T] - def getDirect[T](scope: ScopeType, key: AttributeKey[T]): Option[T] - def set[T](scope: ScopeType, key: AttributeKey[T], value: T): Settings[ScopeType] -} + def allKeys[A](f: (ScopeType, AttributeKey[_]) => A): Seq[A] + def get[A](scope: ScopeType, key: AttributeKey[A]): Option[A] + def getDirect[A](scope: ScopeType, key: AttributeKey[A]): Option[A] + def set[A](scope: ScopeType, key: AttributeKey[A], value: A): Settings[ScopeType] +end Settings private final class Settings0[ScopeType]( val data: Map[ScopeType, AttributeMap], val delegates: ScopeType => Seq[ScopeType] -) extends Settings[ScopeType] { +) extends Settings[ScopeType]: def scopes: Set[ScopeType] = data.keySet def keys(scope: ScopeType) = data(scope).keys.toSet - def allKeys[T](f: (ScopeType, AttributeKey[_]) => T): Seq[T] = - data.flatMap { case (scope, map) => map.keys.map(k => f(scope, k)) }.toSeq + def allKeys[A](f: (ScopeType, AttributeKey[_]) => A): Seq[A] = + data.flatMap { case (scope, map) => + map.keys.map(k => f(scope, k)) + }.toSeq - def get[T](scope: ScopeType, key: AttributeKey[T]): Option[T] = - delegates(scope).flatMap(sc => getDirect(sc, key)).headOption + def get[A](scope: ScopeType, key: AttributeKey[A]): Option[A] = + delegates(scope).flatMap { sc => + getDirect(sc, key) + }.headOption def definingScope(scope: ScopeType, key: AttributeKey[_]): Option[ScopeType] = - delegates(scope).find(sc => getDirect(sc, key).isDefined) + delegates(scope).find { sc => + getDirect(sc, key).isDefined + } - def getDirect[T](scope: ScopeType, key: AttributeKey[T]): Option[T] = - (data get scope).flatMap(_ get key) + def getDirect[A](scope: ScopeType, key: AttributeKey[A]): Option[A] = + data.get(scope).flatMap(_.get(key)) - def set[T](scope: ScopeType, key: AttributeKey[T], value: T): Settings[ScopeType] = { + def set[A](scope: ScopeType, key: AttributeKey[A], value: A): Settings[ScopeType] = val map = data.getOrElse(scope, AttributeMap.empty) val newData = data.updated(scope, map.put(key, value)) - new Settings0(newData, delegates) - } -} + Settings0(newData, delegates) + +end Settings0 // delegates should contain the input Scope as the first entry // this trait is intended to be mixed into an object -trait Init[ScopeType] { +trait Init[ScopeType]: - /** The Show instance used when a detailed String needs to be generated. + /** + * The Show instance used when a detailed String needs to be generated. * It is typically used when no context is available. */ def showFullKey: Show[ScopedKey[_]] - sealed case class ScopedKey[T](scope: ScopeType, key: AttributeKey[T]) - extends KeyedInitialize[T] { + sealed case class ScopedKey[A](scope: ScopeType, key: AttributeKey[A]) extends KeyedInitialize[A]: def scopedKey = this - } + end ScopedKey - type SettingSeq[T] = Seq[Setting[T]] + type SettingSeq[A] = Seq[Setting[A]] type ScopedMap = IMap[ScopedKey, SettingSeq] type CompiledMap = Map[ScopedKey[_], Compiled[_]] type MapScoped = ScopedKey ~> ScopedKey - type ValidatedRef[T] = Either[Undefined, ScopedKey[T]] - type ValidatedInit[T] = Either[Seq[Undefined], Initialize[T]] + type ValidatedRef[A] = Either[Undefined, ScopedKey[A]] + type ValidatedInit[A] = Either[Seq[Undefined], Initialize[A]] type ValidateRef = ScopedKey ~> ValidatedRef type ScopeLocal = ScopedKey[_] => Seq[Setting[_]] type MapConstant = ScopedKey ~> Option @@ -81,45 +87,46 @@ trait Init[ScopeType] { * The result of this initialization is the composition of applied transformations. * This can be useful when dealing with dynamic Initialize values. */ - lazy val capturedTransformations: Initialize[Initialize ~> Initialize] = - new TransformCapture(idK[Initialize]) + lazy val capturedTransformations: Initialize[[x] => Initialize[x] => Initialize[x]] = + TransformCapture(idK[Initialize]) - def setting[T]( - key: ScopedKey[T], - init: Initialize[T], + def setting[A1]( + key: ScopedKey[A1], + init: Initialize[A1], pos: SourcePosition = NoPosition - ): Setting[T] = new Setting[T](key, init, pos) + ): Setting[A1] = Setting[A1](key, init, pos) - def valueStrict[T](value: T): Initialize[T] = pure(() => value) - def value[T](value: => T): Initialize[T] = pure(value _) - def pure[T](value: () => T): Initialize[T] = new Value(value) - def optional[T, U](i: Initialize[T])(f: Option[T] => U): Initialize[U] = new Optional(Some(i), f) + def valueStrict[A1](value: A1): Initialize[A1] = pure(() => value) + def value[A1](value: => A1): Initialize[A1] = pure(() => value) + def pure[A1](value: () => A1): Initialize[A1] = Value(value) + def optional[A1, A2](i: Initialize[A1])(f: Option[A1] => A2): Initialize[A2] = + Optional(Some(i), f) - def update[T](key: ScopedKey[T])(f: T => T): Setting[T] = - setting[T](key, map(key)(f), NoPosition) + def update[A1](key: ScopedKey[A1])(f: A1 => A1): Setting[A1] = + setting[A1](key, map(key)(f), NoPosition) - def bind[S, T](in: Initialize[S])(f: S => Initialize[T]): Initialize[T] = new Bind(f, in) + def bind[A1, A2](in: Initialize[A1])(f: A1 => Initialize[A2]): Initialize[A2] = Bind(f, in) - def map[S, T](in: Initialize[S])(f: S => T): Initialize[T] = - new Apply[λ[L[x] => L[S]], T](f, in, AList.single[S]) + def map[A1, A2](in: Initialize[A1])(f: A1 => A2): Initialize[A2] = + Apply[[F[_]] =>> F[A1], A2](f, in, AList.single[A1]) - def app[K[L[x]], T](inputs: K[Initialize])(f: K[Id] => T)( - implicit alist: AList[K] - ): Initialize[T] = new Apply[K, T](f, inputs, alist) + def app[K[L[x]], T](inputs: K[Initialize])(f: K[Id] => T)(implicit + alist: AList[K] + ): Initialize[T] = Apply[K, T](f, inputs, alist) - def uniform[S, T](inputs: Seq[Initialize[S]])(f: Seq[S] => T): Initialize[T] = - new Apply[λ[L[x] => List[L[S]]], T](f, inputs.toList, AList.seq[S]) + def uniform[A1, A2](inputs: Seq[Initialize[A1]])(f: Seq[A1] => A2): Initialize[A2] = + Apply[[F[_]] =>> List[F[A1]], A2](f, inputs.toList, AList.list[A1]) /** * The result of this initialization is the validated `key`. * No dependency is introduced on `key`. If `selfRefOk` is true, validation will not fail if the key is referenced by a definition of `key`. * That is, key := f(validated(key).value) is allowed only if `selfRefOk == true`. */ - private[sbt] final def validated[T]( - key: ScopedKey[T], + private[sbt] final def validated[A1]( + key: ScopedKey[A1], selfRefOk: Boolean - ): ValidationCapture[T] = - new ValidationCapture(key, selfRefOk) + ): ValidationCapture[A1] = + ValidationCapture(key, selfRefOk) /** * Constructs a derived setting that will be automatically defined in every scope where one of its dependencies @@ -127,17 +134,17 @@ trait Init[ScopeType] { * A setting initialized with dynamic dependencies is only allowed if `allowDynamic` is true. * Only the static dependencies are tracked, however. Dependencies on previous values do not introduce a derived setting either. */ - final def derive[T]( - s: Setting[T], + final def derive[A1]( + s: Setting[A1], allowDynamic: Boolean = false, filter: ScopeType => Boolean = const(true), trigger: AttributeKey[_] => Boolean = const(true), default: Boolean = false - ): Setting[T] = { + ): Setting[A1] = deriveAllowed(s, allowDynamic) foreach sys.error - val d = new DerivedSetting[T](s.key, s.init, s.pos, filter, trigger) - if (default) d.default() else d - } + val d = new DerivedSetting[A1](s.key, s.init, s.pos, filter, trigger) + if default then d.default() + else d def deriveAllowed[T](s: Setting[T], allowDynamic: Boolean): Option[String] = s.init match { case _: Bind[_, _] if !allowDynamic => Some("Cannot derive from dynamic dependencies.") @@ -154,9 +161,10 @@ trait Init[ScopeType] { private[this] final def nextDefaultID(): Long = nextID.incrementAndGet() def empty(implicit delegates: ScopeType => Seq[ScopeType]): Settings[ScopeType] = - new Settings0(Map.empty, delegates) + Settings0(Map.empty, delegates) - def asTransform(s: Settings[ScopeType]): ScopedKey ~> Id = λ[ScopedKey ~> Id](k => getValue(s, k)) + def asTransform(s: Settings[ScopeType]): [A] => ScopedKey[A] => Id[A] = [A] => + (sk: ScopedKey[A]) => getValue(s, sk) def getValue[T](s: Settings[ScopeType], k: ScopedKey[T]) = s.get(k.scope, k.key) getOrElse (throw new InvalidReference(k)) @@ -167,11 +175,6 @@ trait Init[ScopeType] { def apply[T](k: ScopedKey[T]): ScopedKey[T] = k.copy(scope = f(k.scope)) } - private final class InvalidReference(val key: ScopedKey[_]) - extends RuntimeException( - "Internal settings error: invalid reference to " + showFullKey.show(key) - ) - private[this] def applyDefaults(ss: Seq[Setting[_]]): Seq[Setting[_]] = { val result = new java.util.LinkedHashSet[Setting[_]] val others = new java.util.ArrayList[Setting[_]] @@ -184,8 +187,8 @@ trait Init[ScopeType] { result.asScala.toVector } - def compiled(init: Seq[Setting[_]], actual: Boolean = true)( - implicit delegates: ScopeType => Seq[ScopeType], + def compiled(init: Seq[Setting[_]], actual: Boolean = true)(implicit + delegates: ScopeType => Seq[ScopeType], scopeLocal: ScopeLocal, display: Show[ScopedKey[_]] ): CompiledMap = { @@ -203,17 +206,17 @@ trait Init[ScopeType] { } @deprecated("Use makeWithCompiledMap", "1.4.0") - def make(init: Seq[Setting[_]])( - implicit delegates: ScopeType => Seq[ScopeType], + def make(init: Seq[Setting[_]])(implicit + delegates: ScopeType => Seq[ScopeType], scopeLocal: ScopeLocal, display: Show[ScopedKey[_]] ): Settings[ScopeType] = makeWithCompiledMap(init)._2 - def makeWithCompiledMap(init: Seq[Setting[_]])( - implicit delegates: ScopeType => Seq[ScopeType], + def makeWithCompiledMap(init: Seq[Setting[_]])(implicit + delegates: ScopeType => Seq[ScopeType], scopeLocal: ScopeLocal, display: Show[ScopedKey[_]] - ): (CompiledMap, Settings[ScopeType]) = { + ): (CompiledMap, Settings[ScopeType]) = val cMap = compiled(init)(delegates, scopeLocal, display) // order the initializations. cyclic references are detected here. val ordered: Seq[Compiled[_]] = sort(cMap) @@ -224,33 +227,30 @@ trait Init[ScopeType] { case rru: RuntimeUndefined => throw Uninitialized(cMap.keys.toSeq, delegates, rru.undefined, true) } - } def sort(cMap: CompiledMap): Seq[Compiled[_]] = Dag.topologicalSort(cMap.values)(_.dependencies.map(cMap)) - def compile(sMap: ScopedMap): CompiledMap = sMap match { - case m: IMap.IMap0[ScopedKey, SettingSeq] @unchecked => - Par(m.backing.toVector) - .map { - case (k, ss) => + def compile(sMap: ScopedMap): CompiledMap = + sMap match + case m: IMap.IMap0[ScopedKey, SettingSeq] @unchecked => + Par(m.backing.toVector) + .map { case (k, ss) => val deps = ss.flatMap(_.dependencies).toSet ( k, - new Compiled(k.asInstanceOf[ScopedKey[Any]], deps, ss.asInstanceOf[SettingSeq[Any]]) + Compiled(k.asInstanceOf[ScopedKey[Any]], deps, ss.asInstanceOf[SettingSeq[Any]]) ) - } - .toVector - .toMap - case _ => - sMap.toTypedSeq.map { - case sMap.TPair(k, ss) => + } + .toVector + .toMap + case _ => + sMap.toTypedSeq.map { case sMap.TPair(k, ss) => val deps = ss.flatMap(_.dependencies) - (k, new Compiled(k, deps, ss)) - }.toMap - } + (k, Compiled(k, deps, ss)) + }.toMap - def grouped(init: Seq[Setting[_]]): ScopedMap = { + def grouped(init: Seq[Setting[_]]): ScopedMap = val result = new java.util.HashMap[ScopedKey[_], Seq[Setting[_]]] init.foreach { s => result.putIfAbsent(s.key, Vector(s)) match { @@ -259,21 +259,21 @@ trait Init[ScopeType] { } } IMap.fromJMap[ScopedKey, SettingSeq]( - result.asInstanceOf[java.util.Map[ScopedKey[_], SettingSeq[_]]] + result.asInstanceOf[java.util.Map[ScopedKey[Any], SettingSeq[Any]]] ) - } - def add[T](m: ScopedMap, s: Setting[T]): ScopedMap = - m.mapValue[T](s.key, Vector.empty[Setting[T]], ss => append(ss, s)) + def add[A1](m: ScopedMap, s: Setting[A1]): ScopedMap = + m.mapValue[A1](s.key, Vector.empty[Setting[A1]], ss => append(ss, s)) - def append[T](ss: Seq[Setting[T]], s: Setting[T]): Seq[Setting[T]] = - if (s.definitive) Vector(s) else ss :+ s + def append[A1](ss: Seq[Setting[A1]], s: Setting[A1]): Seq[Setting[A1]] = + if s.definitive then Vector(s) + else ss :+ s def addLocal(init: Seq[Setting[_]])(implicit scopeLocal: ScopeLocal): Seq[Setting[_]] = Par(init).map(_.dependencies flatMap scopeLocal).toVector.flatten ++ init - def delegate(sMap: ScopedMap)( - implicit delegates: ScopeType => Seq[ScopeType], + def delegate(sMap: ScopedMap)(implicit + delegates: ScopeType => Seq[ScopeType], display: Show[ScopedKey[_]] ): ScopedMap = { def refMap(ref: Setting[_], isFirst: Boolean) = new ValidateKeyRef { @@ -285,49 +285,46 @@ trait Init[ScopeType] { val undefined = new java.util.ArrayList[Undefined] val result = new java.util.concurrent.ConcurrentHashMap[ScopedKey[_], Any] val backing = sMap.toSeq - Par(backing).foreach { - case (key, settings) => - val valid = new java.util.ArrayList[Setting[_]] - val undefs = new java.util.ArrayList[Undefined] - def validate(s: Setting[_], first: Boolean): Unit = { - s.validateKeyReferenced(refMap(s, first)) match { - case Right(v) => valid.add(v); () - case Left(us) => us.foreach(u => undefs.add(u)) - } + Par(backing).foreach { case (key, settings) => + val valid = new java.util.ArrayList[Setting[_]] + val undefs = new java.util.ArrayList[Undefined] + def validate(s: Setting[_], first: Boolean): Unit = { + s.validateKeyReferenced(refMap(s, first)) match { + case Right(v) => valid.add(v); () + case Left(us) => us.foreach(u => undefs.add(u)) } - settings.headOption match { - case Some(s) => - validate(s, true) - settings.tail.foreach(validate(_, false)) - case _ => - } - if (undefs.isEmpty) result.put(key, valid.asScala.toVector) - else undefined.addAll(undefs) + } + settings.headOption match { + case Some(s) => + validate(s, true) + settings.tail.foreach(validate(_, false)) + case _ => + } + if (undefs.isEmpty) result.put(key, valid.asScala.toVector) + else undefined.addAll(undefs) } - if (undefined.isEmpty) + if undefined.isEmpty then IMap.fromJMap[ScopedKey, SettingSeq]( - result.asInstanceOf[java.util.Map[ScopedKey[_], SettingSeq[_]]] + result.asInstanceOf[java.util.Map[ScopedKey[Any], SettingSeq[Any]]] ) - else - throw Uninitialized(sMap.keys.toSeq, delegates, undefined.asScala.toList, false) + else throw Uninitialized(sMap.keys.toSeq, delegates, undefined.asScala.toList, false) } - private[this] def delegateForKey[T]( + private[this] def delegateForKey[A1]( sMap: ScopedMap, - k: ScopedKey[T], + k: ScopedKey[A1], scopes: Seq[ScopeType], ref: Setting[_], selfRefOk: Boolean - ): Either[Undefined, ScopedKey[T]] = { + ): Either[Undefined, ScopedKey[A1]] = val skeys = scopes.iterator.map(x => ScopedKey(x, k.key)) val definedAt = skeys.find(sk => (selfRefOk || ref.key != sk) && (sMap contains sk)) definedAt.toRight(Undefined(ref, k)) - } - private[this] def applyInits(ordered: Seq[Compiled[_]])( - implicit delegates: ScopeType => Seq[ScopeType] - ): Settings[ScopeType] = { + private[this] def applyInits(ordered: Seq[Compiled[_]])(implicit + delegates: ScopeType => Seq[ScopeType] + ): Settings[ScopeType] = val x = java.util.concurrent.Executors.newFixedThreadPool(Runtime.getRuntime.availableProcessors) try { @@ -340,27 +337,28 @@ trait Init[ScopeType] { } finally { x.shutdown() } - } def showUndefined( u: Undefined, validKeys: Seq[ScopedKey[_]], delegates: ScopeType => Seq[ScopeType] - )( - implicit display: Show[ScopedKey[_]] - ): String = { + )(implicit + display: Show[ScopedKey[_]] + ): String = val guessed = guessIntendedScope(validKeys, delegates, u.referencedKey) val derived = u.defining.isDerived val refString = display.show(u.defining.key) - val sourceString = if (derived) "" else parenPosString(u.defining) + val sourceString = if derived then "" else parenPosString(u.defining) val guessedString = - if (derived) "" + if derived then "" else guessed.map(g => "\n Did you mean " + display.show(g) + " ?").toList.mkString val derivedString = - if (derived) ", which is a derived setting that needs this key to be defined in this scope." + if derived then + ", which is a derived setting that needs this key to be defined in this scope." else "" - display.show(u.referencedKey) + " from " + refString + sourceString + derivedString + guessedString - } + display.show( + u.referencedKey + ) + " from " + refString + sourceString + derivedString + guessedString private[this] def parenPosString(s: Setting[_]): String = s.positionString match { case None => ""; case Some(s) => " (" + s + ")" } @@ -369,40 +367,27 @@ trait Init[ScopeType] { validKeys: Seq[ScopedKey[_]], delegates: ScopeType => Seq[ScopeType], key: ScopedKey[_] - ): Option[ScopedKey[_]] = { + ): Option[ScopedKey[_]] = val distances = validKeys.flatMap { validKey => refinedDistance(delegates, validKey, key).map(dist => (dist, validKey)) } distances.sortBy(_._1).map(_._2).headOption - } def refinedDistance( delegates: ScopeType => Seq[ScopeType], a: ScopedKey[_], b: ScopedKey[_] ): Option[Int] = - if (a.key != b.key || a == b) None + if a.key != b.key || a == b then None else { val dist = delegates(a.scope).indexOf(b.scope) - if (dist < 0) None else Some(dist) + if dist < 0 then None + else Some(dist) } final class Uninitialized(val undefined: Seq[Undefined], override val toString: String) extends Exception(toString) - final class Undefined private[sbt] (val defining: Setting[_], val referencedKey: ScopedKey[_]) - - final class RuntimeUndefined(val undefined: Seq[Undefined]) - extends RuntimeException("References to undefined settings at runtime.") { - override def getMessage = - super.getMessage + undefined.map { u => - "\n" + u.referencedKey + " referenced from " + u.defining - }.mkString - } - - def Undefined(defining: Setting[_], referencedKey: ScopedKey[_]): Undefined = - new Undefined(defining, referencedKey) - def Uninitialized( validKeys: Seq[ScopedKey[_]], delegates: ScopeType => Seq[ScopeType], @@ -420,27 +405,25 @@ trait Init[ScopeType] { ) } - final class Compiled[T]( - val key: ScopedKey[T], + final class Compiled[A1]( + val key: ScopedKey[A1], val dependencies: Iterable[ScopedKey[_]], - val settings: Seq[Setting[T]] - ) { + val settings: Seq[Setting[A1]] + ): override def toString = showFullKey.show(key) - } + end Compiled final class Flattened(val key: ScopedKey[_], val dependencies: Iterable[ScopedKey[_]]) def flattenLocals(compiled: CompiledMap): Map[ScopedKey[_], Flattened] = { - val locals = compiled flatMap { - case (key, comp) => - if (key.key.isLocal) Seq(comp) - else nilSeq[Compiled[_]] + val locals = compiled flatMap { case (key, comp) => + if (key.key.isLocal) Seq(comp) + else nilSeq[Compiled[_]] } val ordered = Dag.topologicalSort(locals)( - _.dependencies.flatMap( - dep => - if (dep.key.isLocal) Seq[Compiled[_]](compiled(dep)) - else nilSeq[Compiled[_]] + _.dependencies.flatMap(dep => + if (dep.key.isLocal) Seq[Compiled[_]](compiled(dep)) + else nilSeq[Compiled[_]] ) ) def flatten( @@ -450,8 +433,8 @@ trait Init[ScopeType] { ): Flattened = new Flattened( key, - deps.flatMap( - dep => if (dep.key.isLocal) cmap(dep).dependencies else Seq[ScopedKey[_]](dep).toIterable + deps.flatMap(dep => + if (dep.key.isLocal) cmap(dep).dependencies else Seq[ScopedKey[_]](dep).toIterable ) ) @@ -461,11 +444,10 @@ trait Init[ScopeType] { cmap.updated(c.key, flatten(cmap, c.key, c.dependencies)) } - compiled flatMap { - case (key, comp) => - if (key.key.isLocal) nilSeq[(ScopedKey[_], Flattened)] - else - Seq[(ScopedKey[_], Flattened)]((key, flatten(flattenedLocals, key, comp.dependencies))) + compiled flatMap { case (key, comp) => + if (key.key.isLocal) nilSeq[(ScopedKey[_], Flattened)] + else + Seq[(ScopedKey[_], Flattened)]((key, flatten(flattenedLocals, key, comp.dependencies))) } } @@ -489,12 +471,12 @@ trait Init[ScopeType] { * same Seq to Set. On a 2020 16" macbook pro, creating the compiled map * for the sbt project is roughly 2 seconds faster after this change * (about 3.5 seconds before compared to about 1.5 seconds after) - * */ - private trait Delegates { + private trait Delegates: def contains(s: ScopeType): Boolean def exists(f: ScopeType => Boolean): Boolean - } + end Delegates + private[this] def mkDelegates(delegates: ScopeType => Seq[ScopeType]): ScopeType => Delegates = { val delegateMap = new java.util.concurrent.ConcurrentHashMap[ScopeType, Delegates] s => @@ -515,8 +497,8 @@ trait Init[ScopeType] { /** * Intersects two scopes, returning the more specific one if they intersect, or None otherwise. */ - private[sbt] def intersect(s1: ScopeType, s2: ScopeType)( - implicit delegates: ScopeType => Seq[ScopeType] + private[sbt] def intersect(s1: ScopeType, s2: ScopeType)(implicit + delegates: ScopeType => Seq[ScopeType] ): Option[ScopeType] = intersectDelegates(s1, s2, mkDelegates(delegates)) /** @@ -612,8 +594,7 @@ trait Init[ScopeType] { val out = local :+ d.setting.setScope(s) d.outputs ++= out out - } else - nilSeq + } else nilSeq } getOrElse nilSeq } derivedForKey.flatMap(localAndDerived) @@ -641,133 +622,145 @@ trait Init[ScopeType] { } } - /** Abstractly defines a value of type `T`. + extension (f: [x] => Initialize[x] => Initialize[x]) + def ∙(g: [x] => Initialize[x] => Initialize[x]): [x] => Initialize[x] => Initialize[x] = + [x] => (f3: Initialize[x]) => f(g(f3)) + + extension (f: [x] => ValidatedInit[x] => Initialize[x]) + def composeVI( + g: [x] => Initialize[x] => ValidatedInit[x] + ): [x] => Initialize[x] => Initialize[x] = + [x] => (f3: Initialize[x]) => f(g(f3)) + + /** + * Abstractly defines a value of type `A1`. * * Specifically it defines a node in a task graph, * where the `dependencies` represents dependent nodes, * and `evaluate` represents the calculation based on the existing body of knowledge. * - * @tparam T the type of the value this defines. + * @tparam A1 the type of the value this defines. */ - sealed trait Initialize[T] { + sealed trait Initialize[A1]: def dependencies: Seq[ScopedKey[_]] - def apply[S](g: T => S): Initialize[S] + def apply[A2](g: A1 => A2): Initialize[A2] - private[sbt] def mapReferenced(g: MapScoped): Initialize[T] - private[sbt] def mapConstant(g: MapConstant): Initialize[T] + private[sbt] def mapReferenced(g: MapScoped): Initialize[A1] + private[sbt] def mapConstant(g: MapConstant): Initialize[A1] - private[sbt] def validateReferenced(g: ValidateRef): ValidatedInit[T] = + private[sbt] def validateReferenced(g: ValidateRef): ValidatedInit[A1] = validateKeyReferenced(new ValidateKeyRef { - def apply[B](key: ScopedKey[B], selfRefOk: Boolean) = g(key) + def apply[A2](key: ScopedKey[A2], selfRefOk: Boolean) = g(key) }) - private[sbt] def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[T] + private[sbt] def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] - def evaluate(map: Settings[ScopeType]): T - def zip[S](o: Initialize[S]): Initialize[(T, S)] = zipTupled(o)(idFun) - def zipWith[S, U](o: Initialize[S])(f: (T, S) => U): Initialize[U] = zipTupled(o)(f.tupled) - private[this] def zipTupled[S, U](o: Initialize[S])(f: ((T, S)) => U): Initialize[U] = - new Apply[λ[L[x] => (L[T], L[S])], U](f, (this, o), AList.tuple2[T, S]) + def evaluate(map: Settings[ScopeType]): A1 + def zip[A2](o: Initialize[A2]): Initialize[(A1, A2)] = zipTupled(o)(idFun) + def zipWith[A2, U](o: Initialize[A2])(f: (A1, A2) => U): Initialize[U] = + zipTupled(o)(f.tupled) + private[this] def zipTupled[A2, U](o: Initialize[A2])(f: ((A1, A2)) => U): Initialize[U] = + Apply[[F[_]] =>> Tuple.Map[(A1, A2), F], U](f, (this, o), AList.tuple2[A1, A2]) /** A fold on the static attributes of this and nested Initializes. */ private[sbt] def processAttributes[S](init: S)(f: (S, AttributeMap) => S): S - } + end Initialize - object Initialize { - implicit def joinInitialize[T](s: Seq[Initialize[T]]): JoinInitSeq[T] = new JoinInitSeq(s) + object Initialize: + implicit def joinInitialize[A1](s: Seq[Initialize[A1]]): JoinInitSeq[A1] = new JoinInitSeq(s) - final class JoinInitSeq[T](s: Seq[Initialize[T]]) { - def joinWith[S](f: Seq[T] => S): Initialize[S] = uniform(s)(f) - def join: Initialize[Seq[T]] = uniform(s)(idFun) - } + final class JoinInitSeq[A1](s: Seq[Initialize[A1]]): + def joinWith[A2](f: Seq[A1] => A2): Initialize[A2] = uniform(s)(f) + def join: Initialize[Seq[A1]] = uniform(s)(idFun) + end JoinInitSeq - def join[T](inits: Seq[Initialize[T]]): Initialize[Seq[T]] = uniform(inits)(idFun) + def join[A1](inits: Seq[Initialize[A1]]): Initialize[Seq[A1]] = uniform(inits)(idFun) - def joinAny[M[_]](inits: Seq[Initialize[M[T]] forSome { type T }]): Initialize[Seq[M[_]]] = - join(inits.asInstanceOf[Seq[Initialize[M[_]]]]) - } + def joinAny[F[_]]: [A] => Seq[Initialize[F[A]]] => Initialize[Seq[F[Any]]] = [A] => + (inits: Seq[Initialize[F[A]]]) => join(inits.asInstanceOf[Seq[Initialize[F[Any]]]]) + end Initialize - object SettingsDefinition { + object SettingsDefinition: implicit def unwrapSettingsDefinition(d: SettingsDefinition): Seq[Setting[_]] = d.settings implicit def wrapSettingsDefinition(ss: Seq[Setting[_]]): SettingsDefinition = new SettingList(ss) - } + end SettingsDefinition - sealed trait SettingsDefinition { + sealed trait SettingsDefinition: def settings: Seq[Setting[_]] - } + end SettingsDefinition - final class SettingList(val settings: Seq[Setting[_]]) extends SettingsDefinition + final class SettingList(override val settings: Seq[Setting[_]]) extends SettingsDefinition - sealed class Setting[T] private[Init] ( - val key: ScopedKey[T], - val init: Initialize[T], + sealed class Setting[A1] private[Init] ( + val key: ScopedKey[A1], + val init: Initialize[A1], val pos: SourcePosition - ) extends SettingsDefinition { - def settings = this :: Nil + ) extends SettingsDefinition: + override def settings = this :: Nil def definitive: Boolean = !init.dependencies.contains(key) def dependencies: Seq[ScopedKey[_]] = - remove(init.dependencies.asInstanceOf[Seq[ScopedKey[T]]], key) - def mapReferenced(g: MapScoped): Setting[T] = make(key, init mapReferenced g, pos) + remove(init.dependencies.asInstanceOf[Seq[ScopedKey[A1]]], key) - def validateReferenced(g: ValidateRef): Either[Seq[Undefined], Setting[T]] = + def mapReferenced(g: MapScoped): Setting[A1] = make(key, init mapReferenced g, pos) + + def validateReferenced(g: ValidateRef): Either[Seq[Undefined], Setting[A1]] = (init validateReferenced g).map(newI => make(key, newI, pos)) - private[sbt] def validateKeyReferenced(g: ValidateKeyRef): Either[Seq[Undefined], Setting[T]] = + private[sbt] def validateKeyReferenced(g: ValidateKeyRef): Either[Seq[Undefined], Setting[A1]] = (init validateKeyReferenced g).map(newI => make(key, newI, pos)) - def mapKey(g: MapScoped): Setting[T] = make(g(key), init, pos) - def mapInit(f: (ScopedKey[T], T) => T): Setting[T] = make(key, init(t => f(key, t)), pos) - def mapConstant(g: MapConstant): Setting[T] = make(key, init mapConstant g, pos) + def mapKey(g: MapScoped): Setting[A1] = make(g(key), init, pos) + def mapInit(f: (ScopedKey[A1], A1) => A1): Setting[A1] = make(key, init(t => f(key, t)), pos) + def mapConstant(g: MapConstant): Setting[A1] = make(key, init mapConstant g, pos) def withPos(pos: SourcePosition) = make(key, init, pos) - def positionString: Option[String] = pos match { + def positionString: Option[String] = pos match case pos: FilePosition => Some(pos.path + ":" + pos.startLine) case NoPosition => None - } - private[sbt] def mapInitialize(f: Initialize[T] => Initialize[T]): Setting[T] = + private[sbt] def mapInitialize(f: Initialize[A1] => Initialize[A1]): Setting[A1] = make(key, f(init), pos) override def toString = "setting(" + key + ") at " + pos - protected[this] def make[B]( - key: ScopedKey[B], - init: Initialize[B], + protected[this] def make[A2]( + key: ScopedKey[A2], + init: Initialize[A2], pos: SourcePosition - ): Setting[B] = new Setting[B](key, init, pos) + ): Setting[A2] = Setting[A2](key, init, pos) protected[sbt] def isDerived: Boolean = false - private[sbt] def setScope(s: ScopeType): Setting[T] = + private[sbt] def setScope(s: ScopeType): Setting[A1] = make(key.copy(scope = s), init.mapReferenced(mapScope(const(s))), pos) /** Turn this setting into a `DefaultSetting` if it's not already, otherwise returns `this` */ - private[sbt] def default(id: => Long = nextDefaultID()): DefaultSetting[T] = + private[sbt] def default(id: => Long = nextDefaultID()): DefaultSetting[A1] = DefaultSetting(key, init, pos, id) - } + end Setting - private[Init] sealed class DerivedSetting[T]( - sk: ScopedKey[T], - i: Initialize[T], + private[Init] sealed class DerivedSetting[A1]( + sk: ScopedKey[A1], + i: Initialize[A1], p: SourcePosition, val filter: ScopeType => Boolean, val trigger: AttributeKey[_] => Boolean - ) extends Setting[T](sk, i, p) { + ) extends Setting[A1](sk, i, p): override def make[B](key: ScopedKey[B], init: Initialize[B], pos: SourcePosition): Setting[B] = new DerivedSetting[B](key, init, pos, filter, trigger) protected[sbt] override def isDerived: Boolean = true - override def default(_id: => Long): DefaultSetting[T] = - new DerivedSetting[T](sk, i, p, filter, trigger) with DefaultSetting[T] { val id = _id } + override def default(_id: => Long): DefaultSetting[A1] = + new DerivedSetting[A1](sk, i, p, filter, trigger) with DefaultSetting[A1] { val id = _id } override def toString = "derived " + super.toString - } + end DerivedSetting // Only keep the first occurrence of this setting and move it to the front so that it has lower precedence than non-defaults. // This is intended for internal sbt use only, where alternatives like Plugin.globalSettings are not available. - private[Init] sealed trait DefaultSetting[T] extends Setting[T] { + private[Init] sealed trait DefaultSetting[A1] extends Setting[A1]: val id: Long override def make[B](key: ScopedKey[B], init: Initialize[B], pos: SourcePosition): Setting[B] = @@ -775,191 +768,236 @@ trait Init[ScopeType] { override final def hashCode = id.hashCode - override final def equals(o: Any): Boolean = o match { - case d: DefaultSetting[_] => d.id == id; case _ => false - } + override final def equals(o: Any): Boolean = + o match + case d: DefaultSetting[_] => d.id == id + case _ => false - override def toString = s"default($id) " + super.toString + override def toString: String = s"default($id) " + super.toString override def default(id: => Long) = this - } + end DefaultSetting - object DefaultSetting { - def apply[T](sk: ScopedKey[T], i: Initialize[T], p: SourcePosition, _id: Long) = - new Setting[T](sk, i, p) with DefaultSetting[T] { val id = _id } - } + object DefaultSetting: + def apply[A1](sk: ScopedKey[A1], i: Initialize[A1], p: SourcePosition, _id: Long) = + new Setting[A1](sk, i, p) with DefaultSetting[A1]: + val id = _id + end DefaultSetting - private[this] def handleUndefined[T](vr: ValidatedInit[T]): Initialize[T] = vr match { + private[this] def handleUndefined[A](vr: ValidatedInit[A]): Initialize[A] = vr match case Left(undefs) => throw new RuntimeUndefined(undefs) case Right(x) => x - } - private[this] lazy val getValidated = λ[ValidatedInit ~> Initialize](handleUndefined(_)) + private[this] lazy val getValidatedK = [A] => (fa: ValidatedInit[A]) => handleUndefined(fa) // mainly for reducing generated class count - private[this] def validateKeyReferencedT(g: ValidateKeyRef) = - λ[Initialize ~> ValidatedInit](_ validateKeyReferenced g) - - private[this] def mapReferencedT(g: MapScoped) = λ[Initialize ~> Initialize](_ mapReferenced g) - private[this] def mapConstantT(g: MapConstant) = λ[Initialize ~> Initialize](_ mapConstant g) - private[this] def evaluateT(g: Settings[ScopeType]) = λ[Initialize ~> Id](_ evaluate g) + private[this] def validateKeyReferencedK( + g: ValidateKeyRef + ): [A] => Initialize[A] => ValidatedInit[A] = [A] => + (fa: Initialize[A]) => (fa.validateKeyReferenced(g)) + private[this] def mapReferencedK(g: MapScoped): [A] => Initialize[A] => Initialize[A] = [A] => + (fa: Initialize[A]) => (fa.mapReferenced(g)) + private[this] def mapConstantK(g: MapConstant): [A] => Initialize[A] => Initialize[A] = [A] => + (fa: Initialize[A]) => (fa.mapConstant(g)) + private[this] def evaluateK(g: Settings[ScopeType]): [A] => Initialize[A] => Id[A] = [A] => + (fa: Initialize[A]) => (fa.evaluate(g)) private[this] def deps(ls: Seq[Initialize[_]]): Seq[ScopedKey[_]] = ls.flatMap(_.dependencies) - /** An `Initialize[T]` associated with a `ScopedKey[S]`. + /** + * An `Initialize[T]` associated with a `ScopedKey[S]`. * @tparam S the type of the associated `ScopedKey` * @tparam T the type of the value this `Initialize` defines. */ - sealed trait Keyed[S, T] extends Initialize[T] { + sealed trait Keyed[S, A1] extends Initialize[A1]: def scopedKey: ScopedKey[S] - def transform: S => T + def transform: S => A1 - final def dependencies = scopedKey :: Nil - final def apply[Z](g: T => Z): Initialize[Z] = new GetValue(scopedKey, g compose transform) - final def evaluate(ss: Settings[ScopeType]): T = transform(getValue(ss, scopedKey)) - final def mapReferenced(g: MapScoped): Initialize[T] = new GetValue(g(scopedKey), transform) + override final def dependencies = scopedKey :: Nil + override final def apply[A2](g: A1 => A2): Initialize[A2] = + GetValue(scopedKey, g compose transform) + override final def evaluate(ss: Settings[ScopeType]): A1 = transform(getValue(ss, scopedKey)) + override final def mapReferenced(g: MapScoped): Initialize[A1] = + GetValue(g(scopedKey), transform) - private[sbt] final def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[T] = - g(scopedKey, false) match { + private[sbt] override final def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = + g(scopedKey, false) match case Left(un) => Left(un :: Nil) - case Right(nk) => Right(new GetValue(nk, transform)) - } + case Right(nk) => Right(GetValue(nk, transform)) - final def mapConstant(g: MapConstant): Initialize[T] = g(scopedKey) match { - case None => this - case Some(const) => new Value(() => transform(const)) - } + override final def mapConstant(g: MapConstant): Initialize[A1] = + g(scopedKey) match + case None => this + case Some(const) => Value(() => transform(const)) - private[sbt] def processAttributes[B](init: B)(f: (B, AttributeMap) => B): B = init - } + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = + init + end Keyed - private[this] final class GetValue[S, T](val scopedKey: ScopedKey[S], val transform: S => T) - extends Keyed[S, T] + private[this] final class GetValue[S, A1](val scopedKey: ScopedKey[S], val transform: S => A1) + extends Keyed[S, A1] - /** A `Keyed` where the type of the value and the associated `ScopedKey` are the same. - * @tparam T the type of both the value this `Initialize` defines and the type of the associated `ScopedKey`. + /** + * A `Keyed` where the type of the value and the associated `ScopedKey` are the same. + * @tparam A1 the type of both the value this `Initialize` defines and the type of the associated `ScopedKey`. */ - trait KeyedInitialize[T] extends Keyed[T, T] { - final val transform = idFun[T] - } + trait KeyedInitialize[A1] extends Keyed[A1, A1]: + final val transform = idFun[A1] + end KeyedInitialize - private[sbt] final class TransformCapture(val f: Initialize ~> Initialize) - extends Initialize[Initialize ~> Initialize] { - def dependencies = Nil - def apply[Z](g2: (Initialize ~> Initialize) => Z): Initialize[Z] = map(this)(g2) - def evaluate(ss: Settings[ScopeType]): Initialize ~> Initialize = f - def mapReferenced(g: MapScoped) = new TransformCapture(mapReferencedT(g) ∙ f) - def mapConstant(g: MapConstant) = new TransformCapture(mapConstantT(g) ∙ f) + private[sbt] final class TransformCapture(val f: [x] => Initialize[x] => Initialize[x]) + extends Initialize[[x] => Initialize[x] => Initialize[x]]: + override def dependencies: Seq[ScopedKey[_]] = Nil + override def apply[A2](g2: ([x] => Initialize[x] => Initialize[x]) => A2): Initialize[A2] = + map(this)(g2) + override def evaluate(ss: Settings[ScopeType]): [x] => Initialize[x] => Initialize[x] = f + override def mapReferenced(g: MapScoped): Initialize[[x] => Initialize[x] => Initialize[x]] = + TransformCapture(mapReferencedK(g) ∙ f) + override def mapConstant(g: MapConstant): Initialize[[x] => Initialize[x] => Initialize[x]] = + TransformCapture(mapConstantK(g) ∙ f) - def validateKeyReferenced(g: ValidateKeyRef) = - Right(new TransformCapture(getValidated ∙ validateKeyReferencedT(g) ∙ f)) + override def validateKeyReferenced( + g: ValidateKeyRef + ): ValidatedInit[[x] => Initialize[x] => Initialize[x]] = + Right(TransformCapture(getValidatedK.composeVI(validateKeyReferencedK(g)) ∙ f)) - private[sbt] def processAttributes[S](init: S)(f: (S, AttributeMap) => S): S = init - } + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = + init + end TransformCapture - private[sbt] final class ValidationCapture[T](val key: ScopedKey[T], val selfRefOk: Boolean) - extends Initialize[ScopedKey[T]] { - def dependencies = Nil - def apply[Z](g2: ScopedKey[T] => Z): Initialize[Z] = map(this)(g2) - def evaluate(ss: Settings[ScopeType]) = key - def mapReferenced(g: MapScoped) = new ValidationCapture(g(key), selfRefOk) - def mapConstant(g: MapConstant) = this + private[sbt] final class ValidationCapture[A1](val key: ScopedKey[A1], val selfRefOk: Boolean) + extends Initialize[ScopedKey[A1]]: + override def dependencies: Seq[ScopedKey[_]] = Nil + override def apply[A2](g2: ScopedKey[A1] => A2): Initialize[A2] = map(this)(g2) + override def evaluate(ss: Settings[ScopeType]): ScopedKey[A1] = key + override def mapReferenced(g: MapScoped): Initialize[ScopedKey[A1]] = + ValidationCapture(g(key), selfRefOk) + override def mapConstant(g: MapConstant): Initialize[ScopedKey[A1]] = this - def validateKeyReferenced(g: ValidateKeyRef) = g(key, selfRefOk) match { - case Left(un) => Left(un :: Nil) - case Right(k) => Right(new ValidationCapture(k, selfRefOk)) + override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[ScopedKey[A1]] = + g(key, selfRefOk) match + case Left(un) => Left(un :: Nil) + case Right(k) => Right(ValidationCapture(k, selfRefOk)) + + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = + init + end ValidationCapture + + private[sbt] final class Bind[S, A1](val f: S => Initialize[A1], val in: Initialize[S]) + extends Initialize[A1]: + override def dependencies: Seq[ScopedKey[_]] = in.dependencies + override def apply[A2](g: A1 => A2): Initialize[A2] = Bind[S, A2](s => f(s)(g), in) + override def evaluate(ss: Settings[ScopeType]): A1 = f(in evaluate ss) evaluate ss + override def mapReferenced(g: MapScoped) = + Bind[S, A1](s => f(s) mapReferenced g, in mapReferenced g) + + override def validateKeyReferenced(g: ValidateKeyRef) = (in validateKeyReferenced g).map { + validIn => + Bind[S, A1](s => handleUndefined(f(s) validateKeyReferenced g), validIn) } - private[sbt] def processAttributes[S](init: S)(f: (S, AttributeMap) => S): S = init - } + override def mapConstant(g: MapConstant) = + Bind[S, A1](s => f(s) mapConstant g, in mapConstant g) - private[sbt] final class Bind[S, T](val f: S => Initialize[T], val in: Initialize[S]) - extends Initialize[T] { - def dependencies = in.dependencies - def apply[Z](g: T => Z): Initialize[Z] = new Bind[S, Z](s => f(s)(g), in) - def evaluate(ss: Settings[ScopeType]): T = f(in evaluate ss) evaluate ss - def mapReferenced(g: MapScoped) = new Bind[S, T](s => f(s) mapReferenced g, in mapReferenced g) - - def validateKeyReferenced(g: ValidateKeyRef) = (in validateKeyReferenced g).map { validIn => - new Bind[S, T](s => handleUndefined(f(s) validateKeyReferenced g), validIn) - } - - def mapConstant(g: MapConstant) = new Bind[S, T](s => f(s) mapConstant g, in mapConstant g) - - private[sbt] def processAttributes[B](init: B)(f: (B, AttributeMap) => B): B = + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = in.processAttributes(init)(f) - } + end Bind - private[sbt] final class Optional[S, T](val a: Option[Initialize[S]], val f: Option[S] => T) - extends Initialize[T] { - def dependencies = deps(a.toList) - def apply[Z](g: T => Z): Initialize[Z] = new Optional[S, Z](a, g compose f) - def mapReferenced(g: MapScoped) = new Optional(a map mapReferencedT(g).fn, f) + private[sbt] final class Optional[S, A1](val a: Option[Initialize[S]], val f: Option[S] => A1) + extends Initialize[A1]: + override def dependencies: Seq[ScopedKey[_]] = deps(a.toList) + override def apply[A2](g: A1 => A2): Initialize[A2] = new Optional[S, A2](a, g compose f) - def validateKeyReferenced(g: ValidateKeyRef) = a match { + override def mapReferenced(g: MapScoped): Initialize[A1] = + Optional(a.map { mapReferencedK(g)[S] }, f) + + override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = a match case None => Right(this) - case Some(i) => Right(new Optional(i.validateKeyReferenced(g).toOption, f)) - } + case Some(i) => Right(Optional(i.validateKeyReferenced(g).toOption, f)) - def mapConstant(g: MapConstant): Initialize[T] = new Optional(a map mapConstantT(g).fn, f) - def evaluate(ss: Settings[ScopeType]): T = f(a.flatMap(i => trapBadRef(evaluateT(ss)(i)))) + override def mapConstant(g: MapConstant): Initialize[A1] = Optional(a map mapConstantK(g)[S], f) + override def evaluate(ss: Settings[ScopeType]): A1 = + f(a.flatMap { i => trapBadRef(evaluateK(ss)(i)) }) // proper solution is for evaluate to be deprecated or for external use only and a new internal method returning Either be used private[this] def trapBadRef[A](run: => A): Option[A] = try Some(run) catch { case _: InvalidReference => None } - private[sbt] def processAttributes[B](init: B)(f: (B, AttributeMap) => B): B = a match { + private[sbt] override def processAttributes[B](init: B)(f: (B, AttributeMap) => B): B = a match case None => init case Some(i) => i.processAttributes(init)(f) - } - } + end Optional - private[sbt] final class Value[T](val value: () => T) extends Initialize[T] { - def dependencies = Nil - def mapReferenced(g: MapScoped) = this - def validateKeyReferenced(g: ValidateKeyRef) = Right(this) - def apply[S](g: T => S) = new Value[S](() => g(value())) - def mapConstant(g: MapConstant) = this - def evaluate(map: Settings[ScopeType]): T = value() - private[sbt] def processAttributes[S](init: S)(f: (S, AttributeMap) => S): S = init - } + private[sbt] final class Value[A1](val value: () => A1) extends Initialize[A1]: + override def dependencies: Seq[ScopedKey[_]] = Nil + override def mapReferenced(g: MapScoped): Initialize[A1] = this + override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = Right(this) + override def apply[A2](g: A1 => A2): Initialize[A2] = Value[A2](() => g(value())) + override def mapConstant(g: MapConstant): Initialize[A1] = this + override def evaluate(map: Settings[ScopeType]): A1 = value() + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = + init + end Value - private[sbt] final object StaticScopes extends Initialize[Set[ScopeType]] { - def dependencies = Nil - def mapReferenced(g: MapScoped) = this - def validateKeyReferenced(g: ValidateKeyRef) = Right(this) - def apply[S](g: Set[ScopeType] => S) = map(this)(g) - def mapConstant(g: MapConstant) = this - def evaluate(map: Settings[ScopeType]) = map.scopes - private[sbt] def processAttributes[S](init: S)(f: (S, AttributeMap) => S): S = init - } + private[sbt] object StaticScopes extends Initialize[Set[ScopeType]]: + override def dependencies: Seq[ScopedKey[_]] = Nil + override def mapReferenced(g: MapScoped): Initialize[Set[ScopeType]] = this + override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[Set[ScopeType]] = + Right(this) + override def apply[A2](g: Set[ScopeType] => A2) = map(this)(g) + override def mapConstant(g: MapConstant): Initialize[Set[ScopeType]] = this + override def evaluate(map: Settings[ScopeType]): Set[ScopeType] = map.scopes + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = + init + end StaticScopes - private[sbt] final class Apply[K[L[x]], T]( - val f: K[Id] => T, + private[sbt] final class Apply[K[F[x]], A1]( + val f: K[Id] => A1, val inputs: K[Initialize], val alist: AList[K] - ) extends Initialize[T] { - def dependencies = deps(alist.toList(inputs)) - def mapReferenced(g: MapScoped) = mapInputs(mapReferencedT(g)) - def apply[S](g: T => S) = new Apply(g compose f, inputs, alist) - def mapConstant(g: MapConstant) = mapInputs(mapConstantT(g)) + ) extends Initialize[A1]: + override def dependencies: Seq[ScopedKey[_]] = deps(alist.toList(inputs)) + override def mapReferenced(g: MapScoped): Initialize[A1] = mapInputs(mapReferencedK(g)) + override def mapConstant(g: MapConstant): Initialize[A1] = mapInputs(mapConstantK(g)) - def mapInputs(g: Initialize ~> Initialize): Initialize[T] = - new Apply(f, alist.transform(inputs, g), alist) + override def apply[A2](g: A1 => A2): Initialize[A2] = Apply(g compose f, inputs, alist) - def evaluate(ss: Settings[ScopeType]) = f(alist.transform(inputs, evaluateT(ss))) + def mapInputs(g: [a] => Initialize[a] => Initialize[a]): Initialize[A1] = + Apply(f, alist.transform(inputs) { g }, alist) - def validateKeyReferenced(g: ValidateKeyRef) = { - val tx = alist.transform(inputs, validateKeyReferencedT(g)) + override def evaluate(ss: Settings[ScopeType]): A1 = + f(alist.transform(inputs) { evaluateK(ss) }) + + override def validateKeyReferenced(g: ValidateKeyRef): ValidatedInit[A1] = + val tx = alist.transform(inputs) { validateKeyReferencedK(g) } val undefs = alist.toList(tx).flatMap(_.left.toSeq.flatten) - val get = λ[ValidatedInit ~> Initialize](_.right.get) - if (undefs.isEmpty) Right(new Apply(f, alist.transform(tx, get), alist)) else Left(undefs) - } + val get = [A] => (fa: ValidatedInit[A]) => (fa.right.get) + if undefs.isEmpty then Right(Apply(f, alist.transform(tx) { get }, alist)) + else Left(undefs) - private[sbt] def processAttributes[S](init: S)(f: (S, AttributeMap) => S): S = + private[sbt] override def processAttributes[A2](init: A2)(f: (A2, AttributeMap) => A2): A2 = alist.toList(inputs).foldLeft(init) { (v, i) => i.processAttributes(v)(f) } - } - private def remove[T](s: Seq[T], v: T) = s filterNot (_ == v) -} + end Apply + + private def remove[A](s: Seq[A], v: A) = s.filterNot(_ == v) + + final class Undefined private[sbt] (val defining: Setting[_], val referencedKey: ScopedKey[_]) + + def Undefined(defining: Setting[_], referencedKey: ScopedKey[_]): Undefined = + Undefined(defining, referencedKey) + + final class RuntimeUndefined(val undefined: Seq[Undefined]) + extends RuntimeException("References to undefined settings at runtime."): + override def getMessage = + super.getMessage + undefined.map { u => + "\n" + u.referencedKey + " referenced from " + u.defining + }.mkString + end RuntimeUndefined + + private final class InvalidReference(val key: ScopedKey[_]) + extends RuntimeException( + "Internal settings error: invalid reference to " + showFullKey.show(key) + ) +end Init diff --git a/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala b/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala index 4329d781e..1470f37e5 100644 --- a/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala +++ b/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala @@ -15,7 +15,9 @@ trait TypeFunctions: import TypeFunctions._ sealed trait Const[A] { type Apply[B] = A } sealed trait ConstK[A] { type l[L[x]] = A } + type ConstK[A] = [F[_]] =>> A */ + sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] } sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] } @@ -47,7 +49,6 @@ trait TypeFunctions: type ~>|[A[_], B[_]] = A ~> Compose[Option, B]#Apply */ type ~>|[F1[_], F2[_]] = [A] => F1[A] => Option[F2[A]] - end TypeFunctions /* diff --git a/util-collection/src/test/scala-2/SettingsExample.scala b/util-collection/src/test/scala/SettingsExample.scala similarity index 67% rename from util-collection/src/test/scala-2/SettingsExample.scala rename to util-collection/src/test/scala/SettingsExample.scala index 5399f79c1..813d1492b 100644 --- a/util-collection/src/test/scala-2/SettingsExample.scala +++ b/util-collection/src/test/scala/SettingsExample.scala @@ -25,12 +25,11 @@ case class SettingsExample() extends Init[Scope] { }) // A sample delegation function that delegates to a Scope with a lower index. - val delegates: Scope => Seq[Scope] = { - case s @ Scope(index, proj) => - s +: (if (index <= 0) Nil - else { - (if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index - 1)) - }) + val delegates: Scope => Seq[Scope] = { case s @ Scope(index, proj) => + s +: (if (index <= 0) Nil + else { + (if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index - 1)) + }) } // Not using this feature in this example. @@ -39,7 +38,7 @@ case class SettingsExample() extends Init[Scope] { // These three functions + a scope (here, Scope) are sufficient for defining our settings system. } -/** Usage Example **/ +/** Usage Example * */ case class SettingsUsage(val settingsExample: SettingsExample) { import settingsExample._ @@ -73,25 +72,25 @@ case class SettingsUsage(val settingsExample: SettingsExample) { }*/ /** - * Output: - * For the None results, we never defined the value and there was no value to delegate to. - * For a3, we explicitly defined it to be 3. - * a4 wasn't defined, so it delegates to a3 according to our delegates function. - * b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3 - * a5 is defined as the previous value of a5 + 1 and - * since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4. - * b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well - * a0 = None - * b0 = None - * a1 = None - * b1 = None - * a2 = None - * b2 = None - * a3 = Some(3) - * b3 = None - * a4 = Some(3) - * b4 = Some(9) - * a5 = Some(4) - * b5 = Some(9) - */ + * Output: + * For the None results, we never defined the value and there was no value to delegate to. + * For a3, we explicitly defined it to be 3. + * a4 wasn't defined, so it delegates to a3 according to our delegates function. + * b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3 + * a5 is defined as the previous value of a5 + 1 and + * since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4. + * b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well + * a0 = None + * b0 = None + * a1 = None + * b1 = None + * a2 = None + * b2 = None + * a3 = Some(3) + * b3 = None + * a4 = Some(3) + * b4 = Some(9) + * a5 = Some(4) + * b5 = Some(9) + */ }