aboutsummaryrefslogtreecommitdiff
path: root/core/shared/src/main/scala/globalutil.scala
diff options
context:
space:
mode:
Diffstat (limited to 'core/shared/src/main/scala/globalutil.scala')
-rw-r--r--core/shared/src/main/scala/globalutil.scala59
1 files changed, 59 insertions, 0 deletions
diff --git a/core/shared/src/main/scala/globalutil.scala b/core/shared/src/main/scala/globalutil.scala
new file mode 100644
index 0000000..99dee77
--- /dev/null
+++ b/core/shared/src/main/scala/globalutil.scala
@@ -0,0 +1,59 @@
+package magnolia
+
+import scala.reflect.macros.{runtime, whitebox}
+import scala.tools.nsc.Global
+
+/** Workarounds that needs to use `nsc.Global`. */
+private[magnolia] object GlobalUtil {
+
+ // From Shapeless: https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/generic.scala#L698
+ // Cut-n-pasted (with most original comments) and slightly adapted from
+ // https://github.com/scalamacros/paradise/blob/c14c634923313dd03f4f483be3d7782a9b56de0e/plugin/src/main/scala/org/scalamacros/paradise/typechecker/Namers.scala#L568-L613
+ def patchedCompanionRef(c: whitebox.Context)(tpe: c.Type): c.Tree = {
+ // see https://github.com/scalamacros/paradise/issues/7
+ // also see https://github.com/scalamacros/paradise/issues/64
+
+ val global = c.universe.asInstanceOf[Global]
+ val typer = c.asInstanceOf[runtime.Context].callsiteTyper.asInstanceOf[global.analyzer.Typer]
+ val ctx = typer.context
+ val globalType = tpe.asInstanceOf[global.Type]
+ val original = globalType.typeSymbol
+ val owner = original.owner
+ val companion = original.companion.orElse {
+ import global.{ abort => aabort, _ }
+ implicit class PatchedContext(ctx: global.analyzer.Context) {
+ trait PatchedLookupResult { def suchThat(criterion: Symbol => Boolean): Symbol }
+ def patchedLookup(name: Name, expectedOwner: Symbol) = new PatchedLookupResult {
+ override def suchThat(criterion: Symbol => Boolean): Symbol = {
+ var res: Symbol = NoSymbol
+ var ctx = PatchedContext.this.ctx
+ while (res == NoSymbol && ctx.outer != ctx) {
+ // NOTE: original implementation says `val s = ctx.scope lookup name`
+ // but we can't use it, because Scope.lookup returns wrong results when the lookup is ambiguous
+ // and that triggers https://github.com/scalamacros/paradise/issues/64
+ val s = {
+ val lookupResult = ctx.scope.lookupAll(name).filter(criterion).toList
+ lookupResult match {
+ case Nil => NoSymbol
+ case List(unique) => unique
+ case _ => aabort(s"unexpected multiple results for a companion symbol lookup for $original#{$original.id}")
+ }
+ }
+ if (s != NoSymbol && s.owner == expectedOwner)
+ res = s
+ else
+ ctx = ctx.outer
+ }
+ res
+ }
+ }
+ }
+
+ ctx.patchedLookup(original.name.companionName, owner) suchThat { sym =>
+ (original.isTerm || sym.hasModuleFlag) && (sym isCoDefinedWith original)
+ }
+ }
+
+ global.gen.mkAttributedRef(globalType.prefix, companion).asInstanceOf[c.Tree]
+ }
+}