scala / bug

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

Resolution of ambiguous implicits solved by covariance, but why? #7332

Open scabug opened 11 years ago

scabug commented 11 years ago

From https://gist.github.com/tpolecat/5307872:

trait Foo[A]

implicit val c: Foo[Int] = ???
implicit val d: Foo[String] = ???

def bar[A: Foo]: A = ???

bar: Int // compiles only if Foo is covariant in A ... why?

-Xprint:typer output differs for bar: Int...

When trait Foo[A]:

($anon.this.bar[Nothing](): Int)

and when trait Foo[+A]:

($anon.this.bar[Int]($anon.this.c): Int)
scabug commented 11 years ago

Imported From: https://issues.scala-lang.org/browse/SI-7332?orig=1 Reporter: Neuman Vong (lcfrs)

scabug commented 11 years ago

@hubertp said: Making type param A covariant gives type inferencer a bit more help to figure out the right type. In both cases Int is registered as an upper bound on type param A (resulting from the type ascription of bar).

When it is invariant, inferencer calculates least upper bound i.e. Nothing, meaning that it cannot really infer A before proceeding with implicit search. When it is covariant, inferencer calculates greatest lower bound (as A is now in contravariant position wrt to the type of bar) i.e. Int, hence the compiler later searches for an implicit argument of type Foo[Int] and no ambiguity arises.

scabug commented 11 years ago

Neuman Vong (lcfrs) said: Thanks Hubert! I understand the logic, but I was also wondering if it could also infer Foo[Int] from the declaration of Bar: Int.

While the implementation of the logic you described above may be bug-free, I believe it's worth looking at if the logic itself could be improved.

scabug commented 9 years ago

@SethTisue said: See discussion at https://groups.google.com/forum/#!topic/scala-language/dQEomVCH3CI

Jasper-M commented 7 years ago

Another fatality of this inconsistency?

import scala.collection.generic.CanBuildFrom

trait MyCBF[From, Elem] { type To; implicit def realCBF: CanBuildFrom[From, Elem, To] }
object MyCBF {
  def apply[From,Elem](implicit cbf: MyCBF[From, Elem]): MyCBF[From, Elem] { type To = cbf.To } = cbf
  implicit def MyCBF[From, Elem, To0](implicit cbf: CanBuildFrom[From, Elem, To0]): MyCBF[From, Elem]{type To = To0} = 
    new MyCBF[From, Elem] {
      type To = To0
      def realCBF = cbf
    }
}

MyCBF[List[Int], String]
// res0: MyCBF[List[Int],String]{type To = Any} = MyCBF$$anon$1@541c7857
//                                        ^^^^^

Dotty correcly infers MyCBF[List[Int], String]{ To = List[String] }.

PS: related to https://github.com/scala/bug/issues/10099 ?