Skip to content

Syntax for method types or tree constructors useful in meta-programming #5563

Closed
@liufengyun

Description

@liufengyun

I'm writing a ScalaTest macro, where I find it helpful to have syntax for method types.

The use case is to transform the source code:

assert(5 === 6)

which is desugared as:

assert(
  AssertionsSpec.this.convertToEqualizer[scala.Int](5).===(6)(scalactic.Equality.default[scala.Int])
)

and macro expanded to something like the follows:

{
    val lhs = 5
    val rhs = 6
    val result = AssertionsSpec.this.convertToEqualizer[scala.Int](lhs).===(rhs)(scalactic.Equality.default[scala.Int])
    val _bool = Bool.binaryMacroBool(lhs,  "===", rhs, result)
    Assertions.assertionsHelper.macroAssert(_bool, "", pos)
}

The natural thing to do in the implementation is to seal the following tree as a whole:

AssertionsSpec.this.convertToEqualizer[scala.Int]

The ideal implementation is something like the following:

val fun = fn.seal[(Any)Equalizer[_]]
val left = lhs.seal[Any]
val right = rhs.seal[Any]
val equality = eq.seal[Equality[_]]

'{
  val _left   = ~left
  val _right  = ~right
  val _result = ~fun(_left).===(_right)(~equality)
  val _bool = Bool.binaryMacroBool(_left, ~op.toExpr, _right, _result, ~prettifier)
  Assertions.assertionsHelper.macroAssert(_bool, ~clue, ~pos)
}

Note that in the implemetation, we used the syntax for method type: (Any)Equalizer[_].

Or, we can provide tree constructors (Related #5438):

// How to do overloading resolution for `===`?
def result(l: Expr[Any], r: Expr[Any]) = 
  fn.appliedTo(l.unseal).select("===").appliedTo(r.unseal).appliedTo(eq.unseal).seal[Boolean]
val left = lhs.seal[Any]
val right = rhs.seal[Any]

'{
  val _left   = ~left
  val _right  = ~right
  val _result = ~result(_left, _right)
  val _bool = Bool.binaryMacroBool(_left, ~op.toExpr, _right, _result, ~prettifier)
  Assertions.assertionsHelper.macroAssert(_bool, ~clue, ~pos)
}

However, the constructor-approach is inferior: in the quote-approach overloading resolution is a given for free, while in the constructor-approach it will be a burden on macro authors or the constructors have to do overloading resolution. AFAIK, the latter is not in the scope of #5438, @nicolasstucki mentioned adapation should be avoided in constructors.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions