简体   繁体   中英

Simulacrum in Scalafiddle: exception during macro expansion

I wanted to use Simulacrum in Scalafiddle, like:

import simulacrum._

@typeclass trait Ordering[T] {
    def compare(x: T, y: T): Int
    @op("<") def lt(x: T, y: T): Boolean = compare(x, y) < 0
    @op(">") def gt(x: T, y: T): Boolean = compare(x, y) > 0
}

This gives me the following error:

ScalaFiddle.scala:3: error: exception during macro expansion: 
scala.reflect.macros.TypecheckException: not found: type op
    at scala.reflect.macros.contexts.Typers.$anonfun$typecheck$3(Typers.scala:32)
    ...

Here is the fiddle: https://scalafiddle.io/sf/vT0X9FR/4

Do I miss something?

There's nothing wrong with your code, the problem is with ScalaFiddle.

If I attempt to run your code in scastie (similar web IDE for Scala), and print out the type trees generated by it, you can see the following:

|-- class Playground BYVALmode-EXPRmode (site: package <empty>) 
|    |-- new op("<") EXPRmode (silent: class Playground) 

You can see that scastie is causing the generated code to be wrapped inside a Playground class, which is not defined in your code, but provided for you by the web IDE.

If I compile the same example in IDEA, I see the following:

|-- new op("<") EXPRmode (silent: package github) 
|    |-- new op BYVALmode-EXPRmode-FUNmode-POLYmode (silent: package github) 

As you can see, there is no wrapping of the op type created by simulacrum. Because of this wrapping, simulacrum is not able to find the op type it generated, because it's full namespace at compile time is Playground.op .

To avoid this and as a workaround, wrap your traits inside an object:

import simulacrum._

object Foo {
  @typeclass trait Ordering[T] {
    def compare(x: T, y: T): Int
    @op("<") def lt(x: T, y: T): Boolean = compare(x, y) < 0
    @op(">") def gt(x: T, y: T): Boolean = compare(x, y) > 0
  }

  @typeclass trait Numeric[T] extends Ordering[T] {
    @op("+") def plus(x: T, y: T): T
    @op("*") def times(x: T, y: T): T
    @op("unary_-") def negate(x: T): T
    def zero: T
    def abs(x: T): T = if (lt(x, zero)) negate(x) else x
  }

  import Foo.Numeric.ops._
  def signOfTheTimes[T: Numeric](t: T): T = -(t.abs) * t
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM