Refactor ScopeAxis to use enum

This commit is contained in:
Eugene Yokota 2024-11-24 23:10:18 -05:00
parent a30fd384dd
commit 4e3fbcced9
37 changed files with 89 additions and 39 deletions

View File

@ -8,6 +8,8 @@
package sbt
import ScopeAxis.{ Select, zero }
sealed trait DelegateIndex {
def project(ref: ProjectRef): Seq[ScopeAxis[ResolvedReference]]
def config(ref: ProjectRef, conf: ConfigKey): Seq[ScopeAxis[ConfigKey]]
@ -23,9 +25,9 @@ private final class DelegateIndex0(refs: Map[ProjectRef, ProjectDelegates]) exte
case Some(pd) =>
pd.confs.get(conf) match {
case Some(cs) => cs
case None => (Select(conf): ScopeAxis[ConfigKey]) :: (Zero: ScopeAxis[ConfigKey]) :: Nil
case None => Select(conf) :: zero[ConfigKey] :: Nil
}
case None => (Select(conf): ScopeAxis[ConfigKey]) :: (Zero: ScopeAxis[ConfigKey]) :: Nil
case None => Select(conf) :: zero[ConfigKey] :: Nil
}
}
private final class ProjectDelegates(

View File

@ -11,6 +11,7 @@ package sbt
import sbt.Def.{ Initialize, ScopedKey }
import sbt.Previous._
import sbt.Scope.Global
import sbt.ScopeAxis.Select
import sbt.SlashSyntax0.given
import sbt.internal.util._
import sbt.std.TaskExtra._

View File

@ -11,6 +11,7 @@ import java.io.File
import java.util.Locale
import sbt.librarymanagement.Configuration
import sbt.Def.{ Initialize, ScopedKey, Setting }
import sbt.ScopeAxis.Select
import sbt.internal.util.Dag
import sbt.internal.util.complete.Parser
import sbt.internal.util.complete.DefaultParsers

View File

@ -14,6 +14,7 @@ import java.net.URI
import sbt.internal.util.AttributeKey
import sbt.io.IO
import sbt.librarymanagement.Configuration
import sbt.ScopeAxis.{ Select, This }
import sbt.SlashSyntax.RichConfiguration
// in all of these, the URI must be resolved and normalized before it is definitive

View File

@ -12,6 +12,7 @@ import java.net.URI
import sbt.internal.util.{ AttributeKey, AttributeMap, Dag }
import sbt.internal.util.Util._
import sbt.ScopeAxis.{ Select, This, Zero }
import sbt.io.IO
import scala.collection.concurrent.TrieMap

View File

@ -8,46 +8,51 @@
package sbt
import sbt.internal.util.Util._
import sbt.internal.util.Util.*
sealed trait ScopeAxis[+S] {
def foldStrict[T](f: S => T, ifZero: T, ifThis: T): T = fold(f, ifZero, ifThis)
def fold[T](f: S => T, ifZero: => T, ifThis: => T): T = this match {
enum ScopeAxis[+A1]:
/**
* Select is a type constructor that is used to wrap type `S`
* to make a scope component, equivalent of Some in Option.
*/
case Select(axis: A1) extends ScopeAxis[A1]
/**
* This is a scope component that represents not being
* scoped by the user, which later could be further scoped automatically
* by sbt.
*/
case This extends ScopeAxis[Nothing]
/**
* Zero is a scope component that represents not scoping.
* It is a universal fallback component that is strictly weaker
* than any other values on a scope axis.
*/
case Zero extends ScopeAxis[Nothing]
def isSelect: Boolean = this match
case Select(_) => true
case _ => false
def foldStrict[A2](f: A1 => A2, ifZero: A2, ifThis: A2): A2 = fold(f, ifZero, ifThis)
def fold[A2](f: A1 => A2, ifZero: => A2, ifThis: => A2): A2 = this match
case This => ifThis
case Zero => ifZero
case Select(s) => f(s)
}
def toOption: Option[S] = foldStrict(Option(_), none, none)
def map[T](f: S => T): ScopeAxis[T] =
foldStrict(s => Select(f(s)): ScopeAxis[T], Zero: ScopeAxis[T], This: ScopeAxis[T])
def isSelect: Boolean = false
}
/**
* This is a scope component that represents not being
* scoped by the user, which later could be further scoped automatically
* by sbt.
*/
case object This extends ScopeAxis[Nothing]
def toOption: Option[A1] = foldStrict(Option(_), none, none)
/**
* Zero is a scope component that represents not scoping.
* It is a universal fallback component that is strictly weaker
* than any other values on a scope axis.
*/
case object Zero extends ScopeAxis[Nothing]
def map[A2](f: A1 => A2): ScopeAxis[A2] =
foldStrict(s => Select(f(s)): ScopeAxis[A2], Zero: ScopeAxis[A2], This: ScopeAxis[A2])
end ScopeAxis
/**
* Select is a type constructor that is used to wrap type `S`
* to make a scope component, equivalent of Some in Option.
*/
final case class Select[S](s: S) extends ScopeAxis[S] {
override def isSelect = true
}
object ScopeAxis:
def `this`[A1]: ScopeAxis[A1] = ScopeAxis.This
def zero[A1]: ScopeAxis[A1] = ScopeAxis.Zero
object ScopeAxis {
def fromOption[T](o: Option[T]): ScopeAxis[T] = o match {
case Some(v) => Select(v)
case None => Zero
}
}
def fromOption[A1](o: Option[A1]): ScopeAxis[A1] = o match
case Some(v) => ScopeAxis.Select(v)
case None => ScopeAxis.Zero
end ScopeAxis

View File

@ -10,6 +10,7 @@ package sbt
import sbt.librarymanagement.Configuration
import sbt.internal.util.AttributeKey
import sbt.ScopeAxis.{ Select, This }
/**
* SlashSyntax implements the slash syntax to scope keys for build.sbt DSL.

View File

@ -16,6 +16,7 @@ import sbt.internal.util.TupleMapExtension.*
import sbt.util.OptJsonWriter
import sbt.ConcurrentRestrictions.Tag
import sbt.Def.{ Initialize, ScopedKey, Setting, setting }
import sbt.ScopeAxis.Select
import std.TaskMacro
import std.TaskExtra.{ task => mktask, _ }
import scala.reflect.ClassTag

View File

@ -14,6 +14,7 @@ import hedgehog.*
import scala.annotation.nowarn
import scala.reflect.ClassTag
import _root_.sbt.io.IO
import _root_.sbt.ScopeAxis.{ Select, This, Zero }
import _root_.sbt.Scoped.ScopingSetting
import _root_.sbt.librarymanagement.syntax.*
import _root_.sbt.internal.util.{ AttributeKey, AttributeMap }

View File

@ -12,6 +12,7 @@ package test
import hedgehog.*
import hedgehog.runner.*
import Scope.{ Global, ThisScope }
import ScopeAxis.{ Select, This, Zero }
import SlashSyntax0.given
import BuildSettingsInstances.given
import _root_.sbt.internal.util.AttributeKey
@ -19,6 +20,7 @@ import _root_.sbt.internal.util.AttributeKey
object SlashSyntaxSpec extends Properties:
override def tests: List[Test] = List(
property("Global / key", propGlobalKey),
example("Zero / compile", zeroCompile),
property("Reference / key", propReferenceKey),
property("Reference / Config / key", propReferenceConfigKey),
property("Reference / task.key / key", propReferenceAttrKeyKey),
@ -42,6 +44,7 @@ object SlashSyntaxSpec extends Properties:
)
def gen[A1: Gen]: Gen[A1] = summon[Gen[A1]]
lazy val compile: TaskKey[Unit] = TaskKey[Unit]("compile", "compile")
def propGlobalKey: Property =
for
@ -58,6 +61,10 @@ object SlashSyntaxSpec extends Properties:
else true)
)
def zeroCompile: Result =
val actual = Zero / compile
Result.assert(actual.scope.project == Zero && actual.key == compile.key)
def propReferenceKey: Property =
for
ref <- gen[Reference].forAll

View File

@ -12,9 +12,10 @@ import java.io.File
import sjsonnew._
import sbt.Def.{ Setting, inputKey, settingKey, taskKey }
import sbt.Scope.Global
import sbt.ScopeAxis.Zero
import sbt.librarymanagement.ModuleID
import sbt.librarymanagement.syntax._
import sbt.{ LocalProject, ProjectReference, ThisBuild, Zero }
import sbt.{ LocalProject, ProjectReference, ThisBuild }
object SlashSyntaxTest extends sbt.SlashSyntax {
final case class Proj(id: String)

View File

@ -12,6 +12,7 @@ import java.io.File
import sbt.Def.{ ScopedKey, Setting }
import sbt.Keys._
import sbt.ProjectExtra.extract
import sbt.ScopeAxis.{ Select, Zero }
import sbt.SlashSyntax0.given
import sbt.internal.Act
import sbt.internal.CommandStrings._

View File

@ -32,6 +32,7 @@ import sbt.Project.{
}
import sbt.ProjectExtra.*
import sbt.Scope.{ GlobalScope, ThisBuildScope, ThisScope, fillTaskAxis }
import sbt.ScopeAxis.{ Select, This, Zero }
import sbt.State.StateOpsImpl
import sbt.coursierint._
import sbt.internal.CommandStrings.ExportStream

View File

@ -10,6 +10,7 @@ package sbt
import sbt.internal.{ Load, BuildStructure, Act, Aggregation, SessionSettings }
import Scope.GlobalScope
import sbt.ScopeAxis.This
import Def.{ ScopedKey, Setting }
import sbt.internal.util.complete.Parser
import sbt.util.Show

View File

@ -18,6 +18,7 @@ import java.util.concurrent.atomic.AtomicBoolean
import sbt.Project.LoadAction
import sbt.ProjectExtra.*
import sbt.ScopeAxis.Select
import sbt.internal.Aggregation.AnyKeys
import sbt.internal._
import sbt.internal.client.BspClient

View File

@ -13,6 +13,7 @@ import DefaultParsers._
import sbt.Keys._
import Scope.GlobalScope
import Def.ScopedKey
import sbt.ScopeAxis.Select
import sbt.SlashSyntax0.given
import sbt.internal.Load
import sbt.internal.CommandStrings._

View File

@ -37,6 +37,7 @@ import Keys.{
}
import Project.LoadAction
import Scope.{ Global, ThisScope }
import sbt.ScopeAxis.Select
import sbt.SlashSyntax0.given
import Def.{ Flattened, Initialize, ScopedKey, Setting }
import sbt.internal.{

View File

@ -21,6 +21,7 @@ import sbt.Keys._
import sbt.Project.{ inConfig => _, * }
import sbt.ProjectExtra.*
import sbt.ScopeFilter.Make._
import sbt.ScopeAxis.Select
import sbt.SlashSyntax0.given
import sbt.coursierint.LMCoursier
import sbt.internal.inc.{ HashUtil, JarUtils }

View File

@ -13,6 +13,7 @@ import sbt.internal.util.{ AttributeKey, Dag }
import sbt.librarymanagement.{ ConfigRef, Configuration }
import sbt.internal.util.Types.const
import Def.Initialize
import sbt.ScopeAxis.{ Select, Zero }
import java.net.URI
sealed abstract class ScopeFilter { self =>

View File

@ -15,6 +15,7 @@ import sbt.internal.util.complete.{ DefaultParsers, Parser }
import Aggregation.{ KeyValue, Values }
import DefaultParsers._
import sbt.internal.util.Types.idFun
import sbt.ScopeAxis.{ Select, Zero }
import sbt.ProjectExtra.{ failure => _, * }
import java.net.URI
import sbt.internal.CommandStrings.{ MultiTaskCommand, ShowCommand, PrintCommand }

View File

@ -14,6 +14,7 @@ import java.text.DateFormat
import sbt.Def.{ ScopedKey, Settings }
import sbt.Keys.{ showSuccess, showTiming, timingFormat }
import sbt.ProjectExtra.*
import sbt.ScopeAxis.{ Select, Zero }
import sbt.SlashSyntax0.given
import sbt.internal.util.complete.Parser
import sbt.internal.util.complete.Parser.{ failure, seq, success }

View File

@ -16,6 +16,7 @@ import java.net.URI
import Def.{ ScopeLocal, ScopedKey, Setting, displayFull }
import BuildPaths.outputDirectory
import Scope.GlobalScope
import sbt.ScopeAxis.{ Select, This, Zero }
import sbt.SlashSyntax0.given
import BuildStreams.Streams
import sbt.io.syntax._

View File

@ -16,6 +16,7 @@ import sbt.Def._
import sbt.Keys._
// import sbt.Project.richInitializeTask
import sbt.ProjectExtra.*
import sbt.ScopeAxis.Zero
import sbt.SlashSyntax0.given
import sbt.io.syntax._
import sbt.nio.Keys._

View File

@ -18,6 +18,7 @@ import sbt.io.syntax._
import sbt.Cross._
import sbt.Def.{ ScopedKey, Setting }
import sbt.ProjectExtra.extract
import sbt.ScopeAxis.{ Select, Zero }
import sbt.SlashSyntax0.given
import sbt.internal.util.complete.DefaultParsers._
import sbt.internal.util.AttributeKey

View File

@ -11,6 +11,7 @@ package internal
import java.nio.file.{ Path => NioPath }
import sbt.ScopeAxis.Select
import sbt.nio.Keys._
import sbt.nio.{ FileChanges, FileStamp }
@ -100,6 +101,6 @@ object FileChangesMacro:
private def getTaskScope[A: Type](in: Expr[TaskKey[A]])(using qctx: Quotes): Expr[sbt.Scope] =
'{
if $in.scope.task.toOption.isDefined then $in.scope
else $in.scope.copy(task = sbt.Select($in.key))
else $in.scope.copy(task = Select($in.key))
}
end FileChangesMacro

View File

@ -15,6 +15,7 @@ import sbt.Keys._
import sbt.Project.inScope
import sbt.ProjectExtra.{ prefixConfigs, setProject, showLoadingKey, structure }
import sbt.Scope.GlobalScope
import sbt.ScopeAxis.{ Select, Zero }
import sbt.SlashSyntax0.given
import sbt.internal.BuildStreams._
import sbt.internal.inc.classpath.ClasspathUtil

View File

@ -13,6 +13,7 @@ import sbt.Def.ScopedKey
import sbt.Keys._
import sbt.ProjectExtra.showContextKey
import sbt.Scope.Global
import sbt.ScopeAxis.{ Select, Zero }
import sbt.SlashSyntax0.given
import sbt.internal.util.MainAppender._
import sbt.internal.util.{ Terminal => ITerminal, _ }

View File

@ -10,6 +10,7 @@ package sbt
package internal
import sbt.internal.util.AttributeKey
import sbt.ScopeAxis.{ Select, This, Zero }
object Resolve {
def apply(

View File

@ -16,6 +16,7 @@ import sbt.librarymanagement.Configuration
import ProjectExtra.{ relation }
import Def.{ ScopedKey, Setting }
import Scope.Global
import sbt.ScopeAxis.{ Select, This, Zero }
import sbt.SlashSyntax0.given
import complete._
import DefaultParsers._

View File

@ -13,6 +13,7 @@ import sbt.Def._
import sbt.Keys._
// import sbt.Project.richInitializeTask
import sbt.ProjectExtra.*
import sbt.ScopeAxis.Zero
import sbt.SlashSyntax0.given
import sbt.internal.io.Source
import sbt.internal.nio.Globs

View File

@ -13,6 +13,7 @@ import java.nio.file.{ Files, Path }
import java.util.concurrent.ConcurrentHashMap
import sbt.Keys._
import sbt.ScopeAxis.{ Select, Zero }
import sbt.SlashSyntax0.given
import sbt.internal.Clean.ToSeqPath
import sbt.internal.Continuous.FileStampRepository

View File

@ -10,6 +10,7 @@ package sbt
import sbt.internal.util.Types.idFun
import sbt.internal.TestBuild._
import sbt.ScopeAxis.{ Select, This, Zero }
import hedgehog._
import hedgehog.Result.{ all, assert, failure, success }
import hedgehog.runner._

View File

@ -12,6 +12,7 @@ import sbt.internal.TestBuild._
import sbt.internal.util.complete.Parser
import sbt.internal.{ Resolve, TestBuild }
import sbt.ProjectExtra.equalKeys
import sbt.ScopeAxis.{ Select, Zero }
import hedgehog._
import hedgehog.core.{ ShrinkLimit, SuccessCount }
import hedgehog.runner._

View File

@ -10,6 +10,7 @@ package sbt
import java.net.URI
import sbt.Def._
import sbt.ScopeAxis.{ Select, Zero }
import sbt.internal.TestBuild
import sbt.internal.TestBuild._
import sbt.internal.util.AttributeKey

View File

@ -10,6 +10,7 @@ package sbt
package internal
import Def.{ ScopedKey, Setting }
import sbt.ScopeAxis.{ Select, Zero }
import sbt.internal.util.{ AttributeKey, Relation }
import sbt.internal.util.Types.{ const, some }
import sbt.internal.util.complete.Parser

View File

@ -10,6 +10,7 @@ package testpkg
import java.net.URI
import sbt.{ Result => _, _ }
import sbt.ScopeAxis.{ Select, Zero }
import sbt.Def._
import sbt.internal.TestBuild
import sbt.internal.TestBuild._

View File

@ -34,6 +34,9 @@ trait Import {
type ClasspathDependency = ClasspathDep.ClasspathDependency
val ResolvedClasspathDependency = ClasspathDep.ResolvedClasspathDependency
type ResolvedClasspathDependency = ClasspathDep.ResolvedClasspathDependency
val Select = ScopeAxis.Select
val This = ScopeAxis.This
val Zero = ScopeAxis.Zero
// sbt.testing
type TestResult = sbt.protocol.testing.TestResult
val TestResult = sbt.protocol.testing.TestResult