Skip to content

Commit

Permalink
Merge pull request #483 from fthomas/topic/AsValueOf
Browse files Browse the repository at this point in the history
Unify numeric type class instances
  • Loading branch information
fthomas committed Apr 21, 2018
2 parents 1f72cae + 4443b36 commit 54f395a
Show file tree
Hide file tree
Showing 15 changed files with 183 additions and 294 deletions.
6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ cache:
- "$HOME/.ivy2/cache"
- "$HOME/.sbt/boot/"
script:
- sbt ++$TRAVIS_SCALA_VERSION validate
- sbt ++$TRAVIS_SCALA_VERSION validateJVM
- sbt ++$TRAVIS_SCALA_VERSION validateJS
after_success:
- codecov
notifications:
Expand All @@ -31,7 +32,8 @@ matrix:
before_install:
- curl https://raw.githubusercontent.com/scala-native/scala-native/master/scripts/travis_setup.sh | bash -x
script:
- sbt ++$TRAVIS_SCALA_VERSION compileNative validate
- sbt ++$TRAVIS_SCALA_VERSION compileNative validateJVM
- sbt ++$TRAVIS_SCALA_VERSION validateJS
- scala: 2.13.0-M3 # Remember to update this in build.sbt, too.
script:
- sbt ++$TRAVIS_SCALA_VERSION coreJVM/compile
Expand Down
80 changes: 9 additions & 71 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ lazy val moduleCrossSettings = Def.settings(
)

