From a1859eeedc798de3111ad53fc0b719179e4ac93c Mon Sep 17 00:00:00 2001 From: "Frank S. Thomas" Date: Mon, 13 Jul 2015 21:58:52 +0200 Subject: [PATCH] Add isConstant field --- build.sbt | 2 +- .../scala/eu/timepit/refined/Predicate.scala | 21 ++++++++++++++----- .../scala/eu/timepit/refined/boolean.scala | 16 ++++++++++++-- .../timepit/refined/internal/RefineLit.scala | 11 ++++++---- .../eu/timepit/refined/internal/RefineM.scala | 8 ++++--- 5 files changed, 43 insertions(+), 15 deletions(-) diff --git a/build.sbt b/build.sbt index 8b2cd772d..f93dbe4e2 100644 --- a/build.sbt +++ b/build.sbt @@ -81,7 +81,7 @@ lazy val compileSettings = Seq( ), wartremoverErrors in (Compile, compile) ++= Warts.unsafe diff - Seq(Wart.Any, Wart.AsInstanceOf, Wart.NonUnitStatements, Wart.Throw) + Seq(Wart.Any, Wart.DefaultArguments, Wart.AsInstanceOf, Wart.NonUnitStatements, Wart.Throw) ) lazy val scaladocSettings = Seq( diff --git a/shared/src/main/scala/eu/timepit/refined/Predicate.scala b/shared/src/main/scala/eu/timepit/refined/Predicate.scala index 94a9914bb..99e7d4f07 100644 --- a/shared/src/main/scala/eu/timepit/refined/Predicate.scala +++ b/shared/src/main/scala/eu/timepit/refined/Predicate.scala @@ -22,6 +22,8 @@ trait Predicate[P, T] extends Serializable { self => def validate(t: T): Option[String] = if (isValid(t)) None else Some(s"Predicate failed: ${show(t)}.") + val isConstant: Boolean = false + /** Checks if `t` does not satisfy the predicate `P`. */ final def notValid(t: T): Boolean = !isValid(t) @@ -45,6 +47,7 @@ trait Predicate[P, T] extends Serializable { self => def isValid(u: U): Boolean = self.isValid(f(u)) def show(u: U): String = self.show(f(u)) override def validate(u: U): Option[String] = self.validate(f(u)) + override val isConstant: Boolean = self.isConstant override def accumulateIsValid(u: U): List[Boolean] = self.accumulateIsValid(f(u)) override def accumulateShow(u: U): List[String] = self.accumulateShow(f(u)) } @@ -55,10 +58,18 @@ object Predicate { def apply[P, T](implicit p: Predicate[P, T]): Predicate[P, T] = p /** Constructs a [[Predicate]] from its parameters. */ - def instance[P, T](validateT: T => Boolean, showT: T => String): Predicate[P, T] = + def instance[P, T](isValidF: T => Boolean, showF: T => String, constant: Boolean = false): Predicate[P, T] = new Predicate[P, T] { - def isValid(t: T): Boolean = validateT(t) - def show(t: T): String = showT(t) + def isValid(t: T): Boolean = isValidF(t) + def show(t: T): String = showF(t) + override val isConstant: Boolean = constant + } + + def constant[P, T](isValidV: Boolean, showV: String): Predicate[P, T] = + new Predicate[P, T] { + def isValid(t: T): Boolean = isValidV + def show(t: T): String = showV + override val isConstant: Boolean = true } /** @@ -79,9 +90,9 @@ object Predicate { /** Returns a [[Predicate]] that ignores its inputs and always yields `true`. */ def alwaysValid[P, T]: Predicate[P, T] = - instance(_ => true, _ => "true") + constant(isValidV = true, "true") /** Returns a [[Predicate]] that ignores its inputs and always yields `false`. */ def alwaysInvalid[P, T]: Predicate[P, T] = - instance(_ => false, _ => "false") + constant(isValidV = false, "false") } diff --git a/shared/src/main/scala/eu/timepit/refined/boolean.scala b/shared/src/main/scala/eu/timepit/refined/boolean.scala index 60b854e63..5b7cedcd9 100644 --- a/shared/src/main/scala/eu/timepit/refined/boolean.scala +++ b/shared/src/main/scala/eu/timepit/refined/boolean.scala @@ -52,6 +52,8 @@ private[refined] trait BooleanPredicates { case Some(_) => None case None => Some(s"Predicate ${p.show(t)} did not fail.") } + + override val isConstant: Boolean = p.isConstant } implicit def andPredicate[A, B, T](implicit pa: Predicate[A, T], pb: Predicate[B, T]): Predicate[A And B, T] = @@ -69,6 +71,8 @@ private[refined] trait BooleanPredicates { Some(s"Right predicate of ${show(t)} failed: $sr") case _ => None } + + override val isConstant: Boolean = pa.isConstant && pb.isConstant } implicit def orPredicate[A, B, T](implicit pa: Predicate[A, T], pb: Predicate[B, T]): Predicate[A Or B, T] = @@ -82,6 +86,8 @@ private[refined] trait BooleanPredicates { Some(s"Both predicates of ${show(t)} failed. Left: $sl Right: $sr") case _ => None } + + override val isConstant: Boolean = pa.isConstant && pb.isConstant } implicit def xorPredicate[A, B, T](implicit pa: Predicate[A, T], pb: Predicate[B, T]): Predicate[A Xor B, T] = @@ -97,6 +103,8 @@ private[refined] trait BooleanPredicates { Some(s"Both predicates of ${show(t)} succeeded.") case _ => None } + + override val isConstant: Boolean = pa.isConstant && pb.isConstant } implicit def allOfHNilPredicate[T]: Predicate[AllOf[HNil], T] = @@ -105,7 +113,8 @@ private[refined] trait BooleanPredicates { implicit def allOfHConsPredicate[PH, PT <: HList, T](implicit ph: Predicate[PH, T], pt: Predicate[AllOf[PT], T]): Predicate[AllOf[PH :: PT], T] = Predicate.instance( t => ph.isValid(t) && pt.isValid(t), - t => s"(${ph.show(t)} && ${pt.show(t)})" + t => s"(${ph.show(t)} && ${pt.show(t)})", + ph.isConstant && pt.isConstant ) implicit def anyOfHNilPredicate[T]: Predicate[AnyOf[HNil], T] = @@ -114,7 +123,8 @@ private[refined] trait BooleanPredicates { implicit def anyOfHConsPredicate[PH, PT <: HList, T](implicit ph: Predicate[PH, T], pt: Predicate[AnyOf[PT], T]): Predicate[AnyOf[PH :: PT], T] = Predicate.instance( t => ph.isValid(t) || pt.isValid(t), - t => s"(${ph.show(t)} || ${pt.show(t)})" + t => s"(${ph.show(t)} || ${pt.show(t)})", + ph.isConstant && pt.isConstant ) implicit def oneOfHNilPredicate[T]: Predicate[OneOf[HNil], T] = @@ -125,6 +135,8 @@ private[refined] trait BooleanPredicates { def isValid(t: T): Boolean = accumulateIsValid(t).count(identity) == 1 def show(t: T): String = accumulateShow(t).mkString("oneOf(", ", ", ")") + override val isConstant: Boolean = ph.isConstant && pt.isConstant + override def accumulateIsValid(t: T): List[Boolean] = ph.isValid(t) :: pt.accumulateIsValid(t) diff --git a/shared/src/main/scala/eu/timepit/refined/internal/RefineLit.scala b/shared/src/main/scala/eu/timepit/refined/internal/RefineLit.scala index 256b9d3df..575ceadfa 100644 --- a/shared/src/main/scala/eu/timepit/refined/internal/RefineLit.scala +++ b/shared/src/main/scala/eu/timepit/refined/internal/RefineLit.scala @@ -17,14 +17,17 @@ object RefineLit { def macroImpl[P: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context)(t: c.Expr[T])(p: c.Expr[Predicate[P, T]]): c.Expr[T @@ P] = { import c.universe._ - val litValue: T = t.tree match { + val predicate: Predicate[P, T] = MacroUtils.eval(c)(p) + + val tValue: T = t.tree match { case Literal(Constant(value)) => value.asInstanceOf[T] + case _ if predicate.isConstant => null.asInstanceOf[T] case _ => c.abort(c.enclosingPosition, "refineLit only supports literals") } - val predicate: Predicate[P, T] = MacroUtils.eval(c)(p) - predicate.validate(litValue) match { - case None => c.Expr(q"$t.asInstanceOf[${weakTypeOf[T @@ P]}]") + predicate.validate(tValue) match { + case None => + c.Expr(q"$t.asInstanceOf[${weakTypeOf[T @@ P]}]") case Some(msg) => c.abort(c.enclosingPosition, msg) } } diff --git a/shared/src/main/scala/eu/timepit/refined/internal/RefineM.scala b/shared/src/main/scala/eu/timepit/refined/internal/RefineM.scala index c26c28e5e..6b123a8bf 100644 --- a/shared/src/main/scala/eu/timepit/refined/internal/RefineM.scala +++ b/shared/src/main/scala/eu/timepit/refined/internal/RefineM.scala @@ -15,13 +15,15 @@ object RefineM { def macroImpl[P: c.WeakTypeTag, T: c.WeakTypeTag](c: blackbox.Context)(t: c.Expr[T])(p: c.Expr[Predicate[P, T]]): c.Expr[Refined[T, P]] = { import c.universe._ - val litValue: T = t.tree match { + val predicate: Predicate[P, T] = MacroUtils.eval(c)(p) + + val tValue: T = t.tree match { case Literal(Constant(value)) => value.asInstanceOf[T] + case _ if predicate.isConstant => null.asInstanceOf[T] case _ => c.abort(c.enclosingPosition, "refineM only supports literals") } - val predicate: Predicate[P, T] = MacroUtils.eval(c)(p) - predicate.validate(litValue) match { + predicate.validate(tValue) match { case None => c.Expr(q"_root_.eu.timepit.refined.Refined[${weakTypeOf[T]}, ${weakTypeOf[P]}]($t)") case Some(msg) => c.abort(c.enclosingPosition, msg)