Skip to content
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

cm.reflect(object) doesn't properly work for value classes #6179

Closed
scabug opened this issue Aug 4, 2012 · 12 comments
Closed

cm.reflect(object) doesn't properly work for value classes #6179

scabug opened this issue Aug 4, 2012 · 12 comments
Assignees
Milestone

Comments

@scabug
Copy link

scabug commented Aug 4, 2012

import scala.reflect.runtime.universe._
import scala.reflect.runtime.{currentMirror => cm}

object Test extends App {
  val plus = typeOf[Int].declaration(newTermName("$plus")).asTerm.alternatives(0).asMethod
  println(cm.reflect(2).reflectMethod(plus))
}
scala.ScalaReflectionException: expected a member of class Integer, you provided method scala.Int.$plus
        at scala.reflect.runtime.JavaMirrors$JavaMirror.ErrorNotMember(JavaMirrors.scala:127)
        at scala.reflect.runtime.JavaMirrors$JavaMirror.scala$reflect$runtime$JavaMirrors$JavaMirror$$checkMemberOf(JavaMirrors.scala:157)
        at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaInstanceMirror.reflectMethod(JavaMirrors.scala:178)
        at scala.reflect.runtime.JavaMirrors$JavaMirror$JavaInstanceMirror.reflectMethod(JavaMirrors.scala:159)
        at Test$delayedInit$body.apply(reflection-magicsymbols-invoke.scala:6)
        at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
        at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
        at scala.App$$anonfun$main$1.apply(App.scala:61)
        at scala.App$$anonfun$main$1.apply(App.scala:61)
        at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
        at scala.collection.immutable.List.foreach(List.scala:78)
        at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
        at scala.collection.mutable.ListBuffer.foreach(ListBuffer.scala:45)
        at scala.App$class.main(App.scala:61)
        at Test$.main(reflection-magicsymbols-invoke.scala:4)
        at Test.main(reflection-magicsymbols-invoke.scala)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scala.tools.nsc.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:71)
        at scala.tools.nsc.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
        at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:139)
        at scala.tools.nsc.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:71)
        at scala.tools.nsc.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:139)
        at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:28)
        at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:45)
        at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:35)
        at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:45)
        at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:70)
        at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:92)
        at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
        at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
@scabug
Copy link
Author

scabug commented Aug 4, 2012

Imported From: https://issues.scala-lang.org/browse/SI-6179?orig=1
Reporter: @xeno-by
Other Milestones: 2.10.0

@scabug
Copy link
Author

scabug commented Aug 4, 2012

@xeno-by said:
Once this issue is fixed, we can start implementing reflective invocation for stuff like Int.+ or Double.*

@scabug
Copy link
Author

scabug commented Aug 5, 2012

@xeno-by said:
Woot! It is already possible to invoke methods of derived value classes, because methodToScala internally performs erasure, so it's able to find value class methods after transformation.

@scabug
Copy link
Author

scabug commented Aug 5, 2012

@xeno-by said:
In scala/scala#1057 I fixed the bug with checkMemberOf that always considered primitives to be boxed. However actually invoking all the gazillion of magic methods on primitives is a completely different business that needs a sophisticated solution. For now I just added the "implementation restriction" error message.

@scabug
Copy link
Author

scabug commented Aug 5, 2012

@xeno-by said:
Demoting to major and deferring the fix to 2.10.x

@scabug
Copy link
Author

scabug commented Aug 6, 2012

@paulp said:
By the gods, please don't overlook the fact that the primitive operations have already been implemented as methods for structural types. Even if they're to be reimplemented to act on unboxed types, don't further balkanize the code.

@scabug
Copy link
Author

scabug commented Aug 6, 2012

@xeno-by said:
Sounds great! Could you please point to the relevant piece of code?

@scabug
Copy link
Author

scabug commented Aug 6, 2012

@paulp said:
I was hoping you would already know. Someone should surely have pointed in this direction by now.

See BoxesRunTime.java for the implementations, generated from Cleanup.scala.

@scabug
Copy link
Author

scabug commented Aug 6, 2012

@xeno-by said:
Wow that's super cool! Now I might actually implement this in 2.10.0.

@scabug
Copy link
Author

scabug commented Aug 6, 2012

@xeno-by said:
Promoting to critical, because there seems to be an easy fix.

@scabug
Copy link
Author

scabug commented Aug 6, 2012

@paulp said:
Don't miss these methods in StdNames which I wrote just in case someone came along someday who wanted to do this.

    def primitiveInfixMethodName(name: Name): TermName = name match {
      case OR   => takeOr
      case XOR  => takeXor
      case AND  => takeAnd
      case EQ   => testEqual
      case NE   => testNotEqual
      case ADD  => add
      case SUB  => subtract
      case MUL  => multiply
      case DIV  => divide
      case MOD  => takeModulo
      case LSL  => shiftSignedLeft
      case LSR  => shiftLogicalRight
      case ASR  => shiftSignedRight
      case LT   => testLessThan
      case LE   => testLessOrEqualThan
      case GE   => testGreaterOrEqualThan
      case GT   => testGreaterThan
      case ZOR  => takeConditionalOr
      case ZAND => takeConditionalAnd
      case _    => NO_NAME
    }
    /** Postfix/prefix, really.
     */
    def primitivePostfixMethodName(name: Name): TermName = name match {
      case UNARY_!    => takeNot
      case UNARY_+    => positive
      case UNARY_-    => negate
      case UNARY_~    => complement
      case `toByte`   => toByte
      case `toShort`  => toShort
      case `toChar`   => toCharacter
      case `toInt`    => toInteger
      case `toLong`   => toLong
      case `toFloat`  => toFloat
      case `toDouble` => toDouble
      case _          => NO_NAME
    }

@scabug
Copy link
Author

scabug commented Aug 7, 2012

@xeno-by said:
scala/scala@3aa221e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants