Last active
December 30, 2015 16:29
-
-
Save xeno-by/7854812 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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