summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2014-02-16 16:45:27 +0100
committerJason Zaugg <jzaugg@gmail.com>2014-02-16 16:45:27 +0100
commit6ef6c96eff2f0d2f505d45a1436d73a960193076 (patch)
tree6df5b2255fb4e369059fae1f3efbfdbe9c1506c6 /src
parentd300fb6250dc0abdfb74194438bfc778446a9856 (diff)
parenta02e053a5dec134f7c7dc53a2c1091039218237d (diff)
downloadscala-6ef6c96eff2f0d2f505d45a1436d73a960193076.tar.gz
scala-6ef6c96eff2f0d2f505d45a1436d73a960193076.tar.bz2
scala-6ef6c96eff2f0d2f505d45a1436d73a960193076.zip
Merge pull request #3397 from xeno-by/ticket/5920
SI-5920 enables default and named args in macros
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/Printers.scala6
-rw-r--r--src/compiler/scala/tools/nsc/settings/ScalaSettings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala28
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala93
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala4
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala3
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala19
-rw-r--r--src/compiler/scala/tools/reflect/ToolBoxFactory.scala17
-rw-r--r--src/reflect/scala/reflect/api/Printers.scala16
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala3
-rw-r--r--src/reflect/scala/reflect/internal/StdNames.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala12
-rw-r--r--src/reflect/scala/reflect/internal/TreeInfo.scala15
-rw-r--r--src/reflect/scala/reflect/internal/settings/MutableSettings.scala1
-rw-r--r--src/reflect/scala/reflect/runtime/Settings.scala1
16 files changed, 135 insertions, 89 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Printers.scala b/src/compiler/scala/tools/nsc/ast/Printers.scala
index c64b18207a..f3def3c80c 100644
--- a/src/compiler/scala/tools/nsc/ast/Printers.scala
+++ b/src/compiler/scala/tools/nsc/ast/Printers.scala
@@ -178,9 +178,9 @@ trait Printers extends scala.reflect.internal.Printers { this: Global =>
}
}
- def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymkinds)
- def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymkinds)
- def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true)
+ def asString(t: Tree): String = render(t, newStandardTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymowners, settings.Yshowsymkinds)
+ def asCompactString(t: Tree): String = render(t, newCompactTreePrinter, settings.printtypes, settings.uniqid, settings.Yshowsymowners, settings.Yshowsymkinds)
+ def asCompactDebugString(t: Tree): String = render(t, newCompactTreePrinter, true, true, true, true)
def newStandardTreePrinter(writer: PrintWriter): TreePrinter = new TreePrinter(writer)
def newCompactTreePrinter(writer: PrintWriter): CompactTreePrinter = new CompactTreePrinter(writer)
diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
index a3114a3d7b..a385a31165 100644
--- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
+++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala
@@ -168,6 +168,7 @@ trait ScalaSettings extends AbsScalaSettings
= BooleanSetting ("-Yshow-trees-stringified", "(Requires -Xprint:) Print stringifications along with detailed ASTs.")
val Yshowsyms = BooleanSetting ("-Yshow-syms", "Print the AST symbol hierarchy after each phase.")
val Yshowsymkinds = BooleanSetting ("-Yshow-symkinds", "Print abbreviated symbol kinds next to symbol names.")
+ val Yshowsymowners = BooleanSetting ("-Yshow-symowners", "Print owner identifiers next to symbol names.")
val skip = PhasesSetting ("-Yskip", "Skip")
val Ygenjavap = StringSetting ("-Ygen-javap", "dir", "Generate a parallel output directory of .javap files.", "")
val Ygenasmp = StringSetting ("-Ygen-asmp", "dir", "Generate a parallel output directory of .asmp files (ie ASM Textifier output).", "")
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 2043eb5d5d..40b97394f2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -501,10 +501,6 @@ trait ContextErrors {
}
// doTypeApply
- //tryNamesDefaults
- def NamedAndDefaultArgumentsNotSupportedForMacros(tree: Tree, fun: Tree) =
- NormalTypeError(tree, "macro applications do not support named and/or default arguments")
-
def TooManyArgsNamesDefaultsError(tree: Tree, fun: Tree) =
NormalTypeError(tree, "too many arguments for "+treeSymTypeMsg(fun))
@@ -603,12 +599,11 @@ trait ContextErrors {
//adapt
def MissingArgsForMethodTpeError(tree: Tree, meth: Symbol) = {
+ val errorExplanation = "missing arguments for " + meth.fullLocationString
+ val suggestPartialApplication = ";\nfollow this method with `_' if you want to treat it as a partially applied function"
val message =
- if (meth.isMacro) MacroTooFewArgumentListsMessage
- else "missing arguments for " + meth.fullLocationString + (
- if (meth.isConstructor) ""
- else ";\nfollow this method with `_' if you want to treat it as a partially applied function"
- )
+ if (meth.isMacro || meth.isConstructor) errorExplanation
+ else errorExplanation + suggestPartialApplication
issueNormalTypeError(tree, message)
setError(tree)
}
@@ -748,15 +743,12 @@ trait ContextErrors {
throw MacroExpansionException
}
- private def MacroTooFewArgumentListsMessage = "too few argument lists for macro invocation"
- def MacroTooFewArgumentListsError(expandee: Tree) = macroExpansionError2(expandee, MacroTooFewArgumentListsMessage)
-
- private def MacroTooManyArgumentListsMessage = "too many argument lists for macro invocation"
- def MacroTooManyArgumentListsError(expandee: Tree) = macroExpansionError2(expandee, MacroTooManyArgumentListsMessage)
-
- def MacroTooFewArgumentsError(expandee: Tree) = macroExpansionError2(expandee, "too few arguments for macro invocation")
-
- def MacroTooManyArgumentsError(expandee: Tree) = macroExpansionError2(expandee, "too many arguments for macro invocation")
+ def MacroFastTrackFailed(expandee: Tree) = {
+ // here we speculate that the reason why FastTrackEntry.validate failed is the lack arguments for a given method
+ // that's not ideal, but on the other hand this allows us to keep FastTrack simple without hooking errorgen into it
+ MissingArgsForMethodTpeError(expandee, expandee.symbol)
+ throw MacroExpansionException
+ }
def MacroGeneratedAbort(expandee: Tree, ex: AbortMacroException) = {
// errors have been reported by the macro itself, so we do nothing here
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index 677c94e063..1f90dd4939 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -353,7 +353,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
new {
val universe: self.global.type = self.global
val callsiteTyper: universe.analyzer.Typer = typer.asInstanceOf[global.analyzer.Typer]
- val expandee = universe.analyzer.macroExpanderAttachment(expandeeTree).original orElse duplicateAndKeepPositions(expandeeTree)
+ val expandee = universe.analyzer.macroExpanderAttachment(expandeeTree).desugared orElse duplicateAndKeepPositions(expandeeTree)
} with UnaffiliatedMacroContext {
val prefix = Expr[Nothing](prefixTree)(TypeTag.Nothing)
override def toString = "MacroContext(%s@%s +%d)".format(expandee.symbol.name, expandee.pos, enclosingMacros.length - 1 /* exclude myself */)
@@ -371,7 +371,15 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
def standardMacroArgs(typer: Typer, expandee: Tree): MacroArgs = {
val macroDef = expandee.symbol
val paramss = macroDef.paramss
- val treeInfo.Applied(core, targs, argss) = expandee
+ val treeInfo.Applied(core, targs, maybeNamedArgss) = expandee
+ val argss = map2(maybeNamedArgss, paramss)((args, params) => {
+ if (args.exists(_.isInstanceOf[AssignOrNamedArg])) {
+ val sorted = ListBuffer.fill(params.length)(EmptyTree: Tree)
+ args foreach { case AssignOrNamedArg(Ident(name), arg) => sorted(params.indexWhere(_.name == name)) = arg }
+ sorted.toList
+ } else if (params.length == args.length) args
+ else args ++ List.fill(params.length - args.length)(EmptyTree)
+ })
val prefix = core match { case Select(qual, _) => qual; case _ => EmptyTree }
val context = expandee.attachments.get[MacroRuntimeAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefix, expandee))
@@ -383,16 +391,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
|paramss: $paramss
""".trim)
- import typer.TyperErrorGen._
- val isNullaryArgsEmptyParams = argss.isEmpty && paramss == ListOfNil
- if (paramss.length < argss.length) MacroTooManyArgumentListsError(expandee)
- if (paramss.length > argss.length && !isNullaryArgsEmptyParams) MacroTooFewArgumentListsError(expandee)
-
val macroImplArgs: List[Any] =
if (fastTrack contains macroDef) {
// Take a dry run of the fast track implementation
if (fastTrack(macroDef) validate expandee) argss.flatten
- else MacroTooFewArgumentListsError(expandee)
+ else typer.TyperErrorGen.MacroFastTrackFailed(expandee)
}
else {
def calculateMacroArgs(binding: MacroImplBinding) = {
@@ -403,14 +406,6 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
// wrap argss in c.Expr if necessary (i.e. if corresponding macro impl param is of type c.Expr[T])
// expand varargs (nb! varargs can apply to any parameter section, not necessarily to the last one)
val trees = map3(argss, paramss, signature)((args, defParams, implParams) => {
- val isVarargs = isVarArgsList(defParams)
- if (isVarargs) {
- if (defParams.length > args.length + 1) MacroTooFewArgumentsError(expandee)
- } else {
- if (defParams.length < args.length) MacroTooManyArgumentsError(expandee)
- if (defParams.length > args.length) MacroTooFewArgumentsError(expandee)
- }
-
val wrappedArgs = mapWithIndex(args)((arg, j) => {
val fingerprint = implParams(min(j, implParams.length - 1))
fingerprint match {
@@ -421,7 +416,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
}
})
- if (isVarargs) {
+ if (isVarArgsList(defParams)) {
val (normal, varargs) = wrappedArgs splitAt (defParams.length - 1)
normal :+ varargs // pack all varargs into a single Seq argument (varargs Scala style)
} else wrappedArgs
@@ -529,9 +524,11 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
* the expandee with an error marker set if there has been an error
*/
abstract class MacroExpander(val typer: Typer, val expandee: Tree) {
+ val symbol = expandee match { case Block(_, expr) => expr.symbol; case tree => tree.symbol }
+
def onSuccess(expanded: Tree): Tree
def onFallback(expanded: Tree): Tree
- def onSuppressed(expandee: Tree): Tree = expandee
+ def onSuppressed(expanded: Tree): Tree = expanded
def onDelayed(expanded: Tree): Tree = expanded
def onSkipped(expanded: Tree): Tree = expanded
def onFailure(expanded: Tree): Tree = { typer.infer.setError(expandee); expandee }
@@ -551,15 +548,15 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
if (Statistics.canEnable) Statistics.incCounter(macroExpandCount)
try {
withInfoLevel(nodePrinters.InfoLevel.Quiet) { // verbose printing might cause recursive macro expansions
- if (expandee.symbol.isErroneous || (expandee exists (_.isErroneous))) {
- val reason = if (expandee.symbol.isErroneous) "not found or incompatible macro implementation" else "erroneous arguments"
+ if (symbol.isErroneous || (expandee exists (_.isErroneous)) || (desugared exists (_.isErroneous))) {
+ val reason = if (symbol.isErroneous) "not found or incompatible macro implementation" else "erroneous arguments"
macroLogVerbose(s"cancelled macro expansion because of $reason: $expandee")
onFailure(typer.infer.setError(expandee))
} else try {
val expanded = {
- val runtime = macroRuntime(expandee)
- if (runtime != null) macroExpandWithRuntime(typer, expandee, runtime)
- else macroExpandWithoutRuntime(typer, expandee)
+ val runtime = macroRuntime(desugared)
+ if (runtime != null) macroExpandWithRuntime(typer, desugared, runtime)
+ else macroExpandWithoutRuntime(typer, desugared)
}
expanded match {
case Success(expanded) =>
@@ -591,7 +588,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
extends MacroExpander(typer, expandee) {
lazy val innerPt = {
val tp = if (isNullaryInvocation(expandee)) expandee.tpe.finalResultType else expandee.tpe
- if (isBlackbox(expandee)) tp
+ if (isBlackbox(symbol)) tp
else {
// approximation is necessary for whitebox macros to guide type inference
// read more in the comments for onDelayed below
@@ -599,6 +596,50 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
deriveTypeWithWildcards(undetparams)(tp)
}
}
+ override protected def expand(desugared: Tree) = {
+ // SI-5940 in order for a macro expansion that involves named or default arguments
+ // to see the actual prefix and arguments being passed by the user instead of their desugarings
+ // we need to inline synthetics in case when `fun` is actually a macro
+ // underlying macro implementation is going to get explicitly passed arguments in correct order
+ // and the rest (defaults filled in by the vanilla part of `tryNamesDefaults`) will become empty trees
+ // in order for the macro to be able to account for evaluation order, the original is provided in `c.macroApplication`
+ // of course, ideally we would like to provide the impl with right-hand sides of those default arguments
+ // but currently that is flat out impossible because of the difference in scopes
+ // anyway this is already an improvement over the former status quo when named/default invocations were outright prohibited
+ def undoNamesDefaults(tree: Tree): Tree = {
+ val (qualsym, qual, vdefs0, app @ Applied(_, _, argss)) = tree match {
+ case Block((qualdef @ ValDef(_, name, _, qual)) +: vdefs, app) if name.startsWith(nme.QUAL_PREFIX) => (qualdef.symbol, qual, vdefs, app)
+ case Block(vdefs, app) => (NoSymbol, EmptyTree, vdefs, app)
+ case tree => (NoSymbol, EmptyTree, Nil, tree)
+ }
+ val vdefs = vdefs0.map{ case vdef: ValDef => vdef }
+ def hasNamesDefaults(args: List[Tree]) = {
+ args.exists(arg => isDefaultGetter(arg) || vdefs.exists(_.symbol == arg.symbol))
+ }
+ def undoNamesDefaults(args: List[Tree], depth: Int) = {
+ def extractRhs(vdef: ValDef) = vdef.rhs.changeOwner(vdef.symbol -> typer.context.owner)
+ case class Arg(tree: Tree, ipos: Int, inamed: Int) { val param = app.symbol.paramss(depth)(ipos) }
+ val indexed = args.map(arg => arg -> vdefs.indexWhere(_.symbol == arg.symbol)).zipWithIndex.flatMap({
+ /* default */ case ((arg, _), _) if isDefaultGetter(arg) => None
+ /* positional */ case ((arg, -1), ipos) => Some(Arg(arg, ipos, -1))
+ /* default+named */ case ((_, inamed), _) if isDefaultGetter(extractRhs(vdefs(inamed))) => None
+ /* named */ case ((arg, inamed), ipos) => Some(Arg(extractRhs(vdefs(inamed)), ipos, inamed))
+ })
+ if (indexed.forall(_.inamed == -1)) indexed.map(_.tree)
+ else indexed.sortBy(_.inamed).map(arg => AssignOrNamedArg(Ident(arg.param.name), arg.tree))
+ }
+ def loop(tree: Tree, depth: Int): Tree = tree match {
+ case Apply(fun, args) if hasNamesDefaults(args) => treeCopy.Apply(tree, loop(fun, depth - 1), undoNamesDefaults(args, depth))
+ case Apply(fun, args) => treeCopy.Apply(tree, loop(fun, depth - 1), args)
+ case TypeApply(core, targs) => treeCopy.TypeApply(tree, core, targs)
+ case Select(core, name) if qualsym != NoSymbol && core.symbol == qualsym => treeCopy.Select(tree, qual, name)
+ case core => core
+ }
+ if (app.symbol == null || app.symbol == NoSymbol || app.exists(_.isErroneous)) tree
+ else loop(app, depth = argss.length - 1)
+ }
+ super.expand(undoNamesDefaults(desugared))
+ }
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
@@ -616,7 +657,7 @@ trait Macros extends FastTrack with MacroRuntimes with Traces with Helpers {
}
}
- if (isBlackbox(expandee)) {
+ if (isBlackbox(symbol)) {
val expanded1 = atPos(enclosingMacroPosition.makeTransparent)(Typed(expanded0, TypeTree(innerPt)))
typecheck("blackbox typecheck", expanded1, outerPt)
} else {
@@ -678,7 +719,7 @@ 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, outerPt)
+ if (isBlackbox(symbol)) typer.instantiatePossiblyExpectingUnit(delayed, mode, outerPt)
else {
forced += delayed
typer.infer.inferExprInstance(delayed, typer.context.extractUndetparams(), outerPt, keepNothings = false)
diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
index 6a4df415ae..dceb0a47d8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
@@ -162,7 +162,7 @@ trait NamesDefaults { self: Analyzer =>
// never used for constructor calls, they always have a stable qualifier
def blockWithQualifier(qual: Tree, selected: Name) = {
- val sym = blockTyper.context.owner.newValue(unit.freshTermName("qual$"), newFlags = ARTIFACT) setInfo uncheckedBounds(qual.tpe) setPos (qual.pos.makeTransparent)
+ val sym = blockTyper.context.owner.newValue(unit.freshTermName(nme.QUAL_PREFIX), newFlags = ARTIFACT) setInfo uncheckedBounds(qual.tpe) setPos (qual.pos.makeTransparent)
blockTyper.context.scope enter sym
val vd = atPos(sym.pos)(ValDef(sym, qual) setType NoType)
// it stays in Vegas: SI-5720, SI-5727
@@ -292,7 +292,7 @@ trait NamesDefaults { self: Analyzer =>
arg.tpe
}
).widen // have to widen or types inferred from literal defaults will be singletons
- val s = context.owner.newValue(unit.freshTermName(), arg.pos, newFlags = ARTIFACT) setInfo {
+ val s = context.owner.newValue(unit.freshTermName(nme.NAMEDARG_PREFIX), arg.pos, newFlags = ARTIFACT) setInfo {
val tp = if (byName) functionType(Nil, argTpe) else argTpe
uncheckedBounds(tp)
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
index 57f27a05fd..1a6d2f0011 100644
--- a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -85,6 +85,7 @@ trait StdAttachments {
tree match {
// see the comment to `isMacroExpansionSuppressed` to learn why we need
// a special traversal strategy here
+ case Block(_, expr) => unsuppressMacroExpansion(expr)
case Apply(fn, _) => unsuppressMacroExpansion(fn)
case TypeApply(fn, _) => unsuppressMacroExpansion(fn)
case _ => // do nothing
@@ -101,6 +102,8 @@ trait StdAttachments {
// we have to account for the fact that during typechecking an expandee might become wrapped,
// i.e. surrounded by an inferred implicit argument application or by an inferred type argument application.
// in that case the expandee itself will no longer be suppressed and we need to look at the core
+ // upd. we also need to allow for blocks, because that's what names and defaults are often desugared to
+ case Block(_, expr) => isMacroExpansionSuppressed(expr)
case Apply(fn, _) => isMacroExpansionSuppressed(fn)
case TypeApply(fn, _) => isMacroExpansionSuppressed(fn)
case _ => false
diff --git a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
index b801b644fb..71e6454931 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TypeDiagnostics.scala
@@ -525,7 +525,6 @@ trait TypeDiagnostics {
val unused = p.unusedTerms
unused foreach { defn: DefTree =>
val sym = defn.symbol
- val isDefaultGetter = sym.name containsName nme.DEFAULT_GETTER_STRING
val pos = (
if (defn.pos.isDefined) defn.pos
else if (sym.pos.isDefined) sym.pos
@@ -536,7 +535,7 @@ trait TypeDiagnostics {
)
val why = if (sym.isPrivate) "private" else "local"
val what = (
- if (isDefaultGetter) "default argument"
+ if (sym.isDefaultGetter) "default argument"
else if (sym.isConstructor) "constructor"
else if (sym.isVar || sym.isGetter && sym.accessed.isVar) "var"
else if (sym.isVal || sym.isGetter && sym.accessed.isVal) "val"
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index f4d2a2cea0..aadc8f5e3b 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1161,7 +1161,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
case mt: MethodType if mode.typingExprNotFunNotLhs && mt.isImplicit => // (4.1)
adaptToImplicitMethod(mt)
- case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode && !treeInfo.isMacroApplicationOrBlock(tree) =>
+ case mt: MethodType if mode.typingExprNotFunNotLhs && !hasUndetsInMonoMode =>
instantiateToMethodType(mt)
case _ =>
vanillaAdapt(tree)
@@ -3272,12 +3272,6 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
*/
def tryNamesDefaults: Tree = {
val lencmp = compareLengths(args, formals)
-
- def checkNotMacro() = {
- if (treeInfo.isMacroApplication(fun))
- tryTupleApply orElse duplErrorTree(NamedAndDefaultArgumentsNotSupportedForMacros(tree, fun))
- }
-
if (mt.isErroneous) duplErrTree
else if (mode.inPatternMode) {
// #2064
@@ -3296,18 +3290,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
else if (allArgsArePositional(argPos) && !isNamedApplyBlock(fun)) {
// if there's no re-ordering, and fun is not transformed, no need to transform
// more than an optimization, e.g. important in "synchronized { x = update-x }"
- checkNotMacro()
doTypedApply(tree, fun, namelessArgs, mode, pt)
} else {
- checkNotMacro()
- transformNamedApplication(Typer.this, mode, pt)(
- treeCopy.Apply(tree, fun, namelessArgs), argPos)
+ unsuppressMacroExpansion(transformNamedApplication(Typer.this, mode, pt)(
+ treeCopy.Apply(tree, suppressMacroExpansion(fun), namelessArgs), argPos))
}
} else {
// defaults are needed. they are added to the argument list in named style as
// calls to the default getters. Example:
// foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a))
- checkNotMacro()
// SI-8111 transformNamedApplication eagerly shuffles around the application to preserve
// evaluation order. During this process, it calls `changeOwner` on symbols that
@@ -3330,7 +3321,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
symsOwnedByContextOwner foreach (_.owner = context.owner)
}
- val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x)
+ val fun1 = transformNamedApplication(Typer.this, mode, pt)(suppressMacroExpansion(fun), x => x)
if (fun1.isErroneous) duplErrTree
else {
assert(isNamedApplyBlock(fun1), fun1)
@@ -3356,7 +3347,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// useful when a default doesn't match parameter type, e.g. def f[T](x:T="a"); f[Int]()
val note = "Error occurred in an application involving default arguments."
if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
- doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
+ unsuppressMacroExpansion(doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt))
} else {
rollbackNamesDefaultsOwnerChanges()
tryTupleApply orElse duplErrorTree(NotEnoughArgsError(tree, fun, missing))
diff --git a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
index d459b4f981..6fabac9fe8 100644
--- a/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
+++ b/src/compiler/scala/tools/reflect/ToolBoxFactory.scala
@@ -166,7 +166,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
def typecheck(expr: Tree, pt: Type, silent: Boolean, withImplicitViewsDisabled: Boolean, withMacrosDisabled: Boolean): Tree =
transformDuringTyper(expr, withImplicitViewsDisabled = withImplicitViewsDisabled, withMacrosDisabled = withMacrosDisabled)(
(currentTyper, expr) => {
- trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymkinds.value))
+ trace("typing (implicit views = %s, macros = %s): ".format(!withImplicitViewsDisabled, !withMacrosDisabled))(showAttributed(expr, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
currentTyper.silent(_.typed(expr, pt), reportAmbiguousErrors = false) match {
case analyzer.SilentResultValue(result) =>
trace("success: ")(showAttributed(result, true, true, settings.Yshowsymkinds.value))
@@ -181,7 +181,7 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
def inferImplicit(tree: Tree, pt: Type, isView: Boolean, silent: Boolean, withMacrosDisabled: Boolean, pos: Position): Tree =
transformDuringTyper(tree, withImplicitViewsDisabled = false, withMacrosDisabled = withMacrosDisabled)(
(currentTyper, tree) => {
- trace("inferring implicit %s (macros = %s): ".format(if (isView) "view" else "value", !withMacrosDisabled))(showAttributed(pt, true, true, settings.Yshowsymkinds.value))
+ trace("inferring implicit %s (macros = %s): ".format(if (isView) "view" else "value", !withMacrosDisabled))(showAttributed(pt, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
analyzer.inferImplicit(tree, pt, isView, currentTyper.context, silent, withMacrosDisabled, pos, (pos, msg) => throw ToolBoxError(msg))
})
@@ -239,10 +239,10 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
List(),
List(methdef),
NoPosition))
- trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymkinds.value))
+ trace("wrapped: ")(showAttributed(moduledef, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
val cleanedUp = resetAttrs(moduledef)
- trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymkinds.value))
+ trace("cleaned up: ")(showAttributed(cleanedUp, true, true, settings.Yshowsymowners.value, settings.Yshowsymkinds.value))
cleanedUp.asInstanceOf[ModuleDef]
}
@@ -290,19 +290,22 @@ abstract class ToolBoxFactory[U <: JavaUniverse](val u: U) { factorySelf =>
tree
}
- def showAttributed(artifact: Any, printTypes: Boolean = true, printIds: Boolean = true, printKinds: Boolean = false): String = {
+ def showAttributed(artifact: Any, printTypes: Boolean = true, printIds: Boolean = true, printOwners: Boolean = false, printKinds: Boolean = false): String = {
val saved1 = settings.printtypes.value
val saved2 = settings.uniqid.value
- val saved3 = settings.Yshowsymkinds.value
+ val saved3 = settings.Yshowsymowners.value
+ val saved4 = settings.Yshowsymkinds.value
try {
settings.printtypes.value = printTypes
settings.uniqid.value = printIds
+ settings.Yshowsymowners.value = printOwners
settings.Yshowsymkinds.value = printKinds
artifact.toString
} finally {
settings.printtypes.value = saved1
settings.uniqid.value = saved2
- settings.Yshowsymkinds.value = saved3
+ settings.Yshowsymowners.value = saved3
+ settings.Yshowsymkinds.value = saved4
}
}
diff --git a/src/reflect/scala/reflect/api/Printers.scala b/src/reflect/scala/reflect/api/Printers.scala
index 5bc92d3893..637fcd782e 100644
--- a/src/reflect/scala/reflect/api/Printers.scala
+++ b/src/reflect/scala/reflect/api/Printers.scala
@@ -142,6 +142,7 @@ trait Printers { self: Universe =>
def print(args: Any*)
protected var printTypes = false
protected var printIds = false
+ protected var printOwners = false
protected var printKinds = false
protected var printMirrors = false
protected var printPositions = false
@@ -149,6 +150,8 @@ trait Printers { self: Universe =>
def withoutTypes: this.type = { printTypes = false; this }
def withIds: this.type = { printIds = true; this }
def withoutIds: this.type = { printIds = false; this }
+ def withOwners: this.type = { printOwners = true; this }
+ def withoutOwners: this.type = { printOwners = false; this }
def withKinds: this.type = { printKinds = true; this }
def withoutKinds: this.type = { printKinds = false; this }
def withMirrors: this.type = { printMirrors = true; this }
@@ -169,12 +172,13 @@ trait Printers { self: Universe =>
}
/** @group Printers */
- protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = {
+ protected def render(what: Any, mkPrinter: PrintWriter => TreePrinter, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String = {
val buffer = new StringWriter()
val writer = new PrintWriter(buffer)
val printer = mkPrinter(writer)
printTypes.value.map(printTypes => if (printTypes) printer.withTypes else printer.withoutTypes)
printIds.value.map(printIds => if (printIds) printer.withIds else printer.withoutIds)
+ printOwners.value.map(printOwners => if (printOwners) printer.withOwners else printer.withoutOwners)
printKinds.value.map(printKinds => if (printKinds) printer.withKinds else printer.withoutKinds)
printMirrors.value.map(printMirrors => if (printMirrors) printer.withMirrors else printer.withoutMirrors)
printPositions.value.map(printPositions => if (printPositions) printer.withPositions else printer.withoutPositions)
@@ -193,8 +197,8 @@ trait Printers { self: Universe =>
*
* @group Printers
*/
- def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
- render(any, newTreePrinter(_), printTypes, printIds, printKinds, printMirrors, printPositions)
+ def show(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
+ render(any, newTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions)
/** Hook to define what `show(...)` means.
* @group Printers
@@ -219,14 +223,14 @@ trait Printers { self: Universe =>
* @group Printers
*/
protected def newCodePrinter(out: PrintWriter): TreePrinter
-
+
/** Renders internal structure of a reflection artifact as the
* visualization of a Scala syntax tree.
*
* @group Printers
*/
- def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
- render(any, newRawTreePrinter(_), printTypes, printIds, printKinds, printMirrors, printPositions)
+ def showRaw(any: Any, printTypes: BooleanFlag = None, printIds: BooleanFlag = None, printOwners: BooleanFlag = None, printKinds: BooleanFlag = None, printMirrors: BooleanFlag = None, printPositions: BooleanFlag = None): String =
+ render(any, newRawTreePrinter(_), printTypes, printIds, printOwners, printKinds, printMirrors, printPositions)
/** Hook to define what `showRaw(...)` means.
* @group Printers
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index 26db97b725..6734a2bd5a 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -65,6 +65,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
printTypes = settings.printtypes.value
printIds = settings.uniqid.value
+ printOwners = settings.Yshowsymowners.value
printKinds = settings.Yshowsymkinds.value
printMirrors = false // typically there's no point to print mirrors inside the compiler, as there is only one mirror there
printPositions = settings.Xprintpos.value
@@ -275,6 +276,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
printValueParams
print(" => ", body, ")")
if (printIds && tree.symbol != null) print("#" + tree.symbol.id)
+ if (printOwners && tree.symbol != null) print("@" + tree.symbol.owner.id)
}
protected def printSuper(tree: Super, resultName: => String) = {
@@ -1139,6 +1141,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
else if (sym.isStatic && (sym.isClass || sym.isModule)) print(sym.fullName)
else print(sym.name)
if (printIds) print("#", sym.id)
+ if (printOwners) print("@", sym.owner.id)
if (printKinds) print("#", sym.abbreviatedKindString)
if (printMirrors) print("%M", footnotes.put[scala.reflect.api.Mirror[_]](mirrorThatLoaded(sym)))
case tag: TypeTag[_] =>
diff --git a/src/reflect/scala/reflect/internal/StdNames.scala b/src/reflect/scala/reflect/internal/StdNames.scala
index 9fd2199c19..aad5f32b5f 100644
--- a/src/reflect/scala/reflect/internal/StdNames.scala
+++ b/src/reflect/scala/reflect/internal/StdNames.scala
@@ -308,6 +308,8 @@ trait StdNames {
val WHILE_PREFIX = "while$"
val FRESH_PREFIX = "fresh"
val FRESH_SUFFIX = "macro$" // uses a keyword to avoid collisions with mangled names
+ val QUAL_PREFIX = "qual$"
+ val NAMEDARG_PREFIX = "x$"
// Compiler internal names
val ANYname: NameType = "<anyname>"
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index c5c104a2fc..02616d1ba6 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -561,6 +561,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
def isConstructor = false
def isEarlyInitialized = false
def isGetter = false
+ def isDefaultGetter = false
def isLocalDummy = false
def isMixinConstructor = false
def isOverloaded = false
@@ -2477,14 +2478,14 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
* If !settings.debug translates expansions of operators back to operator symbol.
* E.g. $eq => =.
* If settings.uniqid, adds id.
+ * If settings.Yshowsymowners, adds owner's id
* If settings.Yshowsymkinds, adds abbreviated symbol kind.
*/
def nameString: String = {
val name_s = if (settings.debug.value) "" + unexpandedName else unexpandedName.dropLocal.decode
- val id_s = if (settings.uniqid.value) "#" + id else ""
val kind_s = if (settings.Yshowsymkinds.value) "#" + abbreviatedKindString else ""
- name_s + id_s + kind_s
+ name_s + idString + kind_s
}
def fullNameString: String = {
@@ -2498,7 +2499,11 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
}
/** If settings.uniqid is set, the symbol's id, else "" */
- final def idString = if (settings.uniqid.value) "#"+id else ""
+ final def idString = {
+ val id_s = if (settings.uniqid.value) "#"+id else ""
+ val owner_s = if (settings.Yshowsymowners.value) "@"+owner.id else ""
+ id_s + owner_s
+ }
/** String representation, including symbol's kind e.g., "class Foo", "method Bar".
* If hasMeaninglessName is true, uses the owner's name to disambiguate identity.
@@ -2650,6 +2655,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
override def isSetterParameter = isValueParameter && owner.isSetter
override def isAccessor = this hasFlag ACCESSOR
override def isGetter = isAccessor && !isSetter
+ override def isDefaultGetter = name containsName nme.DEFAULT_GETTER_STRING
override def isSetter = isAccessor && nme.isSetterName(name) // todo: make independent of name, as this can be forged.
override def isLocalDummy = nme.isLocalDummyName(name)
override def isClassConstructor = name == nme.CONSTRUCTOR
diff --git a/src/reflect/scala/reflect/internal/TreeInfo.scala b/src/reflect/scala/reflect/internal/TreeInfo.scala
index 8cad2497c1..0b42a8f9ac 100644
--- a/src/reflect/scala/reflect/internal/TreeInfo.scala
+++ b/src/reflect/scala/reflect/internal/TreeInfo.scala
@@ -281,6 +281,10 @@ abstract class TreeInfo {
}
}
+ def isDefaultGetter(tree: Tree) = {
+ tree.symbol != null && tree.symbol.isDefaultGetter
+ }
+
/** Is tree a self constructor call this(...)? I.e. a call to a constructor of the
* same object?
*/
@@ -864,13 +868,8 @@ abstract class TreeInfo {
case _ => false
})
- def isMacroApplication(tree: Tree): Boolean = !tree.isDef && {
- val sym = tree.symbol
- sym != null && sym.isTermMacro && !sym.isErroneous
- }
-
- def isMacroApplicationOrBlock(tree: Tree): Boolean = tree match {
- case Block(_, expr) => isMacroApplicationOrBlock(expr)
- case tree => isMacroApplication(tree)
+ def isMacroApplication(tree: Tree): Boolean = tree match {
+ case Block(_, expr) => isMacroApplication(expr)
+ case tree => !tree.isDef && tree.symbol != null && tree.symbol.isTermMacro && !tree.symbol.isErroneous
}
}
diff --git a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
index 816916787e..048fe9ef37 100644
--- a/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
+++ b/src/reflect/scala/reflect/internal/settings/MutableSettings.scala
@@ -39,6 +39,7 @@ abstract class MutableSettings extends AbsSettings {
def Xprintpos: BooleanSetting
def Yposdebug: BooleanSetting
def Yrangepos: BooleanSetting
+ def Yshowsymowners: BooleanSetting
def Yshowsymkinds: BooleanSetting
def breakCycles: BooleanSetting
def debug: BooleanSetting
diff --git a/src/reflect/scala/reflect/runtime/Settings.scala b/src/reflect/scala/reflect/runtime/Settings.scala
index de5ba99900..d46846fc21 100644
--- a/src/reflect/scala/reflect/runtime/Settings.scala
+++ b/src/reflect/scala/reflect/runtime/Settings.scala
@@ -36,6 +36,7 @@ private[reflect] class Settings extends MutableSettings {
val Xprintpos = new BooleanSetting(false)
val Yposdebug = new BooleanSetting(false)
val Yrangepos = new BooleanSetting(false)
+ val Yshowsymowners = new BooleanSetting(false)
val Yshowsymkinds = new BooleanSetting(false)
val breakCycles = new BooleanSetting(false)
val debug = new BooleanSetting(false)