Dotty: Implicit conversion isn't applied for Id type alias

Created on 21 Jan 2020  路  3Comments  路  Source: lampepfl/dotty

minimized code

import scala.language.implicitConversions

class Ops[A](a: A) {
  def bar: Unit = ()
}

implicit def toOps[A](a: A): Ops[A] = new Ops[A](a)

type Id[A] = A

class Foo[A](val value: Id[A]) {
  def same: Foo[A] = new Foo[A](value)
  def map[B](f: A => B): Foo[B] = new Foo[B](f(value))
}

val x: Int = 1
val foo: Foo[Int] = new Foo(1)

val res1 = x.bar
val res2 = foo.value.bar
val res3 = foo.same.value.bar
val res4 = foo.map[Int](_ + 1).value.bar
val res5 = foo.map(_ + 1).value.bar


Compilation output

-- [E008] Member Not Found Error: Id.scala:23:32 -------------------------------
23 |val res5 = foo.map(_ + 1).value.bar
   |           ^^^^^^^^^^^^^^^^^^^^^^^^
   |value bar is not a member of Id[B], but could be made available as an extension method.
   |
   |One of the following imports might fix the problem:
   |
   |  import Int.int2double
   |  import Int.int2float
   |  import Int.int2long
   |  import math.BigDecimal.int2bigDecimal
   |  import math.BigInt.int2bigInt
   |  import math.Numeric.IntIsIntegral.mkNumericOps
   |  import math.Numeric.BigIntIsIntegral.mkNumericOps
   |  import math.Numeric.IntIsIntegral.mkOrderingOps
   |  import math.Ordering.Int.mkOrderingOps
   |  import Long.long2double
   |  import Long.long2float
   |  import math.BigDecimal.long2bigDecimal
   |  import math.BigInt.long2bigInt
   |  import math.Numeric.LongIsIntegral.mkNumericOps
   |  import math.Numeric.FloatIsFractional.mkNumericOps
   |  import math.Ordering.Long.mkOrderingOps
   |  import Float.float2double
   |  import math.BigDecimal.double2bigDecimal
   |  import math.Numeric.DoubleIsFractional.mkNumericOps
   |  import math.Numeric.BigDecimalAsIfIntegral.mkNumericOps
   |  import math.Numeric.BigDecimalIsFractional.mkNumericOps
   |  import math.Numeric.LongIsIntegral.mkOrderingOps
   |  import math.Numeric.BigDecimalAsIfIntegral.mkOrderingOps
   |  import math.Numeric.BigDecimalIsFractional.mkOrderingOps
   |  import math.Numeric.BigIntIsIntegral.mkOrderingOps
   |  import math.Numeric.FloatIsFractional.mkOrderingOps
   |  import math.Numeric.DoubleIsFractional.mkOrderingOps
   |  import math.Ordering.BigDecimal.mkOrderingOps
   |  import math.Ordering.BigInt.mkOrderingOps
   |  import math.Ordering.DeprecatedFloatOrdering.mkOrderingOps
   |  import math.Ordering.Float.IeeeOrdering.mkOrderingOps
   |  import math.Ordering.Float.TotalOrdering.mkOrderingOps
   |  import math.Ordering.DeprecatedDoubleOrdering.mkOrderingOps
   |  import math.Ordering.Double.IeeeOrdering.mkOrderingOps
   |  import math.Ordering.Double.TotalOrdering.mkOrderingOps
   |  import math.Integral.Implicits.infixIntegralOps
   |  import math.Numeric.Implicits.infixNumericOps
   |  import math.Ordered.orderingToOrdered
   |  import math.Ordering.Implicits.infixOrderingOps
   |  import reflect.Selectable.reflectiveSelectable
   |  import implicits.Not.amb1
   |  import implicits.Not.amb2
   |         
   |
   |where:    B is a type variable with constraint >: Int
1 error found

expectation

This compiles on Scala 2. I'm running into this in the Cats tests, where we use ScalaTest's should matchers to tests methods on e.g. WriterT[Id, A, B], which return Id[C] where C is inferred.

If you change Id to something like type Id[A] = List[A] and edit Foo appropriately, it compiles fine on Dotty.

bug

Most helpful comment

Btw, these are really useful minimizations! Thanks for putting in the effort.

All 3 comments

It also compiles if Id is covariant. I.e. if I change it like this

type Id[+A] = A

it compiles OK. What happens here is that A is not instantiated since it is nonvariant in the type of foo.map(_ + 1).value. Then since A only has a lower bound no member can be found on A.

A possible fix is to see "through" the alias to realize that A is covariant after all and should be minimized. That might also be a fix for #7993.

Btw, these are really useful minimizations! Thanks for putting in the effort.

I鈥檓 not sure whether it is the same issue or not, but the suggested imports contain duplicated entries:

~ text
import Ordering.Implicits.seqOrdering
import Ordering.Iterable
import math.Ordering.Implicits.seqOrdering
import math.Ordering.Iterable
~

Minimized code:

~~~ scala
import Ordering.Implicits.seqOrdering

class Foo

object OrderingInstances {
implicit def orderingFoo: Ordering[Foo] = ???
}

List(List(new Foo)).sorted
~~~

Was this page helpful?
0 / 5 - 0 ratings

Related issues

andreaTP picture andreaTP  路  3Comments

liufengyun picture liufengyun  路  3Comments

mcku picture mcku  路  3Comments

noti0na1 picture noti0na1  路  3Comments

dwijnand picture dwijnand  路  3Comments