How do I get around with equivalence of two path-dependent types that I know are the same but the compiler does not?
Using Scala 2.10.0 M7 I am trying to convert an AST from one universe to another.
case class MacroBridge(context: Context) {
def toMacroTree(tree: treehugger.forest.Tree): context.universe.Tree = ???
def fromMacroTree(tree: context.universe.Tree): treehugger.forest.Tree = ???
}
Within a macro implementation, I can use it as:
val bridge = treehugger.MacroBridge(c)
def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
However, this results to a compiler error:
[error] /scalamacros-getting-started/library/Macros.scala:21: type mismatch;
[error] found : c.universe.Tree
[error] required: bridge.context.universe.Tree
[error] possible cause: missing arguments for method or constructor
[error] def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
In the above code c is clearly the same value as bridge.context, but maybe because it's a value type checker cannot check it. Putting generalized type constraint did not help:
def fromMacroTree[A](tree: A)(implicit ev: A =:= context.universe.Tree): Tree =
In the macro this still resulted to an error:
[error] /scalamacros-getting-started/library/Macros.scala:21: Cannot prove that c.universe.Tree =:= bridge.context.universe.Tree.
[error] def fromMacroTree(tree: c.universe.Tree): Tree = bridge.fromMacroTree(tree)
I need the access to context.universe so I can get to other dependent types like TermName. Is there a better work around besides casting?:
def fromMacroTree(tree: c.universe.Tree): Tree =
bridge.fromMacroTree(tree.asInstanceOf[bridge.context.universe.Tree])
I could the following make to work:
case class MacroBridge[C <: Context](context: C) {
def fromMacroTree(tree: context.universe.Tree): context.universe.Tree = ???
}
trait MB {
def meth(c: Context) {
val bridge = MacroBridge[c.type](c)
def fromMacroTree(tree: c.universe.Tree): c.universe.Tree =
bridge.fromMacroTree(tree)
}
}
I had nearly the same problem some time ago.
Related
Any idea why this fails to find the implicit view?
// Making B invariant fixes it.
sealed trait ImplicitlyStable[A, +B]
object ImplicitlyStable {
implicit def convertibleToStable[A, B](implicit
aToB: A => B,
// Removing bToB fixes it.
bToB: ImplicitlyStable[B, B]
): ImplicitlyStable[A, B] = ???
}
object Test {
def testConvertibleToStable[A, B](implicit
aToB: A => B,
bToB: ImplicitlyStable[B, B]
): ImplicitlyStable[A, B] =
implicitly[ImplicitlyStable[A, B]]
}
It fails with:
[error] !I e: ImplicitlyStable[A, B]
[error] ImplicitlyStable.convertibleToStable invalid because
[error] !I aToB: A => B
[error] No implicit view available from A => B.
[error]
[error] implicitly[ImplicitlyStable[A, B]]
[error] ^
[error] one error found
It says No implicit view available from A => B which is clearly not true as there is an implicit parameter of that type.
Is this one of those situations where it is inferring Nothing for B? If so, why would it do that?
If I add:
private def unexpected: Nothing = sys.error("Unexpected invocation")
implicit def nothingStableAmbig1[A]: ImplicitlyStable[Nothing, A] = unexpected
implicit def nothingStableAmbig2[A]: ImplicitlyStable[Nothing, A] = unexpected
implicit def nothingStableAmbig3[A]: ImplicitlyStable[A, Nothing] = unexpected
implicit def nothingStableAmbig4[A]: ImplicitlyStable[A, Nothing] = unexpected
Then it fails with:
[error] ambiguous implicit values:
[error] both method nothingStableAmbig3 in object ImplicitlyStable of type [A]ImplicitlyStable[A,Nothing]
[error] and method nothingStableAmbig4 in object ImplicitlyStable of type [A]ImplicitlyStable[A,Nothing]
[error] match expected type ImplicitlyStable[A,B]
[error] implicitly[ImplicitlyStable[A, B]]
[error] ^
So sure enough, it is inferring Nothing, but why?
It seems like this might be a bug in Scala 2 that has been fixed in Scala 3.
I raised an issue for it.
I'm not sure if there is any more reasoning behind why it is inferring Nothing. If anyone knows then that would be great.
Suppose I have trait that represents something like a polymorphic function, e.g.:
trait Func[A[X, Y]] {
def apply[X, Y](a: A[X, Y]): A[X, Y]
}
Now I want to use my trait as a non-polymorphic function by passing type lambda as argument:
type single[T] = { type t[X, Y] = T }
val aInstance: Func[single[String]#t] =
new Func[single[String]#t] {
def apply[X, Y](a: String): String = ???
}
Now I have method test which does some useful things with func, e.g.
def test[A[X, Y]](f: Func[A]): Unit = ???
And I want to invoke test with aInstance without specifying type parameters by hand:
test(aInstance)
Unfortunately, this code does not compile (but test[single[String]#t](aInstance) does) with error messages:
[error] /test.scala:16:3: no type parameters for method test: (f: Func[A])Unit exist so that it can be applied to arguments (Func[[X, Y]String])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : Func[[X, Y]String]
[error] required: Func[?A]
[error] test(aInstance)
[error] ^
[error] /test.scala:16:8: type mismatch;
[error] found : Func[[X, Y]String]
[error] required: Func[A]
[error] test(aInstance)
[error] ^
[error] two errors found
My question is: how can I modify these declarations to allow compiler to infer all required types automatically?
To those wondering why I declared Func as having [X, Y] but never used them in actual code there is a more real-world and less abstract example:
object GenericTest {
trait Item { def name: String }
class ItemA extends Item { def name: String = "a" }
class ItemB extends Item { def name: String = "b" }
trait MapFn[-A[X <: Item], +B[X <: Item]] {
def apply[X <: Item](data: A[X]): B[X]
}
case class ItemsCollection[C[A <: Item]](a: C[ItemA], b: C[ItemB]) {
def map[D[A <: Item]](f: MapFn[C, D]): ItemsCollection[D] =
ItemsCollection(f(a), f(b))
}
// sometimes we want to store sequences...
val itemSeq = ItemsCollection[Seq](Seq(new ItemA), Seq(new ItemB))
// or transform them:
val itemSet = itemSeq.map(new MapFn[Seq, Set] {
override def apply[X <: Item](data: Seq[X]): Set[X] = data.toSet
})
// but one day we wanted to store just objects without any item-specific types... e.g. names:
type single[X] = { type t[A] = X }
val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
override def apply[X <: Item](data: Seq[X]): String = data.head.name
})
/*
[error] test.scala:28:27: no type parameters for method map: (f: MapFn[Seq,D])ItemsCollection[D] exist so that it can be applied to arguments (MapFn[Seq,[A]String])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : MapFn[Seq,[A]String]
[error] required: MapFn[Seq,?D]
[error] val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
[error] ^
[error] test.scala:28:31: type mismatch;
[error] found : MapFn[Seq,[A]String]
[error] required: MapFn[Seq,D]
[error] val itemNames = itemSeq.map(new MapFn[Seq, single[String]#t] {
[error] ^
[error] two errors found
*/
}
Referring to your GenericTest, there is no way to get Scala to infer that shape, because of this closed-but-unfixed bug.
One thing you can do is try to adapt the technique of Unapply, using implicit resolution to determine the likely candidate for D. This will probably entail defining your own typeclass and instances, not using the ones Scalaz supplies, and possibly changing how MapFn is declared to be more suitable for this pattern. Make sure that the instance that gives you single has the lowest priority, as it can always be used (every T is an F[T] if F = Id).
If you control the definition of MapFn, you may also move the B type parameter to a type member. Then the signature of map becomes
def map(f: MapFn[C]): ItemsCollection[f.B] =
You can add a subclass to MapFn that moves the type member back to a parameter for ease of MapFn creation.
Using scala 2.12.4 I cannot get this code to work since it says
[error] .../src/main/scala/effect.scala:32:11: No ClassTag available for A
[error] Effect(effectDefinition)
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
here is the (simplified) code. the reason i need the class tag is to do a filtering later in the code (installEffect).
import scala.reflect.ClassTag
package object effect {
type EffectDefinition[A <: EffectBearing[A]] = A => Unit
case class Effect[A <: EffectBearing[A]](fx: A => Unit)(implicit tag: ClassTag[A]) {
def effectedType: Class[A] = tag.runtimeClass.asInstanceOf
}
trait EffectBearing[This <: EffectBearing[This]] {
def installEffect(effect: Effect[This]): Unit = {
effect.fx(this.asInstanceOf[This])
}
}
trait EffectPropagating {
def installEffect[T<: EffectBearing[T]](effect: Effect[T], typ: Class[T]): Unit =
find(typ).foreach(_.installEffect(effect))
protected def find[T <: EffectBearing[T]](typ: Class[T]): Set[T]
}
class Foo extends EffectBearing[Foo] {}
val fxFoo: EffectDefinition[Foo] = print(_)
def translate[A <: EffectBearing[A]](effectDefinition: EffectDefinition[A]): Effect[A] =
Effect(effectDefinition)
val fx = translate(fxFoo)
}
ps: is the usage of
tag.runtimeClass.asInstanceOf
very bad? I couldn't get around that cast
You have the following method:
def translate[A <: EffectBearing[A]](effectDefinition: EffectDefinition[A]): Effect[A] =
Effect(effectDefinition)
The Effect constructor requires an implicit ClassTag[A] but here A is a type parameter so the compiler doesn't know which concrete class it will be. And there is no ClassTag context bound on A in translate, so the compiler will not be able to find an implicit ClassTag[A].
I am defining a generic tree structure, i.e. one which can be extended so that for example branches and leaves contain additional values (I need this to add a name string for example).
So it looks like this:
trait TreeNodes {
val Node = Either
type Node[+B, +L] = Either[B, L]
val IsBranch = Left
type IsBranch[+B, +L] = Left[B, L]
val IsLeaf = Right
type IsLeaf[+B, +L] = Right[B, L]
}
object TreeLike extends TreeNodes {
trait BranchLike[Elem, B, L] {
type N = Node[B, L]
def iterator: Iterator[N]
}
trait LeafLike[Elem] {
def value: Elem
}
}
trait TreeLike[Elem, Repr] {
type Leaf <: TreeLike.LeafLike[Elem]
type Branch <: TreeLike.BranchLike[Elem, Branch, Leaf]
def root: Branch
}
Unfortunately, there is a pattern matcher bug:
def test[Elem, T <: TreeLike[Elem, T]](tree: T): Unit = {
import TreeLike.{IsLeaf, IsBranch}
def printLeaves(b: T#Branch): Unit = b.iterator.foreach {
case IsLeaf(l) => println(l.value)
case IsBranch(c) => printLeaves(c)
}
printLeaves(tree.root)
}
The error is as follows:
[error] during phase: patmat
[error] library version: version 2.10.3
[error] compiler version: version 2.10.3
...
[error] symbol definition: case val x1: b.N
[error] tpe: b.N
[error] symbol owners: value x1
[error] context owners: value x0$1 -> value $anonfun -> method printLeaves ->
method test -> object Voodoo -> package typerbug
...
[error] no-symbol does not have an owner
I suspect patmat has troubles with T#Branch somehow. Any ideas how to work around here?
I am also not 100% happy with wrapping leaves and branches in Either. This was necessary because the stuff got way out of hand when I tried to define a super type of LeafLike and BranchLike and figuring out how to correctly sub type that in implementations, and pattern matching broke done as well because I didn't figure out how to get correct extractors. So perhaps using Either is not that as a bad idea?
The type alias N is a "problem" (WTF).
trait BranchLike[Elem, B, L] {
def iterator: Iterator[Node[B, L]]
}
This makes it compile. Only that I am not very motivated to continue building this structure if it's about to collapse :-(
I have a DSL and some runtime code. The problem is I got somewhere at runtime:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
and I have a class
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass
}
val wrapper = new MyWrapper(value)
The problem is I need to return java.lang.String from a call of toString. But I got java.io.Serializable. Unfortunately I am neither able to create fixed pattern matching for each java.io.Serializable subtype (this would be crazy) nor to create MyWrapper explicit with new MyWrapper[String](value). I don't know the type of value, maybe it is a subtype of Serializable.
Is there some way to pass type/manifest value at runtime if I know that value type is equal to variable clazz?
Update (solution from Régis Jean-Gilles don't work). REPL test:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass.getName
}
val wrapper = new MyWrapper(value)
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz).asInstanceOf[ClassTypeManifest[java.io.Serializable]])
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
System.err.println(wrapper.toString)
I got an error, if I tried to pass manifest explicit:
scala> :load test.scala
Loading test.scala...
clazz: Class[_ <: java.io.Serializable] = class java.lang.String
value: java.io.Serializable = abc
defined class MyWrapper
<console>:10: error: type mismatch;
found : scala.reflect.ClassManifest[_$1] where type _$1 <: java.io.Serializable
(which expands to) scala.reflect.ClassTag[_$1]
required: Manifest[java.io.Serializable]
val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
^
<console>:8: error: not found: value wrapper
System.err.println(wrapper.toString)
Also I am unable to cast manifest explicit.
There is more strange error when I try to compile my application -
[error] found : scala.reflect.ClassManifest[(some other)_0(in method setProperty)]
[error] (which expands to) scala.reflect.ClassTag[(some other)_0(in method setProperty)]
[error] required: Manifest[_0(in method setProperty)]
[error] new Value.Static(default, Context.virtual(element))(ClassManifest.fromClass(elementProperty.typeClass)))
IMHO Régis Jean-Gilles very very close to solution. How to make it work with Scala 2.10?
If I understand correctly, you are using manifests to work around type erasure but at a specific point all you have is a Class[_] so you need to convert it back to a manifest. Correct?
If so, you can use ClassManifest.fromClass, and then explicitly pass it as the implicit value m.
val wrapper = new MyWrapper(value)(Manifest.classType(clazz))
You should probably abstract it away:
object MyWrapper {
def fromRuntimeType[T <: java.io.Serializable]( value: T ): MyWrapper[T] = {
new MyWrapper(value)(Manifest.classType(value.getClass))
}
}
Keep in mind though that because you only have a Class instance in the first place, you are at the mercy of type erasure again. This means that if the class (that you need to get a manifest for) is generic, you won't have any type parameter information in the manifest returned by ClassManifest.fromClass.
Wouldn't
override def toString = data.getClass.getName
already work for you? That yields java.lang.String.