Last active
January 4, 2016 00:19
-
-
Save puffnfresh/8540756 to your computer and use it in GitHub Desktop.
Minimised scalac crash.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scalaz._ | |
import Scalaz._ | |
import scalaz.effect._ | |
object Test { | |
implicit def eitherTMonadIO[M[_], E](implicit M: MonadIO[M]): MonadIO[({type l[A]=EitherT[M, E, A]})#l] = ??? | |
def x = for { | |
_ <- true whenM IO.putStrLn("World").liftIO[({type e[A]=EitherT[IO, String, A]})#e] | |
} yield () | |
} | |
/* | |
scala> :l Test.scala | |
Loading Test.scala... | |
import scalaz._ | |
import Scalaz._ | |
import scalaz.effect._ | |
error: type mismatch; | |
found : scalaz.EitherT[scalaz.effect.IO,String,Unit] | |
required: ?M | |
Note that implicit conversions are not applicable because they are ambiguous: | |
both method ToBitraverseVFromKleisliLike in trait ToBitraverseOps of type [G[_], F[G[_], _, _], A, B](v: F[G,A,B])(implicit F0: scalaz.Bitraverse[[α, β]F[G,α,β]])scalaz.syntax.BitraverseOps[[α, β]F[G,α,β],A,B] | |
and method ToArrowVFromKleisliLike in trait ToArrowOps of type [G[_], F[G[_], _, _], A, B](v: F[G,A,B])(implicit F0: scalaz.Arrow[[α, β]F[G,α,β]])scalaz.syntax.ArrowOps[[α, β]F[G,α,β],A,B] | |
are possible conversion functions from scalaz.EitherT[scalaz.effect.IO,String,Unit] to ?M | |
*/ |
Fixed the error reporting, at least. The type argument inference for whenM
clearly isn't what you're after. It looks ill-kinded, but Any
is taken to be kind-polymorphic so that is allowed. It will never infer the partially applied type constructor, however.
Introducing a type alias to hint the type-constructor inference is usually the best way to deal with this. The following compiles:
object Test {
import scalaz._
import Scalaz._
import scalaz.effect._
object Test {
implicit def eitherTMonadIO[M[_], E](implicit M: MonadIO[M]): MonadIO[({ type l[A] = EitherT[M, E, A] })#l] = ???
type e[A] = EitherT[IO, String, A]
def x = for {
_ <- true whenM IO.putStrLn("World").liftIO[e]
} yield ()
}
}
import language._
object Test {
trait E[A, B]
def foo[M[_]](mi: M[Int]): M[Int] = mi
val e: E[Int, Int] = ???
// M?[Int] ~ Either[Int, Int]
//
// no type parameters for method foo: (mi: M[Int])M[Int] exist
// argument expression's type is not compatible with formal parameter type;
// found : Test.E[Int,Int]
// required: ?M
// foo(e)
object Sub {
implicit class ImplicitClass1[A](val e: E[_, _]) // aka MergeableEither in the stdlib
// having a non-ambiguous implicit from E[Int, Int] => _[_]
// is enough for type inference to consider this applicable.
// the type variable M? accumulates constraints during the entire
// implicit search rather than just the successful case (!!!),
// which leads us to solve the constraints:
//
// M? >: (ArrowAssoc, Ensuring, StringFormat, StringAdd, Test.Sub.ImplicitClass1)
//
// Only the empty set of upper bounds is actualy material in this case,
// as M appears in a covariant position in the formal param types of `foo`
// of `foo`.
//
// With no upper bounds, the solution is the GLB(Nil), or:
//
// M? = Any
//
// The implicit that it found to satisfy `isCompatible` is now long
// forgotten, and things proceed as if you'd written:
//
// foo[Any](e)
//
// Thanks to the regrettable kind-polymorphic nature of `Any`, this typechecks!
//
// -Ywarn-infer-any on 2.11.x comes highly recommended!
//
// BTW, you could probably add this to wart-remover in 2.10 by finding TypeTree-s
// in type applications where the Type =:= Any but the TypeTree.original == null.
// This means it was inferred; TypeTrees that originate from Idents/Selects in source
// have a non-null original.
foo(e)
}
// This part shows how a type alias (not one that's hidden in a type lambda)
// can help inference.
// During inference, a type variable representing a type constructor is
// unified with the series of candidate types until one matches.
// This is implemented here: https://github.com/scala/scala/blob/v2.10.3-RC3/src/reflect/scala/reflect/internal/Types.scala#L3217
// Type aliases are unwrapped one-by-one to find case where shape of the
// LHS and RHS align.
//
// If that fails, super types are considered.
//
// https://github.com/scala/scala/blob/v2.10.3-RC3/src/reflect/scala/reflect/internal/Types.scala#L3270
//
type EInt[A] = E[Int, A]
val e1: EInt[Int] = e
// M?[Int] ~ EitherInt[Int]
// M = EitherInt
// foo[EitherInt](e)
foo(e1)
foo( foo[({type l[A] = E[Int, A]})#l](e) )
// `------------Test.E[Int,Int]}-----/
//
// The result type of this expression can't refer to the type alias
// `l` as this would be ill-scoped. As such, the compiler has to
// expand the type (by existentially abstracting over `l` which in
// this case is simplified to a dealiasing back to `E[Int, Int]`)
// As such, the type constructor inference doesn't have a means
// unify with `M?[Int]` when inferring the type arg for the outer
// application to `foo`.
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That rings a bell, I fixed that in 2.11.