lazy val moduleJvmSettings = Def.settings(
fork in Test := true,
mimaPreviousArtifacts := {
val hasPredecessor = !unreleasedModules.value.contains(moduleName.value)
latestVersionInSeries.value match {
Expand All @@ -317,74 +316,7 @@ lazy val moduleJvmSettings = Def.settings(
mimaBinaryIssueFilters ++= {
import com.typesafe.tools.mima.core._
Seq(
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.scalacheck.StringInstances.nonEmptyStringArbitrary"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.api.Refined.get"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.api.Refined.get$extension"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.util.time$"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.util.time"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.numeric.moduloValidateNat"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.numeric.moduloValidateWit"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.NumericValidate.moduloValidateNat"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.NumericValidate.moduloValidateWit"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.types.*"),
ProblemFilters.exclude[IncompatibleResultTypeProblem]("eu.timepit.refined.types.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.types.*"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.types.*"),
ProblemFilters.exclude[ReversedMissingMethodProblem]("eu.timepit.refined.types.*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.char.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.CharValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.char$*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.boolean.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.BooleanValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.boolean$*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.generic.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.GenericValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.generic$*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.numeric.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.NumericValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.numeric*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.string.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.StringValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.string*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.collection.*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.CollectionValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.collection*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.string#IPv4.*"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.string#IPv6.*"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.eval$"),
ProblemFilters.exclude[DirectMissingMethodProblem]("eu.timepit.refined.eval.evalValidate"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.EvalValidate"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.jsonpath.string.jsonPathValidate"),
ProblemFilters.exclude[MissingTypesProblem]("eu.timepit.refined.jsonpath.string$*"),
ProblemFilters.exclude[MissingClassProblem]("eu.timepit.refined.jsonpath.StringValidate"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.NumericInference.greaterEqualInference"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.NumericInference.lessEqualInference"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.scalacheck.StringInstances.stringSizeArbitrary"),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"eu.timepit.refined.scalacheck.numeric.*"),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"eu.timepit.refined.scalacheck.NumericInstances.*"),
ProblemFilters.exclude[IncompatibleMethTypeProblem]("eu.timepit.refined.scalacheck.all.*"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"eu.timepit.refined.scalacheck.NumericInstances.*"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.scalacheck.NumericInstances.*"),
ProblemFilters.exclude[InheritedNewAbstractMethodProblem]("eu.timepit.refined.types.*"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.api.RefinedType.dealias"),
ProblemFilters.exclude[ReversedMissingMethodProblem](
"eu.timepit.refined.scalacheck.RefTypeInstances.checkArbitraryRefinedType")
)
)
}
)

Expand Down Expand Up @@ -549,7 +481,7 @@ addCommandsAlias("testJS", allSubprojectsJS.map(_ + "/test"))
addCommandsAlias("testJVM", allSubprojectsJVM.map(_ + "/test"))

addCommandsAlias(
"validate",
"validateJVM",
Seq(
"clean",
"scalafmtCheck",
Expand All @@ -558,7 +490,6 @@ addCommandsAlias(
"scalastyle",
"test:scalastyle",
"mimaReportBinaryIssues",
"testJS",
"coverage",
"testJVM",
"coverageReport",
Expand All @@ -569,3 +500,10 @@ addCommandsAlias(
"packageSrc"
)
)

addCommandsAlias(
"validateJS",
Seq(
"testJS"
)
)
2 changes: 1 addition & 1 deletion latestVersion.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
latestVersion in ThisBuild := "0.8.7"

latestVersionInSeries in ThisBuild := Some("0.8.7")
latestVersionInSeries in ThisBuild := None

unreleasedModules in ThisBuild := Set(
"refined-scopt",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package eu.timepit.refined.api

import eu.timepit.refined.boolean.And
import eu.timepit.refined.internal.Adjacent
import eu.timepit.refined.internal.{Adjacent, WitnessAs}
import eu.timepit.refined.numeric.{Greater, GreaterEqual, Less, LessEqual}
import shapeless.{Nat, Witness}
import shapeless.ops.nat.ToInt

/**
* Type class defining the maximum value of a given type
Expand Down Expand Up @@ -37,18 +35,12 @@ trait MaxInstances extends LowPriorityMaxInstances {
): Max[F[T, GreaterEqual[N]]] =
Max.instance(rt.unsafeWrap(mt.max))

implicit def lessEqualMaxWit[F[_, _], T, N <: T](
implicit rt: RefType[F],
wn: Witness.Aux[N]
): Max[F[T, LessEqual[N]]] =
Max.instance(rt.unsafeWrap(wn.value))

implicit def lessEqualMaxNat[F[_, _], T, N <: Nat](
implicit rt: RefType[F],
tn: ToInt[N],
nt: Numeric[T]
implicit def lessEqualMax[F[_, _], T, N](
implicit
rt: RefType[F],
wn: WitnessAs[N, T]
): Max[F[T, LessEqual[N]]] =
Max.instance(rt.unsafeWrap(nt.fromInt(tn())))
Max.instance(rt.unsafeWrap(wn.snd))

implicit def lessMax[F[_, _], T, N](
implicit rt: RefType[F],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package eu.timepit.refined.api

import eu.timepit.refined.boolean.And
import eu.timepit.refined.internal.Adjacent
import eu.timepit.refined.internal.{Adjacent, WitnessAs}
import eu.timepit.refined.numeric.{Greater, GreaterEqual, Less, LessEqual}
import shapeless.{Nat, Witness}
import shapeless.ops.nat.ToInt

/**
* Type class defining the minimum value of a given type
Expand Down Expand Up @@ -37,18 +35,12 @@ trait MinInstances extends LowPriorityMinInstances {
): Min[F[T, LessEqual[N]]] =
Min.instance(rt.unsafeWrap(mt.min))

implicit def greaterEqualMinWit[F[_, _], T, N <: T](
implicit rt: RefType[F],
wn: Witness.Aux[N]
): Min[F[T, GreaterEqual[N]]] =
Min.instance(rt.unsafeWrap(wn.value))

implicit def greaterEqualMinNat[F[_, _], T, N <: Nat](
implicit rt: RefType[F],
tn: ToInt[N],
nt: Numeric[T]
implicit def greaterEqualMin[F[_, _], T, N](
implicit
rt: RefType[F],
wn: WitnessAs[N, T]
): Min[F[T, GreaterEqual[N]]] =
Min.instance(rt.unsafeWrap(nt.fromInt(tn())))
Min.instance(rt.unsafeWrap(wn.snd))

implicit def greaterMin[F[_, _], T, N](
implicit rt: RefType[F],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import eu.timepit.refined.boolean.Not
import eu.timepit.refined.collection._
import eu.timepit.refined.generic.Equal
import eu.timepit.refined.internal.Resources
import eu.timepit.refined.numeric.{GreaterEqual, LessEqual}
import eu.timepit.refined.numeric.{GreaterEqual, Interval}
import shapeless.Witness
import shapeless.nat._0

/** Module for collection predicates. */
object collection extends CollectionInference {
Expand Down Expand Up @@ -86,7 +87,7 @@ object collection extends CollectionInference {
* Predicate that checks if the size of a `Traversable` is less than
* or equal to `N`.
*/
type MaxSize[N] = Size[LessEqual[N]]
type MaxSize[N] = Size[Interval.Closed[_0, N]]

/** Predicate that checks if a `Traversable` is not empty. */
type NonEmpty = Not[Empty]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package eu.timepit.refined
import eu.timepit.refined.api.{Inference, Validate}
import eu.timepit.refined.api.Inference.==>
import eu.timepit.refined.generic._
import eu.timepit.refined.internal.WitnessAs
import shapeless._
import shapeless.ops.coproduct.ToHList
import shapeless.ops.hlist.ToList
import shapeless.ops.nat.ToInt
import shapeless.ops.record.Keys

/** Module for generic predicates. */
Expand Down Expand Up @@ -36,19 +36,10 @@ object generic extends GenericInference {
final case class Supertype[U]()

object Equal {
implicit def equalValidateWit[T, U <: T](
implicit wu: Witness.Aux[U]
implicit def equalValidate[T, U](
implicit wu: WitnessAs[U, T]
): Validate.Plain[T, Equal[U]] =
Validate.fromPredicate(_ == wu.value, t => s"($t == ${wu.value})", Equal(wu.value))

implicit def equalValidateNat[N <: Nat, T](
implicit tn: ToInt[N],
wn: Witness.Aux[N],
nt: Numeric[T]
): Validate.Plain[T, Equal[N]] = {
val n = nt.fromInt(tn())
Validate.fromPredicate(_ == n, t => s"($t == $n)", Equal(wn.value))
}
Validate.fromPredicate(_ == wu.snd, t => s"($t == ${wu.snd})", Equal(wu.fst))
}

object ConstructorNames {
Expand Down Expand Up @@ -105,17 +96,10 @@ object generic extends GenericInference {

private[refined] trait GenericInference {

implicit def equalValidateInferenceWit[T, U <: T, P](
implicit v: Validate[T, P],
wu: Witness.Aux[U]
implicit def equalValidateInference[T, U, P](
implicit
v: Validate[T, P],
wu: WitnessAs[U, T]
): Equal[U] ==> P =
Inference(v.isValid(wu.value), s"equalValidateInferenceWit(${v.showExpr(wu.value)})")

implicit def equalValidateInferenceNat[T, N <: Nat, P](
implicit v: Validate[T, P],
nt: Numeric[T],
tn: ToInt[N]
): Equal[N] ==> P =
Inference(v.isValid(nt.fromInt(tn())),
s"equalValidateInferenceNat(${v.showExpr(nt.fromInt(tn()))})")
Inference(v.isValid(wu.snd), s"equalValidateInference(${v.showExpr(wu.snd)})")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package eu.timepit.refined.internal

import shapeless.{Nat, Witness}
import shapeless.ops.nat.ToInt

/**
* `WitnessAs[A, B]` provides the singleton value of type `A` in `fst`
* and `fst` converted to type `B` in `snd`.
*
* The purpose of this type class is to write numeric type class
* instances that work with both literal singleton types and
* `shapeless.Nat`.
*
* Example: {{{
* scala> import eu.timepit.refined.W
* | import shapeless.nat._5
*
* scala> WitnessAs[W.`5`.T, Int]
* res1: WitnessAs[W.`5`.T, Int] = WitnessAs(5,5)
*
* scala> WitnessAs[_5, Int]
* res2: WitnessAs[_5, Int] = WitnessAs(Succ(),5)
* }}}
*/
final case class WitnessAs[A, B](fst: A, snd: B)

object WitnessAs {
def apply[A, B](implicit ev: WitnessAs[A, B]): WitnessAs[A, B] = ev

implicit def natWitnessAs[B, A <: Nat](
implicit
wa: Witness.Aux[A],
ta: ToInt[A],
nb: Numeric[B]
): WitnessAs[A, B] =
WitnessAs(wa.value, nb.fromInt(ta.apply()))

implicit def singletonWitnessAs[B, A <: B](
implicit wa: Witness.Aux[A]
): WitnessAs[A, B] =
WitnessAs(wa.value, wa.value)
}

0 comments on commit 54f395a

Please sign in to comment.