scalamacros / paradise

(No longer actively maintained.)
http://scalamacros.org/
BSD 3-Clause "New" or "Revised" License
158 stars 53 forks source link

Unimplemented members for methods in generated class #103

Closed chipsenkbeil closed 7 years ago

chipsenkbeil commented 7 years ago

My problem is that my generated class' members are not getting recognised as implemented. This is currently using Scala 2.10, but I plan to refactor it for 2.11/2.12 once I get this implementation working. Using macroparadise 2.10.

Goal of this was to mark the some traits as freezable and generate an implementation class for each that takes scala.util.Try for each method that is freezable that will have its get method called when accessing the data. All unfreezable methods are filled in with throw new IllegalStateException. And a custom freeze method is created that creates an instance of the Frozen class filled in with the data needed using the methods defined by the trait.

I have set up an annotation macro to be placed on traits and generate a companion object with an inner class called Frozen like below:

{
  abstract trait JavaInfo extends scala.AnyRef {
    @new CanFreeze() def isJavaInfo: Boolean;
    @new CannotFreeze() def toJavaInfo: AnyRef
  };
  object JavaInfo extends scala.AnyRef {
    def <init>() = {
      super.<init>();
      ()
    };
    class Frozen extends JavaInfo with java.io.Serializable {
      <paramaccessor> private val $isJavaInfo: scala.util.Try[Boolean] = _;
      def <init>($isJavaInfo: scala.util.Try[Boolean]) = {
        super.<init>();
        ()
      };
      override def isJavaInfo: Boolean = this.$isJavaInfo.get;
      override def toJavaInfo: AnyRef = throw new IllegalStateException("Method not frozen!")
    };
    def freeze(valueToFreeze: JavaInfo): Frozen = new Frozen(scala.util.Try.apply(valueToFreeze.isJavaInfo))
  };
  ()
}

The following error occurs when I try to run my macro on the trait JavaInfo:

[error] /Users/senk/projects/scala-debugger/scala-debugger-api/src/main/scala/org/scaladebugger/api/profiles/traits/info/JavaInfo.scala:9: class Frozen needs to be abstract, since:
[error] it has 2 unimplemented members.
[error] /** As seen from class Frozen, the missing signatures are as follows.
[error]  *  For convenience, these are usable as stub implementations.
[error]  */
[error]   override def isJavaInfo: Boolean = ???
[error]   override def toJavaInfo: AnyRef = ???
[error] @Freezable trait JavaInfo {
[error]  ^
[error] one error found

The trait itself is as follows:

import org.scaladebugger.macros.freeze.{CanFreeze, CannotFreeze, Freezable}

@Freezable trait JavaInfo {
  @CanFreeze def isJavaInfo: Boolean
  @CannotFreeze def toJavaInfo: AnyRef
}

Get error that nothing has been implemented by the Frozen class, even though I see the implementation in the tree I'm building.

Code in question is here: https://github.com/chipsenkbeil/scala-debugger/blob/AddFreezableMacroSupport/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/Freezable.scala

You can test the failure by checking out that branch and running sbt scalaDebuggerApi/compile, which will compile the macros project for Scala 2.10 followed by the API itself.

chipsenkbeil commented 7 years ago

Update in that now it compiles to the same level with 2.10, 2.11, and 2.12.

See https://github.com/chipsenkbeil/scala-debugger/blob/AddFreezableMacroSupport/scala-debugger-macros/src/main/scala/org/scaladebugger/macros/freeze/FreezableMacro.scala

Still can't get the compiler to recognise my filled in methods. Considering only generated code is referencing the generated class, I would have thought it would work. Am I not understanding something correctly?

chipsenkbeil commented 7 years ago

Figured it out. I was creating the methods and implementing their bodies, but reusing the old modifiers of each method and just tacking on the Flag.OVERRIDE: FlagSet. Turns out unimplemented methods have a Flag.DEFERRED on them, so I was producing a Modifiers(OVERRIDE | DEFERRED), which didn't make sense considering it had a body.