scala / bug

Scala 2 bug reports only. Please, no questions — proper bug reports only.
https://scala-lang.org
231 stars 21 forks source link

Implicit resolution bug in scalac (working in dotty) #10420

Open virusdave opened 7 years ago

virusdave commented 7 years ago

I didn't get an answer on the scala list, and don't see this particular case already on the bug tracker. Then again, i don't really understand why this isn't working, so i may have missed it.

Repro example showing the failure:

trait ShapeLevel
trait FlatShapeLevel extends ShapeLevel
trait ColumnsShapeLevel extends FlatShapeLevel

abstract class Shape[Level <: ShapeLevel, -Mixed_, Unpacked_, Packed_]
object Shape extends TupleShapeImplicits { }
trait TupleShapeImplicits {
  implicit final def tuple2Shape[Level <: ShapeLevel, M1,M2, U1,U2, P1,P2](
      implicit u1: Shape[_ <: Level, M1, U1, P1], 
               u2: Shape[_ <: Level, M2, U2, P2]): 
    Shape[Level, (M1,M2), (U1,U2), (P1,P2)] = ???
}

class Query[A, B] {
  def map[C, D](f: (A) => C)(implicit shape: Shape[_ <: FlatShapeLevel, C, D, _]) = ???
}

// This works, but is too restrictive on the `Level` of the implicit shape
def pairItGood[A, B](q: Query[A, B])(implicit shape: Shape[FlatShapeLevel, A, B, _]) =
  q.map(x => (x, x))

// This works, since i've given it the 'hint' to use the `tuple2Shape` (no-longer-)implicit def
def pairItHint[A, B](q: Query[A, B])(implicit shape: Shape[_ <: FlatShapeLevel, A, B, _]) = {
  implicit val hint = Shape.tuple2Shape(shape, shape)
  q.map(x => (x, x))
}

// This fails.  Why can't we find `tuple2Shape` in this case?  FAILS IN SCALAC, WORKS IN DOTTY!
def pairItBad[A, B](q: Query[A, B])(implicit shape: Shape[_ <: FlatShapeLevel, A, B, _]) =
  q.map(x => (x, x))

Scalac: https://scastie.scala-lang.org/2hFKFaBtSoiJuBDgt26vwA Dotty: https://scastie.scala-lang.org/TgdSZ64xS8e7Ta8HjzZyig

Scala-users thread: https://users.scala-lang.org/t/implicit-resolution-quirk/528/4

virusdave commented 7 years ago

Any thoughts on this?

joroKr21 commented 6 years ago

There are a lot of existential types in this example that make me feel uneasy (there's even a warning about them). Which naturally leads to the following definition that does work:

def pairItBad[L <: FlatShapeLevel, A, B, C](q: Query[A, B])(implicit shape: Shape[L, A, B, C]) =
    q.map(x => (x, x))

Note: Dotty doesn't have existential types (only wildcards).

jvican commented 6 years ago

@joroKr21 Has this issue between existential types and implicit search been reported in scala/bug before?

joroKr21 commented 6 years ago

I don't know. There are many issues about existential types. It's probably not so much the implicit search being involved, but rather type inference messing up with skolems and type variables.

joroKr21 commented 6 years ago

Actually in this example implicit search does matter, because internally it uses an existential abstraction to find implicit candidates.