Closed
Description
In implementing ScalaTest macros, I find two tree constructors are useful:
def selectApply(receiver: Term, name: Name, args: List[Term]): Term
def let(expr: Term)(body: Ident => Term): Term
The constructor selectApply
should do overloading resolution internally, but no other adapation (like inserting apply
nor implicits). The constructor let
allows creating bindings friendly.
The current implementation of assert
is as follows:
case Term.Apply(Term.Select(lhs, op), rhs :: Nil) =>
op match {
case "==" =>
val left = lhs.seal[Any]
val right = rhs.seal[Any]
'{
val _left = ~left
val _right = ~right
val _result = _left == _right
val _bool = Bool.binaryMacroBool(_left, ~op.toExpr, _right, _result, ~prettifier)
Assertions.assertionsHelper.macroAssert(_bool, ~clue, ~pos)
}
case ">" =>
// blocked by tasty constructors
// https://github.com/lampepfl/dotty/pull/5438
val left = lhs.seal[Int]
val right = rhs.seal[Int]
'{
val _left = ~left
val _right = ~right
val _result = _left > _right
val _bool = Bool.binaryMacroBool(_left, ~op.toExpr, _right, _result, ~prettifier)
Assertions.assertionsHelper.macroAssert(_bool, ~clue, ~pos)
}
With the two constructors, the implementation can be made more generic & simpler:
case Term.Apply(Term.Select(lhs, op), rhs :: Nil) =>
val res =
let(lhs) { left =>
let(rhs) { right =>
let(selectApply(left, op, right)) { result =>
val l = left.seal[Any]
val r = right.seal[Any]
val b = result.seal[Boolean]
'{
val _bool = Bool.binaryMacroBool(~l, ~op.toExpr, ~r, ~b, ~prettifier)
Assertions.assertionsHelper.macroAssert(_bool, ~clue, ~pos)
}
}
}
res.seal[Assertion]