Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// shadow sbt-scalajs' crossProject and CrossType until Scala.js 1.0.0 is released
import com.typesafe.tools.mima.core._
import sbtcrossproject.{crossProject, CrossType}

val previousVersion = "1.1.0"
Expand Down Expand Up @@ -33,6 +34,12 @@ lazy val `portable-scala-reflect` = crossProject(JSPlatform, JVMPlatform, Native

mimaPreviousArtifacts +=
organization.value %%% moduleName.value % previousVersion,
mimaBinaryIssueFilters ++= List(
/* Macros were moved to `internal` package so that `Reflect`'s metadata doesn't get polluted by types from `scala-reflect` */
ProblemFilters.exclude[DirectMissingMethodProblem]("org.portablescala.reflect.Reflect.lookupInstantiatableClass_impl"),
ProblemFilters.exclude[DirectMissingMethodProblem]("org.portablescala.reflect.Reflect.lookupLoadableModuleClass_impl"),
ProblemFilters.exclude[MissingClassProblem]("org.portablescala.reflect.Reflect$MacroCompat$*"),
),

publishMavenStyle := true,
publishTo := {
Expand Down
59 changes: 3 additions & 56 deletions jvm/src/main/scala/org/portablescala/reflect/Reflect.scala
Original file line number Diff line number Diff line change
@@ -1,33 +1,12 @@
package org.portablescala.reflect

import scala.language.experimental.macros

import scala.collection.mutable

import java.lang.reflect._

import org.portablescala.reflect.annotation._
import org.portablescala.reflect.internal.Macros

object Reflect {
/** Magic to get cross-compiling access to `blackbox.Context` with a fallback
* on `macros.Context`, without deprecation warning in any Scala version.
*/
private object MacroCompat {
object Scope1 {
object blackbox
}
import Scope1._

object Scope2 {
import scala.reflect.macros._
object Inner {
import blackbox._
type BlackboxContext = Context
}
}
}

import MacroCompat.Scope2.Inner.BlackboxContext

/** Reflectively looks up a loadable module class using the current class
* loader.
Expand All @@ -52,17 +31,7 @@ object Reflect {
* Fully-qualified name of the module class, including its trailing `$`
*/
def lookupLoadableModuleClass(fqcn: String): Option[LoadableModuleClass] =
macro lookupLoadableModuleClass_impl

def lookupLoadableModuleClass_impl(
c: BlackboxContext { type PrefixType = Reflect.type })(
fqcn: c.Expr[String]): c.Expr[Option[LoadableModuleClass]] = {
import c.universe._
val loaderExpr = currentClassLoaderExpr(c)
reify {
c.prefix.splice.lookupLoadableModuleClass(fqcn.splice, loaderExpr.splice)
}
}
macro Macros.lookupLoadableModuleClass

/** Reflectively looks up a loadable module class.
*
Expand Down Expand Up @@ -111,17 +80,7 @@ object Reflect {
* Fully-qualified name of the class
*/
def lookupInstantiatableClass(fqcn: String): Option[InstantiatableClass] =
macro lookupInstantiatableClass_impl

def lookupInstantiatableClass_impl(
c: BlackboxContext { type PrefixType = Reflect.type })(
fqcn: c.Expr[String]): c.Expr[Option[InstantiatableClass]] = {
import c.universe._
val loaderExpr = currentClassLoaderExpr(c)
reify {
c.prefix.splice.lookupInstantiatableClass(fqcn.splice, loaderExpr.splice)
}
}
macro Macros.lookupInstantiatableClass

/** Reflectively looks up an instantiatable class.
*
Expand All @@ -147,18 +106,6 @@ object Reflect {
load(fqcn, loader).filter(isInstantiatableClass).map(new InstantiatableClass(_))
}

private def currentClassLoaderExpr(
c: BlackboxContext { type PrefixType = Reflect.type }): c.Expr[ClassLoader] = {
import c.universe._
val enclosingClassTree = c.reifyEnclosingRuntimeClass
if (enclosingClassTree.isEmpty)
c.abort(c.enclosingPosition, "call site does not have an enclosing class")
val enclosingClassExpr = c.Expr[java.lang.Class[_]](enclosingClassTree)
reify {
enclosingClassExpr.splice.getClassLoader()
}
}

private def isModuleClass(clazz: Class[_]): Boolean = {
try {
val fld = clazz.getField("MODULE$")
Expand Down
63 changes: 63 additions & 0 deletions jvm/src/main/scala/org/portablescala/reflect/internal/Macros.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package org.portablescala.reflect.internal

import org.portablescala.reflect._

/* Macro definitions are enclosed in a dedicated `Macros` object,
* so that their metadata (the types involved etc.) don't pollute `Reflect`'s metadata.
* This enables using `Reflect`'s methods without `scala-reflect` JAR
* https://github.com/scala/bug/issues/8090
* https://github.com/xeno-by/sbt-example-paradise210/issues/1#issuecomment-20996354
*/
object Macros {
/** Magic to get cross-compiling access to `blackbox.Context` with a fallback
* on `macros.Context`, without deprecation warning in any Scala version.
*/
private object MacroCompat {
object Scope1 {
object blackbox
}
import Scope1._

object Scope2 {
import scala.reflect.macros._
object Inner {
import blackbox._
type BlackboxContext = Context
}
}
}

import MacroCompat.Scope2.Inner.BlackboxContext

private def currentClassLoaderExpr(
c: BlackboxContext { type PrefixType = Reflect.type }): c.Expr[ClassLoader] = {
import c.universe._
val enclosingClassTree = c.reifyEnclosingRuntimeClass
if (enclosingClassTree.isEmpty)
c.abort(c.enclosingPosition, "call site does not have an enclosing class")
val enclosingClassExpr = c.Expr[java.lang.Class[_]](enclosingClassTree)
reify {
enclosingClassExpr.splice.getClassLoader()
}
}

def lookupLoadableModuleClass(
c: BlackboxContext { type PrefixType = Reflect.type })(
fqcn: c.Expr[String]): c.Expr[Option[LoadableModuleClass]] = {
import c.universe._
val loaderExpr = currentClassLoaderExpr(c)
reify {
c.prefix.splice.lookupLoadableModuleClass(fqcn.splice, loaderExpr.splice)
}
}

def lookupInstantiatableClass(
c: BlackboxContext { type PrefixType = Reflect.type })(
fqcn: c.Expr[String]): c.Expr[Option[InstantiatableClass]] = {
import c.universe._
val loaderExpr = currentClassLoaderExpr(c)
reify {
c.prefix.splice.lookupInstantiatableClass(fqcn.splice, loaderExpr.splice)
}
}
}