Skip to content

Commit a2b523a

Browse files
xeno-byadriaanm
authored andcommitted
blackbox restriction #1: can't refine the official return type
When an application of a blackbox macro expands into a tree `x`, the expansion is wrapped into a type ascription `(x: T)`, where `T` is the declared return type of the blackbox macro with type arguments and path dependencies applied in consistency with the particular macro application being expanded. This invalidates blackbox macros as an implementation vehicle of type providers.
1 parent ce37ae4 commit a2b523a

File tree

19 files changed

+89
-31
lines changed

19 files changed

+89
-31
lines changed

src/compiler/scala/tools/nsc/typechecker/Macros.scala

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -604,21 +604,27 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
604604
*/
605605
def macroExpandApply(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Tree = {
606606
object expander extends TermMacroExpander(APPLY_ROLE, typer, expandee, mode, pt) {
607-
override def onSuccess(expanded: Tree) = {
607+
override def onSuccess(expanded0: Tree) = {
608+
def approximate(tp: Type) = {
609+
// approximation is necessary for whitebox macros to guide type inference
610+
// read more in the comments for onDelayed below
611+
if (isBlackbox(expandee)) tp
612+
else {
613+
val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
614+
deriveTypeWithWildcards(undetparams)(tp)
615+
}
616+
}
617+
val macroPt = approximate(if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe)
618+
val expanded = if (isBlackbox(expandee)) atPos(enclosingMacroPosition.focus)(Typed(expanded0, TypeTree(macroPt))) else expanded0
619+
608620
// prematurely annotate the tree with a macro expansion attachment
609621
// so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup
610622
linkExpandeeAndExpanded(expandee, expanded)
611-
// approximation is necessary for whitebox macros to guide type inference
612-
// read more in the comments for onDelayed below
613-
def approximate(tp: Type) = {
614-
val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
615-
deriveTypeWithWildcards(undetparams)(tp)
616-
}
617-
val macroPtApprox = approximate(if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe)
623+
618624
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
619625
// therefore we need to re-enable the conversions back temporarily
620-
if (macroDebugVerbose) println(s"typecheck #1 (against macroPtApprox = $macroPtApprox): $expanded")
621-
val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, macroPtApprox))
626+
if (macroDebugVerbose) println(s"typecheck #1 (against macroPt = $macroPt): $expanded")
627+
val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, macroPt))
622628
if (expanded1.isErrorTyped) {
623629
if (macroDebugVerbose) println(s"typecheck #1 has failed: ${typer.context.reportBuffer.errors}")
624630
expanded1
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Test_2.scala:4: error: value x is not a member of Any
2+
println(Macros.foo.x)
3+
^
4+
one error found
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import scala.language.experimental.macros
2+
3+
object Macros {
4+
def impl(c: scala.reflect.macros.BlackboxContext) = {
5+
import c.universe._
6+
q"""
7+
trait Foo {
8+
def x = 2
9+
}
10+
new Foo {}
11+
"""
12+
}
13+
14+
def foo = macro impl
15+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Macros._
2+
3+
object Test extends App {
4+
println(Macros.foo.x)
5+
}

test/files/neg/t5903a/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
trait Tree
@@ -13,7 +13,7 @@ object NewQuasiquotes {
1313
}
1414

1515
object QuasiquoteMacros {
16-
def unapplyImpl(c: BlackboxContext)(t: c.Tree) = {
16+
def unapplyImpl(c: WhiteboxContext)(t: c.Tree) = {
1717
import c.universe._
1818
q"""
1919
new {

test/files/neg/t5903e/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
object Interpolation {
@@ -10,7 +10,7 @@ object Interpolation {
1010
}
1111

1212
object Macros {
13-
def unapplyImpl(c: BlackboxContext)(x: c.Tree) = {
13+
def unapplyImpl(c: WhiteboxContext)(x: c.Tree) = {
1414
import c.universe._
1515
q"""
1616
new {

test/files/run/macro-bodyexpandstoimpl/Impls_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import scala.language.experimental.macros
2-
import scala.reflect.macros.BlackboxContext
2+
import scala.reflect.macros.{BlackboxContext, WhiteboxContext}
33

44
object Impls {
55
def foo(c: BlackboxContext)(x: c.Expr[Int]) = x
66

77
def refToFoo(dummy: Int) = macro refToFoo_impl
8-
def refToFoo_impl(c: BlackboxContext)(dummy: c.Expr[Int]) = {
8+
def refToFoo_impl(c: WhiteboxContext)(dummy: c.Expr[Int]) = {
99
import c.universe._
1010
val body = Select(Ident(TermName("Impls")), TermName("foo"))
1111
val global = c.universe.asInstanceOf[scala.tools.nsc.Global]

test/files/run/macro-expand-unapply-a/Impls_Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22

33
object Helper {
44
def unapplySeq[T](x: List[T]): Option[Seq[T]] = List.unapplySeq[T](x)
55
}
66

77
object Macros {
8-
def impl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Expr[List[T]]) = {
8+
def impl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Expr[List[T]]) = {
99
c.universe.reify(Helper.unapplySeq(x.splice))
1010
}
1111

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
reflective compilation has failed:
22

33
type mismatch;
4-
found : Int(42)
4+
found : Int
55
required: String

test/files/run/macro-system-properties.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@ scala> object GrabContext {
1414
defined object GrabContext
1515

1616
scala> object Test { class C(implicit a: Any) { GrabContext.grab } }
17+
<console>:12: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
18+
object Test { class C(implicit a: Any) { GrabContext.grab } }
19+
^
1720
defined object Test
1821

1922
scala> object Test { class C(implicit a: Any) { GrabContext.grab } }
23+
<console>:12: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
24+
object Test { class C(implicit a: Any) { GrabContext.grab } }
25+
^
2026
defined object Test
2127

2228
scala>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
2
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.reflect.macros.WhiteboxContext
2+
import scala.language.experimental.macros
3+
4+
object Macros {
5+
def impl(c: WhiteboxContext) = {
6+
import c.universe._
7+
q"""
8+
trait Foo {
9+
def x = 2
10+
}
11+
new Foo {}
12+
"""
13+
}
14+
15+
def foo = macro impl
16+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Macros._
2+
3+
object Test extends App {
4+
println(Macros.foo.x)
5+
}

test/files/run/t5903a/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
trait Tree
@@ -13,7 +13,7 @@ object NewQuasiquotes {
1313
}
1414

1515
object QuasiquoteMacros {
16-
def unapplyImpl(c: BlackboxContext)(t: c.Tree) = {
16+
def unapplyImpl(c: WhiteboxContext)(t: c.Tree) = {
1717
import c.universe._
1818
q"""
1919
new {

test/files/run/t5903b/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
object Interpolation {
@@ -10,7 +10,7 @@ object Interpolation {
1010
}
1111

1212
object Macros {
13-
def unapplyImpl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Tree) = {
13+
def unapplyImpl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Tree) = {
1414
import c.universe._
1515
q"""
1616
new {

test/files/run/t5903c/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
object Interpolation {
@@ -10,7 +10,7 @@ object Interpolation {
1010
}
1111

1212
object Macros {
13-
def unapplyImpl[T: c.WeakTypeTag](c: BlackboxContext)(x: c.Tree) = {
13+
def unapplyImpl[T: c.WeakTypeTag](c: WhiteboxContext)(x: c.Tree) = {
1414
import c.universe._
1515
q"""
1616
new {

test/files/run/t5903d/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
object Interpolation {
@@ -10,7 +10,7 @@ object Interpolation {
1010
}
1111

1212
object Macros {
13-
def unapplyImpl(c: BlackboxContext)(x: c.Tree) = {
13+
def unapplyImpl(c: WhiteboxContext)(x: c.Tree) = {
1414
import c.universe._
1515
q"""
1616
new {

test/files/run/t5923a/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import scala.reflect.macros.BlackboxContext
1+
import scala.reflect.macros.WhiteboxContext
22
import language.experimental.macros
33

44
case class C[T](t: String)
@@ -7,7 +7,7 @@ object C {
77
}
88

99
object Macros {
10-
def impl[T](c: BlackboxContext)(ttag: c.WeakTypeTag[T]) = {
10+
def impl[T](c: WhiteboxContext)(ttag: c.WeakTypeTag[T]) = {
1111
import c.universe._
1212
val ttag0 = ttag;
1313
{

test/files/run/t5923c/Macros_1.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import language.experimental.macros
2-
import scala.reflect.macros.BlackboxContext
2+
import scala.reflect.macros.WhiteboxContext
33

44
trait Iso[T, U] {
55
def to(t : T) : U
@@ -8,7 +8,7 @@ trait Iso[T, U] {
88

99
object Iso {
1010
implicit def materializeIso[T, U]: Iso[T, U] = macro impl[T, U]
11-
def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: BlackboxContext): c.Expr[Iso[T, U]] = {
11+
def impl[T: c.WeakTypeTag, U: c.WeakTypeTag](c: WhiteboxContext): c.Expr[Iso[T, U]] = {
1212
import c.universe._
1313
import definitions._
1414
import Flag._

0 commit comments

Comments
 (0)