From e7b893fdc5297ce25ca3cd0f2be5c0d3bfddab66 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Mon, 2 Oct 2017 16:37:12 +0100 Subject: [PATCH] Cleanup and improve the unified slash syntax --- main/src/main/scala/sbt/SlashSyntax.scala | 144 ++++++------------ .../main/scala/sbt/internal/KeyIndex.scala | 4 +- main/src/main/scala/sbt/internal/Load.scala | 7 +- .../test/scala/sbt/internal/TestBuild.scala | 4 +- 4 files changed, 50 insertions(+), 109 deletions(-) diff --git a/main/src/main/scala/sbt/SlashSyntax.scala b/main/src/main/scala/sbt/SlashSyntax.scala index b6a8b560b..14d6d476c 100644 --- a/main/src/main/scala/sbt/SlashSyntax.scala +++ b/main/src/main/scala/sbt/SlashSyntax.scala @@ -1,6 +1,5 @@ package sbt -import java.io.File import sbt.librarymanagement.Configuration /** @@ -23,126 +22,75 @@ import sbt.librarymanagement.Configuration trait SlashSyntax { import SlashSyntax._ - implicit def sbtScopeSyntaxRichReference(r: Reference): RichReference = - new RichReference(Scope(Select(r), This, This, This)) + implicit def sbtSlashSyntaxRichReferenceAxis(a: ScopeAxis[Reference]): RichReference = + new RichReference(Scope(a, This, This, This)) - implicit def sbtScopeSyntaxRichProject(p: Project): RichReference = - new RichReference(Scope(Select(p), This, This, This)) + implicit def sbtSlashSyntaxRichReference(r: Reference): RichReference = Select(r) + implicit def sbtSlashSyntaxRichProject(p: Project): RichReference = (p: Reference) - implicit def sbtScopeSyntaxRichConfiguration(c: Configuration): RichConfiguration = + implicit def sbtSlashSyntaxRichConfigKey(c: ConfigKey): RichConfiguration = new RichConfiguration(Scope(This, Select(c), This, This)) - implicit def sbtScopeSyntaxRichScope(s: Scope): RichScope = - new RichScope(s) + implicit def sbtSlashSyntaxRichConfiguration(c: Configuration): RichConfiguration = (c: ConfigKey) - implicit def sbtScopeSyntaxRichScopeFromScoped(t: Scoped): RichScope = + implicit def sbtSlashSyntaxRichScopeFromScoped(t: Scoped): RichScope = new RichScope(Scope(This, This, Select(t.key), This)) - implicit def sbtScopeSyntaxRichScopeAxis(a: ScopeAxis[Reference]): RichScopeAxis = - new RichScopeAxis(a) + implicit def sbtSlashSyntaxRichScope(s: Scope): RichScope = new RichScope(s) - // Materialize the setting key thunk - implicit def sbtScopeSyntaxSettingKeyThunkMaterialize[A]( - thunk: SettingKeyThunk[A]): SettingKey[A] = - thunk.materialize + implicit def sbtSlashSyntaxScopeAndKeyRescope(scopeAndKey: ScopeAndKey[_]): TerminalScope = + scopeAndKey.rescope - implicit def sbtScopeSyntaxSettingKeyThunkKeyRescope[A](thunk: SettingKeyThunk[A]): RichScope = - thunk.rescope - - // Materialize the task key thunk - implicit def sbtScopeSyntaxTaskKeyThunkMaterialize[A](thunk: TaskKeyThunk[A]): TaskKey[A] = - thunk.materialize - - implicit def sbtScopeSyntaxTaskKeyThunkRescope[A](thunk: TaskKeyThunk[A]): RichScope = - thunk.rescope - - // Materialize the input key thunk - implicit def sbtScopeSyntaxInputKeyThunkMaterialize[A](thunk: InputKeyThunk[A]): InputKey[A] = - thunk.materialize - - implicit def sbtScopeSyntaxInputKeyThunkRescope[A](thunk: InputKeyThunk[A]): RichScope = - thunk.rescope + implicit def sbtSlashSyntaxScopeAndKeyMaterialize[K <: Key[K]](scopeAndKey: ScopeAndKey[K]): K = + scopeAndKey.materialize } object SlashSyntax { - /** RichReference wraps a project to provide the `/` operator for scoping. */ - final class RichReference(s: Scope) { - def /(c: Configuration): RichConfiguration = new RichConfiguration(s in c) - - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: SettingKey[A]): SettingKeyThunk[A] = new SettingKeyThunk(s, key) - - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: TaskKey[A]): TaskKeyThunk[A] = new TaskKeyThunk(s, key) - - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: InputKey[A]): InputKeyThunk[A] = new InputKeyThunk(s, key) - } - - /** RichConfiguration wraps a configuration to provide the `/` operator for scoping. */ - final class RichConfiguration(s: Scope) { - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: SettingKey[A]): SettingKeyThunk[A] = new SettingKeyThunk(s, key) - - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: TaskKey[A]): TaskKeyThunk[A] = new TaskKeyThunk(s, key) - - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: InputKey[A]): InputKeyThunk[A] = new InputKeyThunk(s, key) - } - - /** RichScope wraps a general scope to provide the `/` operator for scoping. */ - final class RichScope(scope: Scope) { - def /[A](key: SettingKey[A]): SettingKey[A] = key in scope - def /[A](key: TaskKey[A]): TaskKey[A] = key in scope - def /[A](key: InputKey[A]): InputKey[A] = key in scope - } - - /** RichScopeAxis wraps a project axis to provide the `/` operator to `Zero` for scoping. */ - final class RichScopeAxis(a: ScopeAxis[Reference]) { - private[this] def toScope: Scope = Scope(a, This, This, This) - - def /(c: Configuration): RichConfiguration = new RichConfiguration(toScope in c) + /** RichReference wraps a reference to provide the `/` operator for scoping. */ + final class RichReference(protected val scope: Scope) extends RichScopeLike { + def /(c: Configuration): RichConfiguration = new RichConfiguration(scope in c) // This is for handling `Zero / Zero / name`. def /(configAxis: ScopeAxis[ConfigKey]): RichConfiguration = - new RichConfiguration(toScope.copy(config = configAxis)) + new RichConfiguration(scope.copy(config = configAxis)) + } - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: SettingKey[A]): SettingKeyThunk[A] = new SettingKeyThunk(toScope, key) + /** RichConfiguration wraps a configuration to provide the `/` operator for scoping. */ + final class RichConfiguration(protected val scope: Scope) extends RichScopeLike - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: TaskKey[A]): TaskKeyThunk[A] = new TaskKeyThunk(toScope, key) + /** Both `Scoped.ScopingSetting` and `Scoped` are parents of `SettingKey`, `TaskKey` and + * `InputKey`. We'll need both, so this is a convenient type alias. */ + type Key[K] = Scoped.ScopingSetting[K] with Scoped - // We don't know what the key is for yet, so just capture in a thunk. - def /[A](key: InputKey[A]): InputKeyThunk[A] = new InputKeyThunk(toScope, key) + sealed trait RichScopeLike { + protected def scope: Scope + + // We don't know what the key is for yet, so just capture for now. + def /[K <: Key[K]](key: K): ScopeAndKey[K] = new ScopeAndKey(scope, key) + } + + /** RichScope wraps a general scope to provide the `/` operator for scoping. */ + final class RichScope(protected val scope: Scope) extends RichScopeLike + + /** TerminalScope provides the last `/` for scoping. */ + final class TerminalScope(scope: Scope) { + def /[K <: Key[K]](key: K): K = key in scope } /** - * SettingKeyThunk is a thunk used to hold a scope and a key - * while we're not sure if the key is terminal or task-scoping. + * ScopeAndKey is a synthetic DSL construct necessary to capture both the built-up scope with a + * given key, while we're not sure if the given key is terminal or task-scoping. The "materialize" + * method will be used if it's terminal, returning the scoped key, while "rescope" will be used + * if we're task-scoping. + * + * @param scope the built-up scope + * @param key a given key + * @tparam K the type of the given key, necessary to type "materialize" */ - final class SettingKeyThunk[A](base: Scope, key: SettingKey[A]) { - private[sbt] def materialize: SettingKey[A] = key in base - private[sbt] def rescope: RichScope = new RichScope(base in key.key) + final class ScopeAndKey[K <: Key[K]](scope: Scope, key: K) { + private[sbt] def materialize: K = key in scope + private[sbt] def rescope: TerminalScope = new TerminalScope(scope in key.key) } - /** - * TaskKeyThunk is a thunk used to hold a scope and a key - * while we're not sure if the key is terminal or task-scoping. - */ - final class TaskKeyThunk[A](base: Scope, key: TaskKey[A]) { - private[sbt] def materialize: TaskKey[A] = key in base - private[sbt] def rescope: RichScope = new RichScope(base in key.key) - } - - /** - * InputKeyThunk is a thunk used to hold a scope and a key - * while we're not sure if the key is terminal or task-scoping. - */ - final class InputKeyThunk[A](base: Scope, key: InputKey[A]) { - private[sbt] def materialize: InputKey[A] = key in base - private[sbt] def rescope: RichScope = new RichScope(base in key.key) - } } diff --git a/main/src/main/scala/sbt/internal/KeyIndex.scala b/main/src/main/scala/sbt/internal/KeyIndex.scala index 573fed713..ebbf80ca8 100644 --- a/main/src/main/scala/sbt/internal/KeyIndex.scala +++ b/main/src/main/scala/sbt/internal/KeyIndex.scala @@ -31,9 +31,7 @@ object KeyIndex { } yield { val data = ids map { id => val configs = configurations.getOrElse(id, Seq()) - Option(id) -> new ConfigIndex(Map.empty, Map(configs map { c => - (c.name, c.id) - }: _*)) + Option(id) -> new ConfigIndex(Map.empty, configs.map(c => (c.name, c.id)).toMap) } Option(uri) -> new ProjectIndex(data.toMap) } diff --git a/main/src/main/scala/sbt/internal/Load.scala b/main/src/main/scala/sbt/internal/Load.scala index 0ed05e692..133d7b39f 100755 --- a/main/src/main/scala/sbt/internal/Load.scala +++ b/main/src/main/scala/sbt/internal/Load.scala @@ -324,11 +324,8 @@ private[sbt] object Load { val attributeKeys = Index.attributeKeys(data) ++ keys.map(_.key) val scopedKeys = keys ++ data.allKeys((s, k) => ScopedKey(s, k)).toVector val projectsMap = projects.mapValues(_.defined.keySet) - val configsMap: Map[String, Seq[Configuration]] = Map(projects.values.toSeq flatMap { bu => - bu.defined map { - case (k, v) => (k, v.configurations) - } - }: _*) + val configsMap: Map[String, Seq[Configuration]] = + projects.values.flatMap(bu => bu.defined map { case (k, v) => (k, v.configurations) }).toMap val keyIndex = KeyIndex(scopedKeys.toVector, projectsMap, configsMap) val aggIndex = KeyIndex.aggregate(scopedKeys.toVector, extra(keyIndex), projectsMap, configsMap) new StructureIndex( diff --git a/main/src/test/scala/sbt/internal/TestBuild.scala b/main/src/test/scala/sbt/internal/TestBuild.scala index 96a4b1383..47874cb7e 100644 --- a/main/src/test/scala/sbt/internal/TestBuild.scala +++ b/main/src/test/scala/sbt/internal/TestBuild.scala @@ -225,9 +225,7 @@ abstract class TestBuild { p <- b.projects.toVector c <- p.configurations.toVector } yield c - val confMap = Map(confs map { c => - (c.name, Seq(c)) - }: _*) + val confMap = confs.map(c => (c.name, Seq(c))).toMap new Structure(env, current, data, KeyIndex(keys, projectsMap, confMap), keyMap) }