Skip to content

Introduce Unliftable for Quasiquotes#3118

Closed
densh wants to merge 2 commits intoscala:masterfrom
densh:pr/unliftable
Closed

Introduce Unliftable for Quasiquotes#3118
densh wants to merge 2 commits intoscala:masterfrom
densh:pr/unliftable

Conversation

@densh
Copy link
Contributor

@densh densh commented Nov 10, 2013

This pr introduces a new Unliftable type class used by quasiquotes to extract custom data types out of trees:

  trait Unliftable[T] {
    def unapply(tree: Tree): Option[T]
  }

When an implicit value of Unliftable[T] is provided this means that user can extract value of T inside of the quasiquote pattern:

  case q"${x: T}" => 
    // body

Where this code is semantically equivalent to:

  case q"$x0" if implicitly[Unliftable[T]].unapply(x0).nonEmpty => 
    val x: T = implicitly[Unliftable[T]].unapply(x0).get
    // body

The major use-case for introduction of Unliftable is vast simplification of extraction of leaf values from the trees:

     val q"${x: Int} + ${y: Int}" = q"1 + 2"

Previously users had to resort to nesting manual tree subpatterns to extract such values:

     val q"${Literal(Constant(x: Int))} + ${Literal(Constant(y: Int))}" = q"1 + 2"

review by @retronym and @xeno-by

This commit introduces internal attachment that allows unapply macros to
be aware of their sub patterns and tweak their expansion depending
on that info.

At the moment this is not possible due to the way pattern macros are
expanded:

	case MacroPat(inner1, inner2) => ...

During type checking this will expand as

	MacroPat.unapply(<unapply-dummy>)

Meaning that macro can’t see inner1 and inner2 in it’s macroApplication.
To circumvent this we attach that info as an attachment to the dummy.
1. Refactor Holes slice of quasiquotes to make unliftable fit into
   the same framework; replace 3 entities: Holes, HoleTypes and Location
   with just a single Hole concept (equiv to previous Holes + HoleTypes)
   and some matchers over types (equiv to previous Locations);

2. Move Liftable trait inside of the cake; this is crucial to decrease
   boilerplate that is required to define liftable and to allow
   combining of liftables together with unliftables in the same class
   without pulling ones hair out;

3. Introduce Unliftable — a type class similar to liftable that lets
   users to extract custom data types out of trees with the help of
   straightforward type ascription syntax:

      val q“foo.bar(${baz: Baz})” = ...

   This will use Unliftable[Baz] to extract custom data type Baz out of
   a tree nested inside of the another tree. A simpler example would be
   extracting of constant values:

      val q”${x: Int} + ${y: Int}” = q”1 + 2”

4. Vastly increase number of standard liftables.
@densh
Copy link
Contributor Author

densh commented Nov 17, 2013

I've found a corner case that needs some more work

@densh densh closed this Nov 17, 2013
@som-snytt
Copy link
Contributor

I'm never on the cutting edge of anything, but I already have a commented

// next week, val q"${s: String}" = name.tree

on SO where I had nothing new to add.
http://stackoverflow.com/a/20029025/1296806

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants