Skip to content

Commit bd615c6

Browse files
committed
refactors macroExpandApply
Moves some code around to clearly define the concepts that the method operates on: 1) `innerPt`, which is expected type provided by the macro def return type, 2) `outerPt`, which is expected type provided by the enclosing context. Once everything is clearly defined, the gist of the expander fits in a few lines in its end. If blackbox, do this. If whitebox, do that. Note that unlike the subsequent commit, this commit doesn’t change the way how macro expansion works. It just clears everything out, so that the upcoming changes can be applied in a concise and comprehensible manner.
1 parent b345b42 commit bd615c6

File tree

1 file changed

+35
-27
lines changed

1 file changed

+35
-27
lines changed

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

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -600,39 +600,47 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
600600
}
601601

602602
/** Expands a term macro used in apply role as `M(2)(3)` in `val x = M(2)(3)`.
603+
* @param outerPt Expected type that comes from enclosing context (something that's traditionally called `pt`).
604+
* @param innerPt Expected type that comes from the signature of a macro def, possibly wildcarded to help type inference.
603605
* @see MacroExpander
604606
*/
605-
def macroExpandApply(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Tree = {
606-
object expander extends TermMacroExpander(APPLY_ROLE, typer, expandee, mode, pt) {
607-
override def onSuccess(expanded0: Tree) = {
608-
def approximate(tp: Type) = {
607+
def macroExpandApply(typer: Typer, expandee: Tree, mode: Mode, outerPt: Type): Tree = {
608+
object expander extends TermMacroExpander(APPLY_ROLE, typer, expandee, mode, outerPt) {
609+
lazy val innerPt = {
610+
val tp = if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe
611+
if (isBlackbox(expandee)) tp
612+
else {
609613
// approximation is necessary for whitebox macros to guide type inference
610614
// read more in the comments for onDelayed below
611-
if (isBlackbox(expandee)) tp
615+
val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
616+
deriveTypeWithWildcards(undetparams)(tp)
617+
}
618+
}
619+
override def onSuccess(expanded0: Tree) = {
620+
// prematurely annotate the tree with a macro expansion attachment
621+
// so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup
622+
linkExpandeeAndExpanded(expandee, expanded0)
623+
624+
def typecheck(label: String, tree: Tree, pt: Type): Tree = {
625+
if (tree.isErrorTyped) tree
612626
else {
613-
val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol }
614-
deriveTypeWithWildcards(undetparams)(tp)
627+
if (macroDebugVerbose) println(s"$label (against pt = $pt): $tree")
628+
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
629+
// therefore we need to re-enable the conversions back temporarily
630+
val result = typer.context.withImplicitsEnabled(typer.typed(tree, mode, pt))
631+
if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reportBuffer.errors}")
632+
result
615633
}
616634
}
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
619635

620-
// prematurely annotate the tree with a macro expansion attachment
621-
// so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup
622-
linkExpandeeAndExpanded(expandee, expanded)
623-
624-
// `macroExpandApply` is called from `adapt`, where implicit conversions are disabled
625-
// therefore we need to re-enable the conversions back temporarily
626-
if (macroDebugVerbose) println(s"typecheck #1 (against macroPt = $macroPt): $expanded")
627-
val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, macroPt))
628-
if (expanded1.isErrorTyped) {
629-
if (macroDebugVerbose) println(s"typecheck #1 has failed: ${typer.context.reportBuffer.errors}")
630-
expanded1
636+
if (isBlackbox(expandee)) {
637+
val expanded1 = atPos(enclosingMacroPosition.focus)(Typed(expanded0, TypeTree(innerPt)))
638+
val expanded2 = typecheck("blackbox typecheck #1", expanded1, innerPt)
639+
typecheck("blackbox typecheck #2", expanded1, outerPt)
631640
} else {
632-
if (macroDebugVerbose) println(s"typecheck #2 (against pt = $pt): $expanded1")
633-
val expanded2 = typer.context.withImplicitsEnabled(super.onSuccess(expanded1))
634-
if (macroDebugVerbose && expanded2.isErrorTyped) println(s"typecheck #2 has failed: ${typer.context.reportBuffer.errors}")
635-
expanded2
641+
val expanded1 = expanded0
642+
val expanded2 = typecheck("whitebox typecheck #1", expanded1, innerPt)
643+
typecheck("whitebox typecheck #2", expanded2, outerPt)
636644
}
637645
}
638646
override def onDelayed(delayed: Tree) = {
@@ -686,11 +694,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
686694
// Thanks to that the materializer can take a look at what's going on and react accordingly.
687695
val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode
688696
if (shouldInstantiate) {
689-
if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt)
697+
if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, outerPt)
690698
else {
691699
forced += delayed
692-
typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false)
693-
macroExpandApply(typer, delayed, mode, pt)
700+
typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), outerPt, keepNothings = false)
701+
macroExpandApply(typer, delayed, mode, outerPt)
694702
}
695703
} else delayed
696704
}

0 commit comments

Comments
 (0)