Skip to content

Structural Type invocation can result fail during reflective lookup due to bridging #10414

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

Open
retronym opened this issue Jul 18, 2017 · 3 comments
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) structural types
Milestone

Comments

@retronym
Copy link
Member

The residual, and hard-to-fix, part of #10334. scala/scala#5977 restored parity with 2.11 with respect to the way this problem manifest with lambdas, but the core issue remains unsolved:

  def t3(): Unit = {
    val f1 = new T[A] {
      def m(x: A) = "f1-a"
      def m(x: B) = "f1-b"
       // the m(Object)Object bridge method invokes (A)Object
    }

    val f2 = new T[B] {
      def m(x: A) = "f2-a"
      def m(x: B) = "f2-b"
       // the (Object)Object bridge method invokes (B)Object
    }

    val g1: T[C] = f1
    val g2: T[C] = f2

    assert(g1.m(new C) == "f1-a")
    assert(g2.m(new C) == "f2-b")

    val s1: { def m(s: C): Object } = g1
    val s2: { def m(s: C): Object } = g2

    // the reflective lookup doesn't find `m(C)Object`
    try {
      s1.m(new C) // should invoke `m(A)Object`
      throw new Error()
    } catch {
      case _: java.lang.NoSuchMethodException =>
    }

    // the reflective lookup doesn't find `m(C)Object`
    try {
      s2.m(new C) // should invoke `m(B)Object`
      throw new Error()
    } catch {
      case _: java.lang.NoSuchMethodException =>
    }
  }
@sjrd
Copy link
Member

sjrd commented Jul 18, 2017

FTR, Scala.js is perfectly bug-compatible with the above. NoSuchMethodExceptions become JavaScript TypeErrors, but otherwise it's exactly the same.

package helloworld

import scala.language.reflectiveCalls

import scala.scalajs.js

class A
class B extends A
class C extends B

trait T[-A] {
  def m(a: A): Object
}

object HelloWorld {
  def main(args: Array[String]): Unit = {
    t3()
  }

  def t3(): Unit = {
    val f1 = new T[A] {
      def m(x: A) = "f1-a"
      def m(x: B) = "f1-b"
       // the m(Object)Object bridge method invokes (A)Object
    }

    val f2 = new T[B] {
      def m(x: A) = "f2-a"
      def m(x: B) = "f2-b"
       // the (Object)Object bridge method invokes (B)Object
    }

    val g1: T[C] = f1
    val g2: T[C] = f2

    assert(g1.m(new C) == "f1-a")
    assert(g2.m(new C) == "f2-b")

    val s1: { def m(s: C): Object } = g1
    val s2: { def m(s: C): Object } = g2

    // the reflective lookup doesn't find `m(C)Object`
    try {
      s1.m(new C) // should invoke `m(A)Object`
      throw new Error()
    } catch {
      case js.JavaScriptException(_: js.TypeError) =>
    }

    // the reflective lookup doesn't find `m(C)Object`
    try {
      s2.m(new C) // should invoke `m(B)Object`
      throw new Error()
    } catch {
      case js.JavaScriptException(_: js.TypeError) =>
    }
  }
}

@smarter
Copy link
Member

smarter commented Jan 5, 2021

This is reproducible without variance too, from #12297:

scala> import scala.language.reflectiveCalls

scala> class Sink[A] { def put(x: A): Unit = {} }
class Sink

scala> val a = new Sink[String]
val a: Sink[String] = Sink@5dbbb292

scala> val b: { def put(x: String): Unit } = a
val b: AnyRef{def put(x: String): Unit} = Sink@5dbbb292

scala> b.put("")
java.lang.NoSuchMethodException: Sink.put(java.lang.String)
  at java.lang.Class.getMethod(Class.java:1786)
  at reflMethod$Method1(<console>:1)
  ... 32 elided

@smarter
Copy link
Member

smarter commented Apr 29, 2021

Fixed in Scala 3 by scala/scala3#12214, in particular for the original example we get:

-- [E007] Type Mismatch Error: try/t10414.scala:28:38 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
28 |    val s1: { def m(s: C): Object } = g1
   |                                      ^^
   |                                      Found:    (g1 : T[C])
   |                                      Required: Object{m(s: C): Object}

longer explanation available when compiling with `-explain`
-- [E007] Type Mismatch Error: try/t10414.scala:29:38 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
29 |    val s2: { def m(s: C): Object } = g2
   |                                      ^^
   |                                      Found:    (g2 : T[C])
   |                                      Required: Object{m(s: C): Object}

@smarter smarter added the fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) label Apr 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fixed in Scala 3 This issue does not exist in the Scala 3 compiler (https://github.com/lampepfl/dotty/) structural types
Projects
None yet
Development

No branches or pull requests

4 participants