Skip to content

Instantly share code, notes, and snippets.

@xeno-by
Last active December 30, 2015 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xeno-by/7854812 to your computer and use it in GitHub Desktop.
Save xeno-by/7854812 to your computer and use it in GitHub Desktop.
// As I mentioned before, macros can do everything that the compiler can do by judicious application of casts.
// Here we get a reference to a typechecker servicing the expansion and from it - to the list of lexical scopes.
// Having that information at hand, we can report the list of variables in both lexical and "this" scopes.
// Since casts are involved here, there's no guarantee that this will work even in-between minor releases of Scala.
// Therefore I would advise going this route only if there are no workarounds for your particular use case.
// Please feel free to email me to ask for workarounds (but please don't leave comments here, because I don't get notified about them)
import scala.reflect.macros.Context
import scala.language.experimental.macros
object LIST_STUFF_IN_SCOPE {
def impl(c: Context)() = {
import c.universe._
import scala.reflect.internal.Flags._
val chain = c.asInstanceOf[scala.reflect.macros.runtime.Context].callsiteTyper.context.enclosingContextChain
println("Context scopes: " + chain.flatMap(_.scope.toList.asInstanceOf[List[Symbol]]).distinct)
println("This scopes: " + chain.map(_.owner.asInstanceOf[Symbol]).distinct.flatMap(owner => {
val ownerx = owner.asInstanceOf[scala.reflect.internal.Symbols#Symbol]
if (ownerx.isPackage) Nil // package members are included in context scopes above
else if (!ownerx.isClass) Nil // we're interested only in classes and module classes (internal underlying classes of objects)
else if (ownerx.hasCompleteInfo) owner.typeSignature.declarations.toList // change this to `owner.members` if you want to see all inherited members
else { println("!! can't introspect the list of members of " + ownerx); Nil } // you can try to force typeSignature, but that might fail horribly
}))
c.literalUnit
}
def apply() = macro impl
}
class Person(firstName: String, lastName: String, age: Int) {
def fullName(implicit titleProvider: () => String): String = {
val title = titleProvider()
LIST_STUFF_IN_SCOPE()
s"$title $firstName $lastName"
}
}
09:50 ~/Projects/210x/sandbox (2.10.x)$ scalac Macros.scala && scalac Test.scala
warning: there were 1 feature warning(s); re-run with -feature for details
one warning found
Context scopes: List(value title, value titleProvider, class WrapperGenerator$1, object WrapperGenerator$1, class WrapperGenerator$AtomicType, object WrapperGenerator$AtomicType, class WrapperGenerator, object WrapperGenerator, class WrapperGenerator$FunctionType, object WrapperGenerator$FunctionType, class WrapperGenerator$BaseType, object WrapperGenerator$BaseType, class WrapperGenerator$StructType, object WrapperGenerator$StructType, anonymous class anonfun$impl$1, object anonfun$impl$1, anonymous class anonfun$impl$2, object anonfun$impl$2, anonymous class anonfun$impl$3, object anonfun$impl$3, class LIST_STUFF_IN_SCOPE$, object LIST_STUFF_IN_SCOPE$, class LIST_STUFF_IN_SCOPE, object LIST_STUFF_IN_SCOPE, class Person, package sun, package com, package java, package javax, package org, package apple, package sunw, package oracle, package jdk, package scala, package quicktime, package <empty>, package _root_)
This scopes: List(value firstName, value lastName, value age, constructor Person, method fullName)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment