From 16e7c70035821fa7783c934fc79a4200d46b7b20 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Thu, 31 Jan 2019 13:54:44 -0800 Subject: [PATCH 1/3] Lint TypeFunctions.scala --- .../src/main/scala/sbt/internal/util/TypeFunctions.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala b/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala index 815eacc39..dea102f8c 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala @@ -18,7 +18,7 @@ trait TypeFunctions { final val left = λ[Id ~> Left[?, Nothing]](Left(_)) final val right = λ[Id ~> Right[Nothing, ?]](Right(_)) final val some = λ[Id ~> Some](Some(_)) - final def idFun[T] = (t: T) => t + final def idFun[T]: T => T = (t: T) => t final def const[A, B](b: B): A => B = _ => b final def idK[M[_]]: M ~> M = λ[M ~> M](m => m) @@ -38,11 +38,11 @@ trait ~>[-A[_], +B[_]] { outer => // directly on ~> because of type inference limitations final def ∙[C[_]](g: C ~> A): C ~> B = λ[C ~> B](c => outer.apply(g(c))) final def ∙[C, D](g: C => D)(implicit ev: D <:< A[D]): C => B[D] = i => apply(ev(g(i))) - final def fn[T] = (t: A[T]) => apply[T](t) + final def fn[T]: A[T] => B[T] = (t: A[T]) => apply[T](t) } object ~> { import TypeFunctions._ val Id: Id ~> Id = idK[Id] - implicit def tcIdEquals: (Id ~> Id) = Id + implicit def tcIdEquals: Id ~> Id = Id } From 9b40a0e5851d2e92302ed5d17b504927b4f63af0 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Thu, 31 Jan 2019 13:56:13 -0800 Subject: [PATCH 2/3] Add meaningful toString to TypeFunctions It can be hard to debug these because the toString output for a kind projector plugin provided lambda is inscrutable. --- .../sbt/internal/util/TypeFunctions.scala | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala b/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala index dea102f8c..6a9aa65d5 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala @@ -8,19 +8,22 @@ package sbt.internal.util trait TypeFunctions { + import TypeFunctions._ type Id[X] = X type NothingK[X] = Nothing sealed trait Const[A] { type Apply[B] = A } sealed trait ConstK[A] { type l[L[x]] = A } sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] } sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] } + type AnyLeft[T] = Left[T, Nothing] + type AnyRight[T] = Right[Nothing, T] - final val left = λ[Id ~> Left[?, Nothing]](Left(_)) - final val right = λ[Id ~> Right[Nothing, ?]](Right(_)) - final val some = λ[Id ~> Some](Some(_)) - final def idFun[T]: T => T = (t: T) => t - final def const[A, B](b: B): A => B = _ => b - final def idK[M[_]]: M ~> M = λ[M ~> M](m => m) + final val left = λ[Id ~> AnyLeft](Left(_)).setToString("TypeFunctions.left") + final val right = λ[Id ~> AnyRight](Right(_)).setToString("TypeFunctions.right") + final val some = λ[Id ~> Some](Some(_)).setToString("TypeFunctions.some") + final def idFun[T]: T => T = ((t: T) => t).setToString("TypeFunctions.id") + final def const[A, B](b: B): A => B = ((_: A) => b).setToString(s"TypeFunctions.const($b)") + final def idK[M[_]]: M ~> M = λ[M ~> M](m => m).setToString("TypeFunctions.idK") def nestCon[M[_], N[_], G[_]](f: M ~> N): (M ∙ G)#l ~> (N ∙ G)#l = f.asInstanceOf[(M ∙ G)#l ~> (N ∙ G)#l] // implemented with a cast to avoid extra object+method call. @@ -31,7 +34,24 @@ trait TypeFunctions { type ~>|[A[_], B[_]] = A ~> Compose[Option, B]#Apply } -object TypeFunctions extends TypeFunctions +object TypeFunctions extends TypeFunctions { + private implicit class Ops[T[_], R[_]](val underlying: T ~> R) extends AnyVal { + def setToString(string: String): T ~> R = new (T ~> R) { + override def apply[U](a: T[U]): R[U] = underlying(a) + override def toString: String = string + override def equals(o: Any): Boolean = underlying.equals(o) + override def hashCode: Int = underlying.hashCode + } + } + private implicit class FunctionOps[A, B](val f: A => B) extends AnyVal { + def setToString(string: String): A => B = new (A => B) { + override def apply(a: A): B = f(a) + override def toString: String = string + override def equals(o: Any): Boolean = f.equals(o) + override def hashCode: Int = f.hashCode + } + } +} trait ~>[-A[_], +B[_]] { outer => def apply[T](a: A[T]): B[T] From efa52143d0203d8f4c343aa8326d63118f78b4ff Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Thu, 31 Jan 2019 16:03:30 -0800 Subject: [PATCH 3/3] Make types private While the AnyLeft and AnyRight types are necessary to make the extension class work, I don't want to leak the AnyLeft or AnyRight traits into the public api. It wasn't neceessary to annotate `some`, but it's good practice to annotate anything public anyway. --- .../main/scala/sbt/internal/util/TypeFunctions.scala | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala b/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala index 6a9aa65d5..fff4e5dd8 100644 --- a/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala +++ b/internal/util-collection/src/main/scala/sbt/internal/util/TypeFunctions.scala @@ -15,12 +15,14 @@ trait TypeFunctions { sealed trait ConstK[A] { type l[L[x]] = A } sealed trait Compose[A[_], B[_]] { type Apply[T] = A[B[T]] } sealed trait ∙[A[_], B[_]] { type l[T] = A[B[T]] } - type AnyLeft[T] = Left[T, Nothing] - type AnyRight[T] = Right[Nothing, T] + private type AnyLeft[T] = Left[T, Nothing] + private type AnyRight[T] = Right[Nothing, T] - final val left = λ[Id ~> AnyLeft](Left(_)).setToString("TypeFunctions.left") - final val right = λ[Id ~> AnyRight](Right(_)).setToString("TypeFunctions.right") - final val some = λ[Id ~> Some](Some(_)).setToString("TypeFunctions.some") + final val left: Id ~> Left[?, Nothing] = + λ[Id ~> AnyLeft](Left(_)).setToString("TypeFunctions.left") + final val right: Id ~> Right[Nothing, ?] = + λ[Id ~> AnyRight](Right(_)).setToString("TypeFunctions.right") + final val some: Id ~> Some[?] = λ[Id ~> Some](Some(_)).setToString("TypeFunctions.some") final def idFun[T]: T => T = ((t: T) => t).setToString("TypeFunctions.id") final def const[A, B](b: B): A => B = ((_: A) => b).setToString(s"TypeFunctions.const($b)") final def idK[M[_]]: M ~> M = λ[M ~> M](m => m).setToString("TypeFunctions.idK")