Skip to content

Some useful tree constructors #5567

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

Closed
liufengyun opened this issue Dec 4, 2018 · 8 comments
Closed

Some useful tree constructors #5567

liufengyun opened this issue Dec 4, 2018 · 8 comments

Comments

@liufengyun
Copy link
Contributor

liufengyun commented Dec 4, 2018

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]
@nicolasstucki
Copy link
Contributor

Those should not be implemented in the core. They should be implemented in some library. The let abstraction is already in https://github.com/nicolasstucki/quoted-util

@smarter
Copy link
Member

smarter commented Dec 4, 2018

Those should not be implemented in the core. They should be implemented in some library.

Why ?

@liufengyun
Copy link
Contributor Author

@nicolasstucki Just checked https://github.com/nicolasstucki/quoted-util, it seems they are not tasty reflect util, but quote util. I assume implementing overloading resolution will be a challenge in library?

@nicolasstucki
Copy link
Contributor

Oh, yes. Those are not on trees. Though they are safer.

@liufengyun liufengyun mentioned this issue Dec 5, 2018
66 tasks
@nicolasstucki
Copy link
Contributor

@liufengyun
Copy link
Contributor Author

liufengyun commented Dec 19, 2018

The provided constructors are not enough:

  • We lack API to create let-bindings (val-bindings) dynamically
  • The way to support dynamic select on a term based on copy is awkward
  • The semantics of Select.copy is unspecified in the case of overloading

We cannot use quote to introduce the binding, because we do not know the type of lhs and rhs statically.

        case Term.Apply(sel @ Term.Select(lhs, op), rhs :: Nil) =>
          case ">" =>
            val Term.IsSelect(select) = sel
            def app(l: Expr[Any], r: Expr[Any]): Expr[Boolean] =
              Term.Apply(Term.Select.copy(select)(l.unseal, ">"), r.unseal :: Nil).seal[Boolean]

            val left = lhs.seal[???]
            val right = rhs.seal[???]
            '{
              val _left   = ~left
              val _right  = ~right
              val _result = ~app('_left, '_right)
              Bool.binaryMacroBool(_left, ~op.toExpr, _right, _result, ~prettifier)
            }

It will be really nice to have something like let and selectApply or equivalent as proposed in the issue.

@nicolasstucki
Copy link
Contributor

#5651 shows how to implement def let(expr: Term)(body: Ident => Term): Term in library code.

@liufengyun
Copy link
Contributor Author

Those should not be implemented in the core. They should be implemented in some library.

I think core and non-core are just a problem of separation, there are multiple ways to achieve the separation, e.g. different packages, not neccesarily in different libraries.

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

3 participants