wvlet / airframe

Essential Building Blocks for Scala
https://wvlet.org/airframe
Apache License 2.0
632 stars 66 forks source link

Surface: Cannot get `methodsOf` for simple generic types #3454

Closed OndrejSpanel closed 6 months ago

OndrejSpanel commented 7 months ago

Following code does not compile with Scala 3:

  case class Gen[X](value: X) {
    def pass(x: X): X = x
  }

  test("Methods of generic type") {
    val methods = Surface.methodsOf[Gen[String]]
  }

The error is:

[error] -- [E007] Type Mismatch Error: C:\Dev\airframe\airframe-surface\src\test\scala\wvlet\airframe\surface\GenericMethodTest.scala:44:35
[error] 44 |    val methods = Surface.methodsOf[Gen[String]]
[error]    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error]    |    Found:    X
[error]    |    Required: String

Note: In my "forked" library version the same call does not fail, yet the method surfaces are not correct. Both returnType and type of parameter 'x' of pass is not String but Object. Maybe type arguments are not applied for the methods when acquiring their surface.

With Scala 2 the code compiles, but the returned types are not applied, similar to my forked library. Following test can be compiled on Scala 2 but it fails:

  case class Gen[X](value: X) {
    def pass(x: X): X = x
    def myself: Gen[X] = this
    def wrap(x: X): Gen[X] = Gen[X](value)
    def unwrap(x: Gen[X]): X = x.value
  }

  test("Methods of generic type") {
    val typeSurface = Surface.of[Gen[String]]
    val methods = Surface.methodsOf[Gen[String]]
    val pass = methods.find(_.name == "pass").get
    pass.returnType shouldBe Surface.of[String]
    val myself = methods.find(_.name == "myself").get
    myself.returnType shouldBe typeSurface
    val wrap = methods.find(_.name == "wrap").get
    wrap.returnType shouldBe typeSurface
    val unwrap = methods.find(_.name == "unwrap").get
    unwrap.returnType shouldBe Surface.of[String]
  }