Skip to content

Commit 1195edf

Browse files
committed
Fix fthomas#755 - expose Implies[P,C] variation of Inference[P,C]
1 parent b7b52a2 commit 1195edf

File tree

4 files changed

+42
-2
lines changed

4 files changed

+42
-2
lines changed

modules/core/shared/src/main/scala/eu/timepit/refined/api/Inference.scala

+17
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,20 @@ object Inference {
3333
): Inference[P, C] =
3434
Inference(i1.isValid && i2.isValid, show.format(i1.show, i2.show))
3535
}
36+
37+
/**
38+
* Similar to `Inference[P, C]` but will not implicitly manifest if `C` cannot be
39+
* inferred from `P`.
40+
*
41+
* It is intended to be used with chained implicit definitions that require proof that `P ==> C`
42+
*/
43+
case class Implies[P, C](show: String)
44+
45+
object Implies {
46+
import scala.reflect.macros.blackbox
47+
import Inference.==>
48+
49+
def manifest[A: c.WeakTypeTag, B: c.WeakTypeTag](c: blackbox.Context)(ir: c.Expr[A ==> B]): c.Expr[Implies[A, B]] = {
50+
c.universe.reify(Implies[A, B]((ir.splice).show))
51+
}
52+
}

modules/core/shared/src/main/scala/eu/timepit/refined/auto.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package eu.timepit.refined
22

3-
import eu.timepit.refined.api.{Refined, RefType, Validate}
3+
import eu.timepit.refined.api.{Implies, Refined, RefType, Validate}
44
import eu.timepit.refined.api.Inference.==>
55
import eu.timepit.refined.macros.{InferMacro, RefineMacro}
66
import shapeless.tag.@@
@@ -32,6 +32,10 @@ object auto {
3232
ir: A ==> B
3333
): F[T, B] = macro InferMacro.impl[F, T, A, B]
3434

35+
implicit def autoImply[A, B](implicit
36+
ir: A ==> B
37+
): Implies[A, B] = macro InferMacro.implies[A, B]
38+
3539
/**
3640
* Implicitly unwraps the `T` from a value of type `F[T, P]` using the
3741
* `[[api.RefType]]` instance of `F`. This allows a `F[T, P]` to be

modules/core/shared/src/main/scala/eu/timepit/refined/macros/InferMacro.scala

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package eu.timepit.refined.macros
22

3+
import eu.timepit.refined.api.Implies
34
import eu.timepit.refined.api.Inference.==>
45
import eu.timepit.refined.api.RefType
56
import eu.timepit.refined.internal.Resources
@@ -20,4 +21,12 @@ class InferMacro(val c: blackbox.Context) extends MacroUtils {
2021

2122
refTypeInstance(rt).unsafeRewrapM(c)(ta)
2223
}
24+
25+
def implies[A: c.WeakTypeTag, B: c.WeakTypeTag](ir: c.Expr[A ==> B]): c.Expr[Implies[A, B]] = {
26+
val inference = eval(ir)
27+
if (inference.notValid) {
28+
abort(Resources.invalidInference(weakTypeOf[A].toString, weakTypeOf[B].toString))
29+
}
30+
Implies.manifest(c)(ir)
31+
}
2332
}

modules/core/shared/src/test/scala/eu/timepit/refined/AutoSpec.scala

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package eu.timepit.refined
22

3-
import eu.timepit.refined.api.Refined
3+
import eu.timepit.refined.api.{Implies, Refined}
44
import eu.timepit.refined.auto._
55
import eu.timepit.refined.char.{Digit, Letter}
66
import eu.timepit.refined.generic._
7+
import eu.timepit.refined.numeric.{Greater}
78
import eu.timepit.refined.types.numeric.PosInt
89
import org.scalacheck.Prop._
910
import org.scalacheck.Properties
@@ -22,6 +23,15 @@ class AutoSpec extends Properties("auto") {
2223
a == b
2324
}
2425

26+
property("autoImply") = secure {
27+
val t = implicitly[Implies[Greater[W.`1`.T], Greater[W.`0`.T]]]
28+
illTyped(
29+
"implicitly[Implies[Greater[W.`-1`.T], Greater[W.`0`.T]]]",
30+
"""type mismatch \(invalid inference\):\s*eu.timepit.refined.numeric.Greater\[Int\(-1\)\] does not imply\s*eu.timepit.refined.numeric.Greater\[Int\(0\)\]"""
31+
)
32+
t.show == "greaterInference(1, 0)"
33+
}
34+
2535
property("autoUnwrap: PosInt: Int") = secure {
2636
val a: PosInt = PosInt.unsafeFrom(1)
2737
val b: Int = a

0 commit comments

Comments
 (0)