refined
refined copied to clipboard
`Refined AnyOf[T :: HNil]` is not compatible with `Refined T`

This requires an Inference instances that proofs that P implies AnyOf[L <: HList] if L contains P. It would probably have a signature like this:
implicit def partOfAnyOf[P, L <: HList](implicit shapeless.Selector[L, P]): P ==> AnyOf[L] = ???
I'm new to Shapeless, I'm stuck with the following:
implicit def partOfAnyOf[P, L <: HList](implicit sel: Selector[L, P]): P ==> AnyOf[L] =
Inference(sel(?), "?")
You don't need to do anything with the sel parameter because if the compiler finds an instance Selector[L, P] it already has proven that L contains P.
So
implicit def partOfAnyOf[P, L <: HList](implicit sel: Selector[L, P]): P ==> AnyOf[L] =
Inference(true, "partOfAnyOf")
should be enough to make your initial code compile.
Thanks. Now something goes really wrong:
import eu.timepit.refined.api.Inference.==>
import eu.timepit.refined.api._
import eu.timepit.refined.auto._
import eu.timepit.refined.boolean.AnyOf
import eu.timepit.refined.char._
import shapeless._
import shapeless.ops.hlist.Selector
object Main extends App {
implicit def partOfAnyOf[P, L <: HList](implicit sel: Selector[L, P]): P ==> AnyOf[L] =
Inference(true, "partOfAnyOf")
val digit: Char Refined Digit = '1'
val code: Char Refined AnyOf[Digit :: Letter :: Whitespace :: HNil] = digit
Error:(15, 73) exception during macro expansion:
java.lang.ClassNotFoundException: Main$
at scala.reflect.internal.util.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:64)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at __wrapper$3$8c7b3e7581aa4551ab51a6293a2a3bd5.__wrapper$3$8c7b3e7581aa4551ab51a6293a2a3bd5$.wrapper(<no source file>:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.$anonfun$compile$11(ToolBoxFactory.scala:279)
at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:448)
at scala.reflect.macros.contexts.Evals.eval(Evals.scala:20)
at scala.reflect.macros.contexts.Evals.eval$(Evals.scala:14)
at scala.reflect.macros.contexts.Context.eval(Context.scala:6)
at eu.timepit.refined.macros.MacroUtils.$anonfun$eval$1(MacroUtils.scala:24)
at scala.Option.getOrElse(Option.scala:121)
at eu.timepit.refined.macros.MacroUtils.tryN(MacroUtils.scala:28)
at eu.timepit.refined.macros.MacroUtils.tryN$(MacroUtils.scala:27)
at eu.timepit.refined.macros.InferMacro.tryN(InferMacro.scala:9)
at eu.timepit.refined.macros.MacroUtils.eval(MacroUtils.scala:24)
at eu.timepit.refined.macros.MacroUtils.eval$(MacroUtils.scala:17)
at eu.timepit.refined.macros.InferMacro.eval(InferMacro.scala:9)
at eu.timepit.refined.macros.InferMacro.impl(InferMacro.scala:18)
val code: Char Refined AnyOf[Digit :: Letter :: Whitespace :: HNil] = digit
Error:(15, 73) type mismatch;
found : eu.timepit.refined.api.Refined[Char,eu.timepit.refined.char.Digit]
required: eu.timepit.refined.api.Refined[Char,eu.timepit.refined.boolean.AnyOf[eu.timepit.refined.char.Digit :: eu.timepit.refined.char.Letter :: eu.timepit.refined.char.Whitespace :: shapeless.HNil]]
val code: Char Refined AnyOf[Digit :: Letter :: Whitespace :: HNil] = digit
The good news is that your Inference instance now works as intended (otherwise you wouldn't see that stack trace) but the bad news is that you're hitting the problem described in https://github.com/fthomas/refined/blob/master/modules/docs/macro_pitfalls.md. For testing the instance it should be enough if you put the instance in your main sources and the test code in the test sources.
This does not help:
object Implicits {
implicit def partOfAnyOf[P, L <: HList](implicit sel: Selector[L, P]): P ==> AnyOf[L] =
Inference(isValid = true, "partOfAnyOf")
}
object Main extends App {
import Implicits._
type ProductCode = Char Refined AnyOf[Digit :: Letter :: Whitespace :: HNil]
val digit: Char Refined Digit = '1'
val code: ProductCode = digit
}
Maybe it's a good idea to add this implicit right into Refined itself? I think it's completely general.
I agree, it would be a welcome addition.