Skip to content

Commit 7415430

Browse files
committed
Merge pull request scala#2497 from scalamacros/topic/macro-qqq
easy way of writing not implemented macros
2 parents 988e27a + bc10715 commit 7415430

File tree

7 files changed

+66
-21
lines changed

7 files changed

+66
-21
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,6 +1307,11 @@ trait ContextErrors {
13071307
throw MacroBodyTypecheckException // don't call fail, because we don't need IS_ERROR
13081308
}
13091309

1310+
def MacroDefIsQmarkQmarkQmark() = {
1311+
macroLogVerbose("typecheck terminated unexpectedly: macro is ???")
1312+
throw MacroBodyTypecheckException
1313+
}
1314+
13101315
def MacroFeatureNotEnabled() = {
13111316
macroLogVerbose("typecheck terminated unexpectedly: language.experimental.macros feature is not enabled")
13121317
fail()

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

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
412412
// Phase II: typecheck the right-hand side of the macro def
413413
val typed = typecheckRhs(macroDdef.rhs)
414414
typed match {
415+
case MacroImplReference(_, meth, _) if meth == Predef_??? =>
416+
bindMacroImpl(macroDef, typed)
417+
MacroDefIsQmarkQmarkQmark()
415418
case MacroImplReference(owner, meth, targs) =>
416419
if (!meth.isMethod) MacroDefInvalidBodyError()
417420
if (!meth.isPublic) MacroImplNotPublicError()
@@ -521,26 +524,30 @@ trait Macros extends scala.tools.reflect.FastTrack with Traces {
521524
val methName = binding.methName
522525
macroLogVerbose(s"resolved implementation as $className.$methName")
523526

524-
// I don't use Scala reflection here, because it seems to interfere with JIT magic
525-
// whenever you instantiate a mirror (and not do anything with in, just instantiate), performance drops by 15-20%
526-
// I'm not sure what's the reason - for me it's pure voodoo
527-
// upd. my latest experiments show that everything's okay
528-
// it seems that in 2.10.1 we can easily switch to Scala reflection
529-
try {
530-
macroLogVerbose(s"loading implementation class: $className")
531-
macroLogVerbose(s"classloader is: ${ReflectionUtils.show(macroClassloader)}")
532-
val implObj = ReflectionUtils.staticSingletonInstance(macroClassloader, className)
533-
// relies on the fact that macro impls cannot be overloaded
534-
// so every methName can resolve to at maximum one method
535-
val implMeths = implObj.getClass.getDeclaredMethods.find(_.getName == methName)
536-
val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") }
537-
macroLogVerbose(s"successfully loaded macro impl as ($implObj, $implMeth)")
538-
args => implMeth.invoke(implObj, ((args.c +: args.others) map (_.asInstanceOf[AnyRef])): _*)
539-
} catch {
540-
case ex: Exception =>
541-
macroLogVerbose(s"macro runtime failed to load: ${ex.toString}")
542-
macroDef setFlag IS_ERROR
543-
null
527+
if (binding.className == Predef_???.owner.fullName.toString && binding.methName == Predef_???.name.encoded) {
528+
args => throw new AbortMacroException(args.c.enclosingPosition, "macro implementation is missing")
529+
} else {
530+
// I don't use Scala reflection here, because it seems to interfere with JIT magic
531+
// whenever you instantiate a mirror (and not do anything with in, just instantiate), performance drops by 15-20%
532+
// I'm not sure what's the reason - for me it's pure voodoo
533+
// upd. my latest experiments show that everything's okay
534+
// it seems that in 2.10.1 we can easily switch to Scala reflection
535+
try {
536+
macroLogVerbose(s"loading implementation class: $className")
537+
macroLogVerbose(s"classloader is: ${ReflectionUtils.show(macroClassloader)}")
538+
val implObj = ReflectionUtils.staticSingletonInstance(macroClassloader, className)
539+
// relies on the fact that macro impls cannot be overloaded
540+
// so every methName can resolve to at maximum one method
541+
val implMeths = implObj.getClass.getDeclaredMethods.find(_.getName == methName)
542+
val implMeth = implMeths getOrElse { throw new NoSuchMethodException(s"$className.$methName") }
543+
macroLogVerbose(s"successfully loaded macro impl as ($implObj, $implMeth)")
544+
args => implMeth.invoke(implObj, ((args.c +: args.others) map (_.asInstanceOf[AnyRef])): _*)
545+
} catch {
546+
case ex: Exception =>
547+
macroLogVerbose(s"macro runtime failed to load: ${ex.toString}")
548+
macroDef setFlag IS_ERROR
549+
null
550+
}
544551
}
545552
})
546553
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5792,7 +5792,7 @@ trait Typers extends Modes with Adaptations with Tags {
57925792
tree1
57935793
}
57945794

5795-
val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous))
5795+
val isMacroBodyOkay = !tree.symbol.isErroneous && !(tree1 exists (_.isErroneous)) && tree1 != EmptyTree
57965796
val shouldInheritMacroImplReturnType = ddef.tpt.isEmpty
57975797
if (isMacroBodyOkay && shouldInheritMacroImplReturnType) computeMacroDefTypeFromMacroImpl(ddef, tree1.symbol) else AnyClass.tpe
57985798
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
macro-qmarkqmarkqmark.scala:5: error: macro implementation is missing
2+
foo1
3+
^
4+
macro-qmarkqmarkqmark.scala:8: error: macros cannot be partially applied
5+
foo2
6+
^
7+
macro-qmarkqmarkqmark.scala:9: error: macro implementation is missing
8+
foo2(1)
9+
^
10+
macro-qmarkqmarkqmark.scala:12: error: macro implementation is missing
11+
foo3[Int]
12+
^
13+
four errors found
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import language.experimental.macros
2+
3+
object Macros {
4+
def foo1 = macro ???
5+
foo1
6+
7+
def foo2(x: Int) = macro ???
8+
foo2
9+
foo2(1)
10+
11+
def foo3[T] = macro ???
12+
foo3[Int]
13+
}

test/files/pos/macro-qmarkqmarkqmark.check

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import language.experimental.macros
2+
3+
object Macros {
4+
def foo1 = macro ???
5+
def foo2(x: Int) = macro ???
6+
def foo3[T] = macro ???
7+
}

0 commit comments

Comments
 (0)