diff --git a/.travis.yml b/.travis.yml index 0e808628d..e13e3c8b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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: @@ -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 diff --git a/build.sbt b/build.sbt index 3404b6938..9db968874 100644 --- a/build.sbt +++ b/build.sbt @@ -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 { @@ -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") - ) + ) } ) @@ -549,7 +481,7 @@ addCommandsAlias("testJS", allSubprojectsJS.map(_ + "/test")) addCommandsAlias("testJVM", allSubprojectsJVM.map(_ + "/test")) addCommandsAlias( - "validate", + "validateJVM", Seq( "clean", "scalafmtCheck", @@ -558,7 +490,6 @@ addCommandsAlias( "scalastyle", "test:scalastyle", "mimaReportBinaryIssues", - "testJS", "coverage", "testJVM", "coverageReport", @@ -569,3 +500,10 @@ addCommandsAlias( "packageSrc" ) ) + +addCommandsAlias( + "validateJS", + Seq( + "testJS" + ) +) diff --git a/latestVersion.sbt b/latestVersion.sbt index 151b08868..9efc524c7 100644 --- a/latestVersion.sbt +++ b/latestVersion.sbt @@ -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", diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/api/Max.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/api/Max.scala index a951adbc4..fd43c02bf 100644 --- a/modules/core/shared/src/main/scala/eu/timepit/refined/api/Max.scala +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/api/Max.scala @@ -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 @@ -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], diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/api/Min.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/api/Min.scala index fea5f4b21..7909196c2 100644 --- a/modules/core/shared/src/main/scala/eu/timepit/refined/api/Min.scala +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/api/Min.scala @@ -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 @@ -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], diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/collection.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/collection.scala index ee86bdf9e..6bf831488 100644 --- a/modules/core/shared/src/main/scala/eu/timepit/refined/collection.scala +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/collection.scala @@ -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 { @@ -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] diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/generic.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/generic.scala index 598e39e2e..3664615c9 100644 --- a/modules/core/shared/src/main/scala/eu/timepit/refined/generic.scala +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/generic.scala @@ -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. */ @@ -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 { @@ -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)})") } diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/internal/WitnessAs.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/internal/WitnessAs.scala new file mode 100644 index 000000000..4133297d3 --- /dev/null +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/internal/WitnessAs.scala @@ -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) +} diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/numeric.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/numeric.scala index dd25820b6..3f1467139 100644 --- a/modules/core/shared/src/main/scala/eu/timepit/refined/numeric.scala +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/numeric.scala @@ -3,8 +3,9 @@ package eu.timepit.refined import eu.timepit.refined.api.{Inference, Validate} import eu.timepit.refined.api.Inference.==> import eu.timepit.refined.boolean.{And, Not} +import eu.timepit.refined.internal.WitnessAs import eu.timepit.refined.numeric._ -import shapeless.{Nat, Witness} +import shapeless.Nat import shapeless.nat.{_0, _2} import shapeless.ops.nat.ToInt @@ -86,116 +87,70 @@ object numeric extends NumericInference { } object Less { - implicit def lessValidateWit[T, N <: T]( - implicit wn: Witness.Aux[N], + implicit def lessValidate[T, N]( + implicit + wn: WitnessAs[N, T], nt: Numeric[T] ): Validate.Plain[T, Less[N]] = - Validate.fromPredicate(t => nt.lt(t, wn.value), t => s"($t < ${wn.value})", Less(wn.value)) - - implicit def lessValidateNat[N <: Nat, T]( - implicit tn: ToInt[N], - wn: Witness.Aux[N], - nt: Numeric[T] - ): Validate.Plain[T, Less[N]] = - Validate.fromPredicate(t => nt.toDouble(t) < tn(), t => s"($t < ${tn()})", Less(wn.value)) + Validate.fromPredicate(t => nt.lt(t, wn.snd), t => s"($t < ${wn.snd})", Less(wn.fst)) } object Greater { - implicit def greaterValidateWit[T, N <: T]( - implicit wn: Witness.Aux[N], + implicit def greaterValidate[T, N]( + implicit + wn: WitnessAs[N, T], nt: Numeric[T] ): Validate.Plain[T, Greater[N]] = - Validate.fromPredicate(t => nt.gt(t, wn.value), t => s"($t > ${wn.value})", Greater(wn.value)) - - implicit def greaterValidateNat[N <: Nat, T]( - implicit tn: ToInt[N], - wn: Witness.Aux[N], - nt: Numeric[T] - ): Validate.Plain[T, Greater[N]] = - Validate.fromPredicate(t => nt.toDouble(t) > tn(), t => s"($t > ${tn()})", Greater(wn.value)) + Validate.fromPredicate(t => nt.gt(t, wn.snd), t => s"($t > ${wn.snd})", Greater(wn.fst)) } object Modulo { - implicit def moduloValidateWitIntegral[T, N <: T, O <: T]( - implicit wn: Witness.Aux[N], - wo: Witness.Aux[O], - it: Integral[T] - ): Validate.Plain[T, Modulo[N, O]] = - Validate.fromPredicate( - t => it.rem(t, wn.value) == wo.value, - t => s"($t % ${wn.value} == ${wo.value})", - Modulo(wn.value, wo.value) - ) - - implicit def moduloValidateNatIntegral[N <: Nat, O <: Nat, T]( - implicit tn: ToInt[N], - to: ToInt[O], - wn: Witness.Aux[N], - wo: Witness.Aux[O], - it: Integral[T] - ): Validate.Plain[T, Modulo[N, O]] = - Validate.fromPredicate( - t => it.rem(t, it.fromInt(tn())) == it.fromInt(to()), - t => s"($t % ${tn()} == ${to()})", - Modulo(wn.value, wo.value) - ) - - implicit def moduloValidateWitNatIntegral[T, N <: T, O <: Nat]( - implicit wn: Witness.Aux[N], - to: ToInt[O], - wo: Witness.Aux[O], + implicit def moduloValidate[T, N, O]( + implicit + wn: WitnessAs[N, T], + wo: WitnessAs[O, T], it: Integral[T] ): Validate.Plain[T, Modulo[N, O]] = Validate.fromPredicate( - t => it.rem(t, wn.value) == it.fromInt(to()), - t => s"($t % ${wn.value} == ${to()})", - Modulo(wn.value, wo.value) + t => it.rem(t, wn.snd) == wo.snd, + t => s"($t % ${wn.snd} == ${wo.snd})", + Modulo(wn.fst, wo.fst) ) } } private[refined] trait NumericInference { - implicit def lessInferenceWit[C, A <: C, B <: C]( - implicit wa: Witness.Aux[A], - wb: Witness.Aux[B], + implicit def lessInference[C, A, B]( + implicit + wa: WitnessAs[A, C], + wb: WitnessAs[B, C], nc: Numeric[C] ): Less[A] ==> Less[B] = - Inference(nc.lt(wa.value, wb.value), s"lessInferenceWit(${wa.value}, ${wb.value})") - - implicit def greaterInferenceWit[C, A <: C, B <: C]( - implicit wa: Witness.Aux[A], - wb: Witness.Aux[B], - nc: Numeric[C] - ): Greater[A] ==> Greater[B] = - Inference(nc.gt(wa.value, wb.value), s"greaterInferenceWit(${wa.value}, ${wb.value})") + Inference(nc.lt(wa.snd, wb.snd), s"lessInference(${wa.snd}, ${wb.snd})") implicit def lessInferenceNat[A <: Nat, B <: Nat]( - implicit ta: ToInt[A], + implicit + ta: ToInt[A], tb: ToInt[B] ): Less[A] ==> Less[B] = Inference(ta() < tb(), s"lessInferenceNat(${ta()}, ${tb()})") + implicit def greaterInference[C, A, B]( + implicit + wa: WitnessAs[A, C], + wb: WitnessAs[B, C], + nc: Numeric[C] + ): Greater[A] ==> Greater[B] = + Inference(nc.gt(wa.snd, wb.snd), s"greaterInference(${wa.snd}, ${wb.snd})") + implicit def greaterInferenceNat[A <: Nat, B <: Nat]( - implicit ta: ToInt[A], + implicit + ta: ToInt[A], tb: ToInt[B] ): Greater[A] ==> Greater[B] = Inference(ta() > tb(), s"greaterInferenceNat(${ta()}, ${tb()})") - implicit def lessInferenceWitNat[C, A <: C, B <: Nat]( - implicit wa: Witness.Aux[A], - tb: ToInt[B], - nc: Numeric[C] - ): Less[A] ==> Less[B] = - Inference(nc.lt(wa.value, nc.fromInt(tb())), s"lessInferenceWitNat(${wa.value}, ${tb()})") - - implicit def greaterInferenceWitNat[C, A <: C, B <: Nat]( - implicit wa: Witness.Aux[A], - tb: ToInt[B], - nc: Numeric[C] - ): Greater[A] ==> Greater[B] = - Inference(nc.gt(wa.value, nc.fromInt(tb())), s"greaterInferenceWitNat(${wa.value}, ${tb()})") - implicit def greaterEqualInference[A]: Greater[A] ==> GreaterEqual[A] = Inference(true, "greaterEqualInference") diff --git a/modules/core/shared/src/main/scala/eu/timepit/refined/types/string.scala b/modules/core/shared/src/main/scala/eu/timepit/refined/types/string.scala index 508476642..41d9fb6f9 100644 --- a/modules/core/shared/src/main/scala/eu/timepit/refined/types/string.scala +++ b/modules/core/shared/src/main/scala/eu/timepit/refined/types/string.scala @@ -3,8 +3,8 @@ package eu.timepit.refined.types import eu.timepit.refined.W import eu.timepit.refined.api.{Refined, RefinedType, RefinedTypeOps} import eu.timepit.refined.collection.{MaxSize, NonEmpty} +import eu.timepit.refined.internal.WitnessAs import eu.timepit.refined.string.MatchesRegex -import shapeless.Witness /** Module for `String` refined types. */ object string { @@ -13,15 +13,15 @@ object string { type FiniteString[N] = String Refined MaxSize[N] object FiniteString { - class FiniteStringOps[N <: Int]( + class FiniteStringOps[N]( implicit rt: RefinedType.AuxT[FiniteString[N], String], - wn: Witness.Aux[N] + wn: WitnessAs[N, Int] ) extends RefinedTypeOps[FiniteString[N], String] { /** The maximum length of a `FiniteString[N]`. */ - final val maxLength: N = - wn.value + final val maxLength: Int = + wn.snd /** * Creates a `FiniteString[N]` from `t` by truncating it @@ -32,10 +32,10 @@ object string { } /** Creates a "companion object" for `FiniteString[N]` with a fixed `N`. */ - def apply[N <: Int]( + def apply[N]( implicit rt: RefinedType.AuxT[FiniteString[N], String], - wn: Witness.Aux[N] + wn: WitnessAs[N, Int] ): FiniteStringOps[N] = new FiniteStringOps[N] } diff --git a/modules/core/shared/src/test/scala/eu/timepit/refined/NumericValidateSpec.scala b/modules/core/shared/src/test/scala/eu/timepit/refined/NumericValidateSpec.scala index a71d1b64e..1fd7cac94 100644 --- a/modules/core/shared/src/test/scala/eu/timepit/refined/NumericValidateSpec.scala +++ b/modules/core/shared/src/test/scala/eu/timepit/refined/NumericValidateSpec.scala @@ -149,7 +149,8 @@ class NumericValidateSpec extends Properties("NumericValidate") { } property("Interval.Open.showExpr") = secure { - showExpr[Interval.Open[_0, _1]](0.5) ?= "((0.5 > 0) && (0.5 < 1))" + val s = showExpr[Interval.Open[_0, _1]](0.5) + (s ?= "((0.5 > 0) && (0.5 < 1))") || (s ?= "((0.5 > 0.0) && (0.5 < 1.0))") } property("Interval.OpenClosed.isValid") = forAll { (d: Double) => @@ -157,7 +158,8 @@ class NumericValidateSpec extends Properties("NumericValidate") { } property("Interval.OpenClosed.showExpr") = secure { - showExpr[Interval.OpenClosed[_0, _1]](0.5) ?= "((0.5 > 0) && !(0.5 > 1))" + val s = showExpr[Interval.OpenClosed[_0, _1]](0.5) + (s ?= "((0.5 > 0) && !(0.5 > 1))") || (s ?= "((0.5 > 0.0) && !(0.5 > 1.0))") } property("Interval.ClosedOpen.isValid") = forAll { (d: Double) => @@ -165,7 +167,8 @@ class NumericValidateSpec extends Properties("NumericValidate") { } property("Interval.ClosedOpen.showExpr") = secure { - showExpr[Interval.ClosedOpen[_0, _1]](0.5) ?= "(!(0.5 < 0) && (0.5 < 1))" + val s = showExpr[Interval.ClosedOpen[_0, _1]](0.5) + (s ?= "(!(0.5 < 0) && (0.5 < 1))") || (s ?= "(!(0.5 < 0.0) && (0.5 < 1.0))") } property("Interval.Closed.isValid") = forAll { (d: Double) => @@ -173,6 +176,7 @@ class NumericValidateSpec extends Properties("NumericValidate") { } property("Interval.Closed.showExpr") = secure { - showExpr[Interval.Closed[_0, _1]](0.5) ?= "(!(0.5 < 0) && !(0.5 > 1))" + val s = showExpr[Interval.Closed[_0, _1]](0.5) + (s ?= "(!(0.5 < 0) && !(0.5 > 1))") || (s ?= "(!(0.5 < 0.0) && !(0.5 > 1.0))") } } diff --git a/modules/core/shared/src/test/scala/eu/timepit/refined/types/StringTypesSpec.scala b/modules/core/shared/src/test/scala/eu/timepit/refined/types/StringTypesSpec.scala index d8754b682..101c04522 100644 --- a/modules/core/shared/src/test/scala/eu/timepit/refined/types/StringTypesSpec.scala +++ b/modules/core/shared/src/test/scala/eu/timepit/refined/types/StringTypesSpec.scala @@ -26,7 +26,7 @@ class StringTypesSpec extends Properties("StringTypes") { property("""FString3.from("abcd")""") = secure { val str = "abcd" FString3.from(str) ?= Left( - "Predicate taking size(abcd) = 4 failed: Predicate (4 > 3) did not fail.") + "Predicate taking size(abcd) = 4 failed: Right predicate of (!(4 < 0) && !(4 > 3)) failed: Predicate (4 > 3) did not fail.") } property("""FString3.truncate(str)""") = forAll { (str: String) => diff --git a/modules/scalacheck/shared/src/main/scala/eu/timepit/refined/scalacheck/numeric.scala b/modules/scalacheck/shared/src/main/scala/eu/timepit/refined/scalacheck/numeric.scala index 9a04e71ca..6d9157e60 100644 --- a/modules/scalacheck/shared/src/main/scala/eu/timepit/refined/scalacheck/numeric.scala +++ b/modules/scalacheck/shared/src/main/scala/eu/timepit/refined/scalacheck/numeric.scala @@ -1,12 +1,10 @@ package eu.timepit.refined.scalacheck import eu.timepit.refined.api.{Max, Min, RefType, Validate} -import eu.timepit.refined.internal.Adjacent +import eu.timepit.refined.internal.{Adjacent, WitnessAs} import eu.timepit.refined.numeric._ import org.scalacheck.{Arbitrary, Gen} import org.scalacheck.Gen.Choose -import shapeless.{Nat, Witness} -import shapeless.ops.nat.ToInt /** * Module that provides `Arbitrary` instances and generators for @@ -31,92 +29,63 @@ trait NumericInstances { /// - implicit def lessArbitraryWit[F[_, _]: RefType, T: Numeric: Choose: Adjacent, N <: T]( - implicit min: Min[T], - wn: Witness.Aux[N] + implicit def lessArbitrary[F[_, _]: RefType, T: Numeric: Choose: Adjacent, N]( + implicit + min: Min[T], + wn: WitnessAs[N, T] ): Arbitrary[F[T, Less[N]]] = - rangeClosedOpenArbitrary(min.min, wn.value) + rangeClosedOpenArbitrary(min.min, wn.snd) - implicit def lessArbitraryNat[F[_, _]: RefType, T: Choose: Adjacent, N <: Nat]( - implicit min: Min[T], - nt: Numeric[T], - tn: ToInt[N] - ): Arbitrary[F[T, Less[N]]] = - rangeClosedOpenArbitrary(min.min, nt.fromInt(tn())) - - implicit def lessEqualArbitraryWit[F[_, _]: RefType, T: Numeric: Choose, N <: T]( - implicit min: Min[T], - wn: Witness.Aux[N] + implicit def lessEqualArbitrary[F[_, _]: RefType, T: Numeric: Choose, N]( + implicit + min: Min[T], + wn: WitnessAs[N, T] ): Arbitrary[F[T, LessEqual[N]]] = - rangeClosedArbitrary(min.min, wn.value) - - implicit def lessEqualArbitraryNat[F[_, _]: RefType, T: Choose, N <: Nat]( - implicit min: Min[T], - nt: Numeric[T], - tn: ToInt[N] - ): Arbitrary[F[T, LessEqual[N]]] = - rangeClosedArbitrary(min.min, nt.fromInt(tn())) - - implicit def greaterArbitraryWit[F[_, _]: RefType, T: Numeric: Choose: Adjacent, N <: T]( - implicit max: Max[T], - wn: Witness.Aux[N] - ): Arbitrary[F[T, Greater[N]]] = - rangeOpenClosedArbitrary(wn.value, max.max) + rangeClosedArbitrary(min.min, wn.snd) - implicit def greaterArbitraryNat[F[_, _]: RefType, T: Choose: Adjacent, N <: Nat]( - implicit max: Max[T], - nt: Numeric[T], - tn: ToInt[N] + implicit def greaterArbitrary[F[_, _]: RefType, T: Numeric: Choose: Adjacent, N]( + implicit + max: Max[T], + wn: WitnessAs[N, T] ): Arbitrary[F[T, Greater[N]]] = - rangeOpenClosedArbitrary(nt.fromInt(tn()), max.max) - - implicit def greaterEqualArbitraryWit[F[_, _]: RefType, T: Numeric: Choose, N <: T]( - implicit max: Max[T], - wn: Witness.Aux[N] - ): Arbitrary[F[T, GreaterEqual[N]]] = - rangeClosedArbitrary(wn.value, max.max) + rangeOpenClosedArbitrary(wn.snd, max.max) - implicit def greaterEqualArbitraryNat[F[_, _]: RefType, T: Choose, N <: Nat]( - implicit max: Max[T], - nt: Numeric[T], - tn: ToInt[N] + implicit def greaterEqualArbitrary[F[_, _]: RefType, T: Numeric: Choose, N]( + implicit + max: Max[T], + wn: WitnessAs[N, T] ): Arbitrary[F[T, GreaterEqual[N]]] = - rangeClosedArbitrary(nt.fromInt(tn()), max.max) + rangeClosedArbitrary(wn.snd, max.max) /// - implicit def intervalOpenArbitrary[F[_, _]: RefType, - T: Numeric: Choose: Adjacent, - L <: T, - H <: T]( - implicit wl: Witness.Aux[L], - wh: Witness.Aux[H] + implicit def intervalOpenArbitrary[F[_, _]: RefType, T: Numeric: Choose: Adjacent, L, H]( + implicit + wl: WitnessAs[L, T], + wh: WitnessAs[H, T] ): Arbitrary[F[T, Interval.Open[L, H]]] = - rangeOpenArbitrary(wl.value, wh.value) - - implicit def intervalOpenClosedArbitrary[F[_, _]: RefType, - T: Numeric: Choose: Adjacent, - L <: T, - H <: T]( - implicit wl: Witness.Aux[L], - wh: Witness.Aux[H] + rangeOpenArbitrary(wl.snd, wh.snd) + + implicit def intervalOpenClosedArbitrary[F[_, _]: RefType, T: Numeric: Choose: Adjacent, L, H]( + implicit + wl: WitnessAs[L, T], + wh: WitnessAs[H, T] ): Arbitrary[F[T, Interval.OpenClosed[L, H]]] = - rangeOpenClosedArbitrary(wl.value, wh.value) - - implicit def intervalClosedOpenArbitrary[F[_, _]: RefType, - T: Numeric: Choose: Adjacent, - L <: T, - H <: T]( - implicit wl: Witness.Aux[L], - wh: Witness.Aux[H] + rangeOpenClosedArbitrary(wl.snd, wh.snd) + + implicit def intervalClosedOpenArbitrary[F[_, _]: RefType, T: Numeric: Choose: Adjacent, L, H]( + implicit + wl: WitnessAs[L, T], + wh: WitnessAs[H, T] ): Arbitrary[F[T, Interval.ClosedOpen[L, H]]] = - rangeClosedOpenArbitrary(wl.value, wh.value) + rangeClosedOpenArbitrary(wl.snd, wh.snd) - implicit def intervalClosedArbitrary[F[_, _]: RefType, T: Numeric: Choose, L <: T, H <: T]( - implicit wl: Witness.Aux[L], - wh: Witness.Aux[H] + implicit def intervalClosedArbitrary[F[_, _]: RefType, T: Numeric: Choose, L, H]( + implicit + wl: WitnessAs[L, T], + wh: WitnessAs[H, T] ): Arbitrary[F[T, Interval.Closed[L, H]]] = - rangeClosedArbitrary(wl.value, wh.value) + rangeClosedArbitrary(wl.snd, wh.snd) /// The following functions are private because it is not guaranteed /// that they produce valid values according to the predicate `P`. diff --git a/modules/scalacheck/shared/src/test/scala/eu/timepit/refined/scalacheck/StringArbitrarySpec.scala b/modules/scalacheck/shared/src/test/scala/eu/timepit/refined/scalacheck/StringArbitrarySpec.scala index 3a7005b50..bdfa7731e 100644 --- a/modules/scalacheck/shared/src/test/scala/eu/timepit/refined/scalacheck/StringArbitrarySpec.scala +++ b/modules/scalacheck/shared/src/test/scala/eu/timepit/refined/scalacheck/StringArbitrarySpec.scala @@ -10,6 +10,7 @@ import eu.timepit.refined.scalacheck.string._ import eu.timepit.refined.string._ import eu.timepit.refined.types.string.{FiniteString, NonEmptyString} import org.scalacheck.Properties +import shapeless.nat._5 class StringArbitrarySpec extends Properties("StringArbitrary") { @@ -23,5 +24,7 @@ class StringArbitrarySpec extends Properties("StringArbitrary") { property("FiniteString[10]") = checkArbitraryRefinedType[FiniteString[W.`10`.T]] + property("FiniteString[_5]") = checkArbitraryRefinedType[FiniteString[_5]] + property("Size[Equal[8]]") = checkArbitraryRefinedType[String Refined Size[Equal[W.`8`.T]]] } diff --git a/notes/0.9.0.markdown b/notes/0.9.0.markdown index 29cfa5321..5149e0dc0 100644 --- a/notes/0.9.0.markdown +++ b/notes/0.9.0.markdown @@ -37,6 +37,11 @@ [scala-dev/#446][scala-dev/#446]. ([#438][#438]) * Update documentation to solve "exception during macro expansion" errors. ([#451][#451] by [@umbreak][@umbreak]) +* Change the definition of `MaxSize[N]` from `Size[LessEqual[N]]` to + `Size[Interval.Closed[_0, N]]` and introduce the `WitnessAs` type class + which unifies numeric type class instances that were split to work with + literal singleton types and `shapeless.Nat`. + ([#473][#473], [#483][#483]) ### Deprecations and removals @@ -87,10 +92,12 @@ [#467]: https://github.com/fthomas/refined/pull/467 [#468]: https://github.com/fthomas/refined/pull/468 [#471]: https://github.com/fthomas/refined/pull/471 +[#473]: https://github.com/fthomas/refined/issues/473 [#475]: https://github.com/fthomas/refined/pull/475 [#478]: https://github.com/fthomas/refined/pull/478 [#479]: https://github.com/fthomas/refined/pull/479 [#482]: https://github.com/fthomas/refined/pull/482 +[#483]: https://github.com/fthomas/refined/pull/483 [scala-dev/#446]: https://github.com/scala/scala-dev/issues/446 [@densh]: https://github.com/densh