diff --git a/main/Build.scala b/main/Build.scala index 0ac1d0377..295faab1b 100644 --- a/main/Build.scala +++ b/main/Build.scala @@ -135,12 +135,12 @@ object Index } def stringToKeyMap(settings: Settings[Scope]): Map[String, AttributeKey[_]] = { - val multiMap = settings.data.values.flatMap(_.keys).toList.distinct.groupBy(_.label) - val duplicates = multiMap collect { case (k, x1 :: x2 :: _) => k } + val multiMap = settings.data.values.flatMap(_.keys).toSet[AttributeKey[_]].groupBy(_.label) + val duplicates = multiMap collect { case (k, xs) if xs.size > 1 => (k, xs.map(_.manifest)) } collect { case (k, xs) if xs.size > 1 => (k, xs) } if(duplicates.isEmpty) multiMap.collect { case (k, v) if validID(k) => (k, v.head) } toMap; else - error(duplicates.mkString("AttributeKey ID collisions detected for '", "', '", "'")) + error(duplicates map { case (k, tps) => "'" + k + "' (" + tps.mkString(", ") + ")" } mkString("AttributeKey ID collisions detected for: ", ", ", "")) } private[this] type TriggerMap = collection.mutable.HashMap[Task[_], Seq[Task[_]]] def triggers(ss: Settings[Scope]): Triggers[Task] = diff --git a/main/Keys.scala b/main/Keys.scala index 2dab01ab8..2216d9322 100644 --- a/main/Keys.scala +++ b/main/Keys.scala @@ -267,7 +267,7 @@ object Keys type Streams = std.Streams[ScopedKey[_]] type TaskStreams = std.TaskStreams[ScopedKey[_]] - def dummy[T](name: String, description: String): (TaskKey[T], Task[T]) = (TaskKey[T](name, description), dummyTask(name)) + def dummy[T: Manifest](name: String, description: String): (TaskKey[T], Task[T]) = (TaskKey[T](name, description), dummyTask(name)) def dummyTask[T](name: String): Task[T] = { val base: Task[T] = task( error("Dummy task '" + name + "' did not get converted to a full task.") ) named name diff --git a/main/Structure.scala b/main/Structure.scala index c15379f6a..9f1d64e8e 100644 --- a/main/Structure.scala +++ b/main/Structure.scala @@ -530,10 +530,10 @@ object Scoped object InputKey { - def apply[T](label: String, description: String = ""): InputKey[T] = + def apply[T: Manifest](label: String, description: String = ""): InputKey[T] = apply( AttributeKey[InputTask[T]](label, description) ) - def apply[T](label: String, description: String, extend1: Scoped, extendN: Scoped*): InputKey[T] = + def apply[T: Manifest](label: String, description: String, extend1: Scoped, extendN: Scoped*): InputKey[T] = apply( AttributeKey[InputTask[T]](label, description, extendScoped(extend1, extendN)) ) def apply[T](akey: AttributeKey[InputTask[T]]): InputKey[T] = @@ -541,10 +541,10 @@ object InputKey } object TaskKey { - def apply[T](label: String, description: String = ""): TaskKey[T] = + def apply[T: Manifest](label: String, description: String = ""): TaskKey[T] = apply( AttributeKey[Task[T]](label, description) ) - def apply[T](label: String, description: String, extend1: Scoped, extendN: Scoped*): TaskKey[T] = + def apply[T: Manifest](label: String, description: String, extend1: Scoped, extendN: Scoped*): TaskKey[T] = apply( AttributeKey[Task[T]](label, description, extendScoped(extend1, extendN)) ) def apply[T](akey: AttributeKey[Task[T]]): TaskKey[T] = @@ -552,10 +552,10 @@ object TaskKey } object SettingKey { - def apply[T](label: String, description: String = ""): SettingKey[T] = + def apply[T: Manifest](label: String, description: String = ""): SettingKey[T] = apply( AttributeKey[T](label, description) ) - def apply[T](label: String, description: String, extend1: Scoped, extendN: Scoped*): SettingKey[T] = + def apply[T: Manifest](label: String, description: String, extend1: Scoped, extendN: Scoped*): SettingKey[T] = apply( AttributeKey[T](label, description, extendScoped(extend1, extendN)) ) def apply[T](akey: AttributeKey[T]): SettingKey[T] = diff --git a/util/collection/Attributes.scala b/util/collection/Attributes.scala index 1025c03df..2302d326d 100644 --- a/util/collection/Attributes.scala +++ b/util/collection/Attributes.scala @@ -4,29 +4,39 @@ package sbt import Types._ +import scala.reflect.Manifest // T must be invariant to work properly. // Because it is sealed and the only instances go through AttributeKey.apply, // a single AttributeKey instance cannot conform to AttributeKey[T] for different Ts sealed trait AttributeKey[T] { + def manifest: Manifest[T] def label: String def description: Option[String] def extend: Seq[AttributeKey[_]] override final def toString = label + override final def hashCode = label.hashCode + override final def equals(o: Any) = (this eq o.asInstanceOf[AnyRef]) || (o match { + case a: AttributeKey[t] => a.label == this.label && a.manifest == this.manifest + case _ => false + }) } object AttributeKey { - def apply[T](name: String): AttributeKey[T] = new AttributeKey[T] { + def apply[T](name: String)(implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def manifest = mf def label = name def description = None def extend = Nil } - def apply[T](name: String, description0: String): AttributeKey[T] = new AttributeKey[T] { + def apply[T](name: String, description0: String)(implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def manifest = mf def label = name def description = Some(description0) def extend = Nil } - def apply[T](name: String, description0: String, extend0: Seq[AttributeKey[_]]): AttributeKey[T] = new AttributeKey[T] { + def apply[T](name: String, description0: String, extend0: Seq[AttributeKey[_]])(implicit mf: Manifest[T]): AttributeKey[T] = new AttributeKey[T] { + def manifest = mf def label = name def description = Some(description0) def extend = extend0