New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implicit Lookup fails for implicit view on nested type. #4225
Comments
Imported From: https://issues.scala-lang.org/browse/SI-4225?orig=1 |
@axel22 said: scala> Foo.foo("foo") andThen (() => "Bar")
<console>:8: error: type mismatch;
found : () => java.lang.String
required: _1.Bar where val _1: java.lang.Object with Foo
Foo.foo("foo") andThen (() => "Bar" |
@axel22 said: 7.3 Views
...
Views are applied in two situations:
1. If an expression e is of type T , and T does not conform to the expression’s
expected type pt. In this case an implicit v is searched which is applicable to
e and whose result type conforms to pt. The search proceeds as in the case of
implicit parameters, where the implicit scope is the one of T => pt. If such a
view is found, the expression e is converted to v (e ). In our case, the The implicit scope of a type T consists of all companion modules (�5.4) of classes
that are associated with the implicit parameter’s type. Here, we say a class C is asso-
ciated with a type T , if it is a base class (�5.1.2) of some part of T . The parts of a type
T are:
...
* if T is a parameterized type S [T1 , . . . , Tn ], the union of the parts of S and
T1 , . . . , Tn ,
... The implicit scope I've shown this and talked to two more people from the lab, and they think this should be put back to the meeting. |
@adriaanm said: trait Foo {
val name : String
trait Bar {
def doSomething : String
override def toString = "Foo(" + name + ").Bar -> " + doSomething
}
object Bar {
implicit def fromFunction(func : Function0[String]) = new Bar {
def doSomething = func()
}
}
def andThen(b : Bar) = b
}
object Foo {
def foo(n : String) = new Foo {
override val name = n
}
}
object Test {
val f = Foo.foo("foo")
f andThen (() => "Bar")
} |
@adriaanm said: class Foo {
class Bar
object Bar {
implicit def fromString(a: String) = new Bar
}
def andThen(b : Bar) = b
}
object Test {
(new Foo) andThen ("Bar")
} |
@adriaanm said: the problem is that the target of the andThen call is not stable, and thus, nor is the expected type of andThen's argument. In the "val f" variant above, the type of the argument is f.Bar, but in the original example it's before the search for the implicit conversion that converts "Bar" into a suitable argument for andThen has even begun, it is doomed: since we've essentially opened the existential in the expected type, but not in the return type of the fromFunction implicit, those types have become hopelessly incompatible. fromFunction's return type must now be thought of as conceptually, it would be reasonable to expect the skolems (existentials that have been opened) X and Y in X.Bar (expected type of andThen's argument) and Y.Bar (return type of the fromFunction implicit) to refer to the same "value", and thus for the type selections to refer to the same type, but this is not how it's implemented (and I'm pretty sure it would be hard to change that) |
@okomok said: class DependentImplicitTezt {
trait Bridge
class Outer {
class Inner extends Bridge
object Inner {
implicit def fromOther(b: Bridge): Inner = throw new Error("todo")
}
def run(x: Inner) = throw new Error("todo")
}
val o1 = new Outer
val o2 = new Outer
val i1 = new o1.Inner
val i2 = new o2.Inner
def doesntCompile {
o1.run(i2) // no
}
def workaround1 {
o1.run(i2: Bridge) // ok
}
def workaround2 {
import o1.Inner.fromOther
o1.run(i2) // ok
}
} |
@paulp said: object Test {
implicit class Ops(val g: scala.reflect.api.JavaUniverse) {
def op[T: g.TypeTag] = ()
}
scala.reflect.runtime.universe.op[Int]
}
|
@retronym said: // [Eugene to Martin] this is the crux of the interaction between
// implicits and reifiers here we need to turn a (supposedly
// path-dependent) type into a tree that will be used as a prefix I'm
// not sure if I've done this right - please, review
case SingleType(prePre, preSym) =>
gen.mkAttributedRef(prePre, preSym) setType pre |
@retronym said: object Test {
class Ops[U <: scala.reflect.api.JavaUniverse](val g: U) {
def op[T: U#TypeTag] = ()
}
implicit def Ops(g: scala.reflect.api.JavaUniverse): Ops[g.type] = new Ops(g)
Ops(scala.reflect.runtime.universe).op[Int]
scala.reflect.runtime.universe.op[Int]
} |
@adriaanm said: |
PR: scala/scala#5999 |
val for the unstable LHS of an implicit method application where the method type depends on the LHS. As applied to this example, taken from scala/bug#4225, ```scala class Foo { class Bar object Bar { implicit def mkBar: Bar = new Bar } } object f extends Foo implicit class Ops[F <: Foo](val f0: F) { def op(i: Int)(implicit b: f0.Bar): f0.Bar = b } f.op1(23) ``` this transformation produces, ```scala { val stabilizer$1 = Ops[f.type](f) stabilizer$1.op1(23) } ``` Because `stabilizer$1` is stable we retain the singleton type `F` and the implicit argument of type `f0.Bar` can be resolved against the implicit scope of `f.type`. A real world example of this is the macro API issue reported in scala/bug#5946 ... following this PR the usage below compiles as expected, ```scala class Ops(val g: scala.reflect.api.JavaUniverse) { def op[T: g.TypeTag] = () } implicit def Ops(g: scala.reflect.api.JavaUniverse): Ops = new Ops(g) scala.reflect.runtime.universe.op[Int] ``` In principle this transformation could also be applied for explicit applications, however there would no gain: to be able to write the explicit argument the user would already have had to explicitly introduce the necessary val.
val for the unstable LHS of an implicit method application where the method type depends on the LHS. As applied to this example, taken from scala/bug#4225, ```scala class Foo { class Bar object Bar { implicit def mkBar: Bar = new Bar } } object f extends Foo implicit class Ops[F <: Foo](val f0: F) { def op(i: Int)(implicit b: f0.Bar): f0.Bar = b } f.op1(23) ``` this transformation produces, ```scala { val stabilizer$1 = Ops[f.type](f) stabilizer$1.op1(23) } ``` Because `stabilizer$1` is stable we retain the singleton type `F` and the implicit argument of type `f0.Bar` can be resolved against the implicit scope of `f.type`. A real world example of this is the macro API issue reported in scala/bug#5946 ... following this PR the usage below compiles as expected, ```scala class Ops(val g: scala.reflect.api.JavaUniverse) { def op[T: g.TypeTag] = () } implicit def Ops(g: scala.reflect.api.JavaUniverse): Ops = new Ops(g) scala.reflect.runtime.universe.op[Int] ``` In principle this transformation could also be applied for explicit applications, however there would no gain: to be able to write the explicit argument the user would already have had to explicitly introduce the necessary val.
This fixes scala/bug#4225 and scala/bug#5946 by introducing a synthetic val for the unstable LHS of an implicit method application where the method type depends on the LHS. As applied to this example, taken from scala/bug#4225, ```scala class Foo { class Bar object Bar { implicit def mkBar: Bar = new Bar } } object f extends Foo implicit class Ops[F <: Foo](val f0: F) { def op(i: Int)(implicit b: f0.Bar): f0.Bar = b } f.op1(23) ``` this transformation produces, ```scala { val stabilizer$1 = Ops[f.type](f) stabilizer$1.op1(23) } ``` Because `stabilizer$1` is stable we retain the singleton type `F` and the implicit argument of type `f0.Bar` can be resolved against the implicit scope of `f.type`. A real world example of this is the macro API issue reported in scala/bug#5946 ... following this PR the usage below compiles as expected, ```scala class Ops(val g: scala.reflect.api.JavaUniverse) { def op[T: g.TypeTag] = () } implicit def Ops(g: scala.reflect.api.JavaUniverse): Ops = new Ops(g) scala.reflect.runtime.universe.op[Int] ``` In principle this transformation could also be applied for explicit applications, however there would no gain: to be able to write the explicit argument the user would already have had to explicitly introduce the necessary val.
And then run in the REPL
=== What is the expected behavior? ===
I expect the implicit lookup to succeed in finding an implicit view for foo.Bar.
=== What do you see instead? ===
A stack trace
=== Additional information ===
(for instance, a link to a relevant mailing list discussion)
=== What versions of the following are you using? ===
The text was updated successfully, but these errors were encountered: