trait Foo[F[_]]
trait Bar[F[_], A]

trait Or[A, B]

class Test {
  implicit def orFoo[A]: Foo[({type L[X] = Or[A, X]})#L] = ???
  implicit def barFoo[F[_]](implicit f: Foo[F]): Foo[({type L[X] = Bar[F, X]})#L] = ???

  // Now we can define a couple of type aliases:
  type StringOr[X] = Or[String, X]
  type BarStringOr[X] = Bar[StringOr, X]

  // ok
  implicitly[Foo[BarStringOr]]
  barFoo[StringOr](null) : Foo[BarStringOr]
  barFoo(null) : Foo[BarStringOr]

  // nok
  implicitly[Foo[({type L[X] = Bar[StringOr, X]})#L]]
  // Let's write the application explicitly, and then
  // compile with just this line enabled and -explaintypes.
  barFoo(null) : Foo[({type L[X] = Bar[StringOr, X]})#L]

  // Foo[[X]Bar[F,X]] <: Foo[[X]Bar[[X]Or[String,X],X]]?
  //   Bar[[X]Or[String,X],X] <: Bar[F,X]?
  //     F[_] <: Or[String,_]?
  //     false
  //   false
  // false

  // Note that the type annotation above is typechecked as
  // Foo[[X]Bar[[X]Or[String,X],X]], ie the type alias `L`
  // is eta expanded.
  //
  // This is done so that it does not escape its defining scope.
  // However, one this is done, higher kinded inference
  // no longer is able to unify F with `StringOr` (scala/bug#2712)
}
