From bd615c62ac4b03816d681a9a0fc717b5bc5d5cea Mon Sep 17 00:00:00 2001 From: Eugene Burmako Date: Tue, 10 Dec 2013 14:24:48 +0100 Subject: refactors macroExpandApply MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .../scala/tools/nsc/typechecker/Macros.scala | 62 ++++++++++++---------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index 27920dbd74..afefc39b0e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -600,39 +600,47 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { } /** Expands a term macro used in apply role as `M(2)(3)` in `val x = M(2)(3)`. + * @param outerPt Expected type that comes from enclosing context (something that's traditionally called `pt`). + * @param innerPt Expected type that comes from the signature of a macro def, possibly wildcarded to help type inference. * @see MacroExpander */ - def macroExpandApply(typer: Typer, expandee: Tree, mode: Mode, pt: Type): Tree = { - object expander extends TermMacroExpander(APPLY_ROLE, typer, expandee, mode, pt) { - override def onSuccess(expanded0: Tree) = { - def approximate(tp: Type) = { + def macroExpandApply(typer: Typer, expandee: Tree, mode: Mode, outerPt: Type): Tree = { + object expander extends TermMacroExpander(APPLY_ROLE, typer, expandee, mode, outerPt) { + lazy val innerPt = { + val tp = if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe + if (isBlackbox(expandee)) tp + else { // approximation is necessary for whitebox macros to guide type inference // read more in the comments for onDelayed below - if (isBlackbox(expandee)) tp + val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol } + deriveTypeWithWildcards(undetparams)(tp) + } + } + override def onSuccess(expanded0: Tree) = { + // prematurely annotate the tree with a macro expansion attachment + // so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup + linkExpandeeAndExpanded(expandee, expanded0) + + def typecheck(label: String, tree: Tree, pt: Type): Tree = { + if (tree.isErrorTyped) tree else { - val undetparams = tp collect { case tp if tp.typeSymbol.isTypeParameter => tp.typeSymbol } - deriveTypeWithWildcards(undetparams)(tp) + if (macroDebugVerbose) println(s"$label (against pt = $pt): $tree") + // `macroExpandApply` is called from `adapt`, where implicit conversions are disabled + // therefore we need to re-enable the conversions back temporarily + val result = typer.context.withImplicitsEnabled(typer.typed(tree, mode, pt)) + if (result.isErrorTyped && macroDebugVerbose) println(s"$label has failed: ${typer.context.reportBuffer.errors}") + result } } - val macroPt = approximate(if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe) - val expanded = if (isBlackbox(expandee)) atPos(enclosingMacroPosition.focus)(Typed(expanded0, TypeTree(macroPt))) else expanded0 - // prematurely annotate the tree with a macro expansion attachment - // so that adapt called indirectly by typer.typed knows that it needs to apply the existential fixup - linkExpandeeAndExpanded(expandee, expanded) - - // `macroExpandApply` is called from `adapt`, where implicit conversions are disabled - // therefore we need to re-enable the conversions back temporarily - if (macroDebugVerbose) println(s"typecheck #1 (against macroPt = $macroPt): $expanded") - val expanded1 = typer.context.withImplicitsEnabled(typer.typed(expanded, mode, macroPt)) - if (expanded1.isErrorTyped) { - if (macroDebugVerbose) println(s"typecheck #1 has failed: ${typer.context.reportBuffer.errors}") - expanded1 + if (isBlackbox(expandee)) { + val expanded1 = atPos(enclosingMacroPosition.focus)(Typed(expanded0, TypeTree(innerPt))) + val expanded2 = typecheck("blackbox typecheck #1", expanded1, innerPt) + typecheck("blackbox typecheck #2", expanded1, outerPt) } else { - if (macroDebugVerbose) println(s"typecheck #2 (against pt = $pt): $expanded1") - val expanded2 = typer.context.withImplicitsEnabled(super.onSuccess(expanded1)) - if (macroDebugVerbose && expanded2.isErrorTyped) println(s"typecheck #2 has failed: ${typer.context.reportBuffer.errors}") - expanded2 + val expanded1 = expanded0 + val expanded2 = typecheck("whitebox typecheck #1", expanded1, innerPt) + typecheck("whitebox typecheck #2", expanded2, outerPt) } } override def onDelayed(delayed: Tree) = { @@ -686,11 +694,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers { // Thanks to that the materializer can take a look at what's going on and react accordingly. val shouldInstantiate = typer.context.undetparams.nonEmpty && !mode.inPolyMode if (shouldInstantiate) { - if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, pt) + if (isBlackbox(expandee)) typer.instantiatePossiblyExpectingUnit(delayed, mode, outerPt) else { forced += delayed - typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), pt, keepNothings = false) - macroExpandApply(typer, delayed, mode, pt) + typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), outerPt, keepNothings = false) + macroExpandApply(typer, delayed, mode, outerPt) } } else delayed } -- cgit v1.2.3