scala.reflect.macros.Context.enclosingPackage deprecated?

118 views
Skip to first unread message

Emanuel Jöbstl

unread,
Jul 16, 2014, 12:38:24 PM7/16/14
to scala...@googlegroups.com
Hello,

The scala compiler (2.11.0) gives me the following warning when using scala.reflect.macros.Context.enclosingPackage.

[warn] method enclosingPackage in trait Enclosures is deprecated: c.enclosingTree-style APIs are now deprecated; consult the scaladoc for more information

In the scala doc, however, the method is not marked as deprecated.

What am I supposed to use?

Thanks for all advice,
Emanuel

Eugene Burmako

unread,
Jul 17, 2014, 7:04:40 AM7/17/14
to Emanuel Jöbstl, scala-user
No idea what's up with the docs (I mean what version of Scala they point to), so I'll just link to the code directly.




--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Antoine Gourlay

unread,
Jul 17, 2014, 8:52:13 AM7/17/14
to Eugene Burmako, Emanuel Jöbstl, scala-user
That link is from an old (pre-2.11.0) nightly build that isn't updated anymore...

Here is the current (2.11.1) version, and the nightly version. It's all on the api docs page on scala-lang :)

--
Antoine
Message has been deleted

Emanuel Jöbstl

unread,
Jul 17, 2014, 3:20:13 PM7/17/14
to scala...@googlegroups.com, e...@eex-dev.net
Thank you for the hint.

The documentation states that I should use c.internal.enclosingOwner.

But how can I gather the AST from the symbol? Basically I try to find all ancestors of the expression undergoing macro expansion in the AST.


FYI: I landed on the outdated documentation via Google. While I am now aware to double-check the version in the future, it would be really nice to display the version or even add a version selector to the on-line doc.

Eugene Burmako

unread,
Jul 17, 2014, 3:37:50 PM7/17/14
to Emanuel Jöbstl, scala-user
Well, that's the sad part of this particular deprecation. As the doc says, we couldn't get enclosing ASTs to work robustly, and that's why we decided to phase this feature away. What's your use case? Maybe we could come up with a workaround together?


--

Emanuel Jöbstl

unread,
Jul 17, 2014, 4:16:11 PM7/17/14
to scala...@googlegroups.com, e...@eex-dev.net
My use case is finding all free variables, which are bound from an outer scope, within an anonymous function (call-by-value or call-by-name).

Consider the function findFreeVariables(fun: => Int): List[(String, Any)], which, when used, would return a list of the name and value of all free variables inside fun.

The approach is to make findFreeVariables a macro, which
  1. traverses the AST of the fun, finds all Idents and store the symbol in a set L
  2. traverses the AST of fun again and find all ancestors for each symbol in L
  3. for each symbol in L, check if one of the ancestors inside fun defines a symbol with the same name, if so, remove the corresponding symbol from L
  4. traverse the AST containing the call we are currently expanding and find all ancestors of our function
  5. for each ValDef found in the ancestors, put the corresponding symbol into a set K
  6. The intersection if L and K contains all free symbols of fun, which are bound from an outer scope and are var or vals.

Step 4 is the step where I used c.enclosingPackage so far. I can also provide  working (under certain circumstances) code for this approach. 

I already asked here on how to accomplish this task (https://groups.google.com/forum/#!topic/scala-user/CmoCZH2Rm0c). Johannes Rudolph suggested using the Idents, but sadly the Idents within fun do not indicate whether the term in question is a function or a val/var from an outer scope.

Thank you very much for your patience!

Eugene Burmako

unread,
Jul 19, 2014, 10:40:43 AM7/19/14
to Emanuel Jöbstl, scala-user
Could you give a few examples of input and output of the function that you're writing? In particular, what would be the result of the following:

Snippet 1
=======
object Test extends App {
  val x = 2
  println(findFreeVariables({ val y = 3; x + y }))
}

Snippet 2
=======
object Test extends App with X {
  println(findFreeVariables({ val y = 3; x + y }))
}
// `class X { val x = 2 }` is defined elsewhere

Snippet 3
=======
object Test extends App {
  import X._
  println(findFreeVariables({ val y = 3; x + y }))
}
// `object X { val x = 2 }` is defined elsewhere



--

Emanuel Jöbstl

unread,
Jul 19, 2014, 12:55:48 PM7/19/14
to scala...@googlegroups.com, e...@eex-dev.net
Sorry, I should have made clear that I have to rule out class or static variables, because they are not referenced by an Ident. This is okay for my use case, however.

Also, there still seem to be problems with call-by-name functions (func: => T): In some cases, the symbol of func is just null. Due to this, I am not able to locate the function in the enclosing tree (which breaks my approach).
Maybe you know a better solution for locating a certain tree in it's enclosing tree?

The following works fine:

def snip1() = {
  val x = 2
  println(
    findFreeVariables(() => {

      val y = 3;
      x + y
    })
  )
}


Output: List(x, 2)

The other snippets do not work.

I uploaded the code to GitHub, if it helps: https://github.com/emiswelt/ScalaMacros



Emanuel Jöbstl

unread,
Aug 14, 2014, 4:03:05 PM8/14/14
to scala...@googlegroups.com, e...@eex-dev.net
I have a working implementation now, without using enclosing trees. Call-by-name functions are also supported.

https://github.com/emiswelt/ScalaMacros

Thanks for the help.
Reply all
Reply to author
Forward
0 new messages