summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala2
-rw-r--r--src/compiler/scala/reflect/internal/StdAttachments.scala2
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala13
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala7
-rw-r--r--src/compiler/scala/reflect/internal/util/Collections.scala25
-rw-r--r--src/compiler/scala/reflect/reify/codegen/Types.scala2
-rw-r--r--src/compiler/scala/reflect/reify/phases/Reify.scala66
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala2
-rw-r--r--src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala3
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/IMain.scala10
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/Power.scala3
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala13
-rw-r--r--src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Analyzer.scala1
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Macros.scala161
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala6
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala24
-rw-r--r--test/files/presentation/callcc-interpreter/Runner.scala4
-rw-r--r--test/files/presentation/patmat.check36
-rw-r--r--test/files/presentation/patmat.flags3
-rw-r--r--test/files/presentation/patmat/Runner.scala11
-rw-r--r--test/files/presentation/patmat/src/PatMatTests.scala28
-rw-r--r--test/files/presentation/random.check3
-rw-r--r--test/pending/run/t5692.flags1
-rw-r--r--test/pending/run/t5692/Impls_Macros_1.scala9
-rw-r--r--test/pending/run/t5692/Test_2.scala4
29 files changed, 297 insertions, 158 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 2b6607e23e..d89e852124 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -103,7 +103,7 @@ trait Definitions extends reflect.api.StandardDefinitions {
getMemberMethod(valueClassCompanion(className.toTermName).moduleClass, methodName)
private def classesMap[T](f: Name => T) = symbolsMap(ScalaValueClassesNoUnit, f)
- private def symbolsMap[T](syms: List[Symbol], f: Name => T): Map[Symbol, T] = syms zip (syms map (x => f(x.name))) toMap
+ private def symbolsMap[T](syms: List[Symbol], f: Name => T): Map[Symbol, T] = mapFrom(syms)(x => f(x.name))
private def symbolsMapFilt[T](syms: List[Symbol], p: Name => Boolean, f: Name => T) = symbolsMap(syms filter (x => p(x.name)), f)
private def boxedName(name: Name) = sn.Boxed(name.toTypeName)
diff --git a/src/compiler/scala/reflect/internal/StdAttachments.scala b/src/compiler/scala/reflect/internal/StdAttachments.scala
index 488195b7dd..ae2ad87deb 100644
--- a/src/compiler/scala/reflect/internal/StdAttachments.scala
+++ b/src/compiler/scala/reflect/internal/StdAttachments.scala
@@ -7,6 +7,4 @@ trait StdAttachments {
self: SymbolTable =>
case class ReifyAttachment(original: Symbol)
-
- case class MacroAttachment(delayed: Boolean, context: Option[MacroContext])
} \ No newline at end of file
diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala
index 7d9dd282cf..9158c2a4d4 100644
--- a/src/compiler/scala/reflect/internal/SymbolTable.scala
+++ b/src/compiler/scala/reflect/internal/SymbolTable.scala
@@ -76,6 +76,19 @@ abstract class SymbolTable extends api.Universe
result
}
+ // For too long have we suffered in order to sort NAMES.
+ // I'm pretty sure there's a reasonable default for that.
+ // Notice challenge created by Ordering's invariance.
+ implicit def lowPriorityNameOrdering[T <: Names#Name]: Ordering[T] =
+ SimpleNameOrdering.asInstanceOf[Ordering[T]]
+
+ private object SimpleNameOrdering extends Ordering[Names#Name] {
+ def compare(n1: Names#Name, n2: Names#Name) = (
+ if (n1 eq n2) 0
+ else n1.toString compareTo n2.toString
+ )
+ }
+
/** Dump each symbol to stdout after shutdown.
*/
final val traceSymbolActivity = sys.props contains "scalac.debug.syms"
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 815a5c0710..2fe7dfda17 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -1509,7 +1509,8 @@ trait Types extends api.Types { self: SymbolTable =>
case tv: TypeVar => tvs += tv
case _ =>
}
- val varToParamMap: Map[Type, Symbol] = tvs map (tv => tv -> tv.origin.typeSymbol.cloneSymbol) toMap
+ val varToParamMap: Map[Type, Symbol] =
+ mapFrom[TypeVar, Type, Symbol](tvs.toList)(_.origin.typeSymbol.cloneSymbol)
val paramToVarMap = varToParamMap map (_.swap)
val varToParam = new TypeMap {
def apply(tp: Type) = varToParamMap get tp match {
@@ -3473,7 +3474,7 @@ trait Types extends api.Types { self: SymbolTable =>
case TypeRef(pre, sym, _) if sameLength(sym.typeParams, args) =>
val eparams = typeParamsToExistentials(sym)
val bounds = args map (TypeBounds upper _)
- (eparams, bounds).zipped foreach (_ setInfo _)
+ foreach2(eparams, bounds)(_ setInfo _)
newExistentialType(eparams, typeRef(pre, sym, eparams map (_.tpe)))
case _ =>
@@ -3655,7 +3656,7 @@ trait Types extends api.Types { self: SymbolTable =>
else owner.newValueParameter(name.toTermName)
paramStack = newParams :: paramStack
try {
- (newParams, ptypes).zipped foreach ((p, t) => p setInfo this(t))
+ foreach2(newParams, ptypes)((p, t) => p setInfo this(t))
val restpe1 = this(restpe)
if (isType) PolyType(newParams, restpe1)
else MethodType(newParams, restpe1)
diff --git a/src/compiler/scala/reflect/internal/util/Collections.scala b/src/compiler/scala/reflect/internal/util/Collections.scala
index 9e4ae1ca00..2e119f8ccc 100644
--- a/src/compiler/scala/reflect/internal/util/Collections.scala
+++ b/src/compiler/scala/reflect/internal/util/Collections.scala
@@ -70,6 +70,27 @@ trait Collections {
lb.toList
}
+ final def flatCollect[A, B](elems: List[A])(pf: PartialFunction[A, Traversable[B]]): List[B] = {
+ val lb = new ListBuffer[B]
+ for (x <- elems ; if pf isDefinedAt x)
+ lb ++= pf(x)
+
+ lb.toList
+ }
+
+ final def distinctBy[A, B](xs: List[A])(f: A => B): List[A] = {
+ val buf = new ListBuffer[A]
+ val seen = mutable.Set[B]()
+ xs foreach { x =>
+ val y = f(x)
+ if (!seen(y)) {
+ buf += x
+ seen += y
+ }
+ }
+ buf.toList
+ }
+
@tailrec final def flattensToEmpty(xss: Seq[Seq[_]]): Boolean = {
xss.isEmpty || xss.head.isEmpty && flattensToEmpty(xss.tail)
}
@@ -89,6 +110,10 @@ trait Collections {
xs find p getOrElse orElse
}
+ final def mapFrom[A, A1 >: A, B](xs: List[A])(f: A => B): Map[A1, B] = {
+ Map[A1, B](xs map (x => (x, f(x))): _*)
+ }
+
final def mapWithIndex[A, B](xs: List[A])(f: (A, Int) => B): List[B] = {
val lb = new ListBuffer[B]
var index = 0
diff --git a/src/compiler/scala/reflect/reify/codegen/Types.scala b/src/compiler/scala/reflect/reify/codegen/Types.scala
index 841ec61e60..8fa24c5b00 100644
--- a/src/compiler/scala/reflect/reify/codegen/Types.scala
+++ b/src/compiler/scala/reflect/reify/codegen/Types.scala
@@ -84,7 +84,7 @@ trait Types {
def spliceType(tpe: Type): Tree = {
// [Eugene] it seems that depending on the context the very same symbol can be either a spliceable tparam or a quantified existential. very weird!
- val quantified = currents collect { case ExistentialType(quantified, _) => quantified } flatMap identity
+ val quantified = currentQuantified
if (tpe.isSpliceable && !(quantified contains tpe.typeSymbol)) {
if (reifyDebug) println("splicing " + tpe)
diff --git a/src/compiler/scala/reflect/reify/phases/Reify.scala b/src/compiler/scala/reflect/reify/phases/Reify.scala
index a1ff486ed7..e03ff5832c 100644
--- a/src/compiler/scala/reflect/reify/phases/Reify.scala
+++ b/src/compiler/scala/reflect/reify/phases/Reify.scala
@@ -19,37 +19,47 @@ trait Reify extends Symbols
import definitions._
import treeInfo._
+ // `reify` looked so nice, I wanted to push the last bit of orthogonal
+ // logic out of it so you can see the improvement. There is no cost to
+ // wrapper methods of this form because the inliner will eliminate them,
+ // but they are very good at separating concerns like pushing/popping
+ // a stack, and they are great for composition and reuse.
+ //
+ // Also, please avoid public vars whenever possible.
+ private object reifyStack {
+ var currents: List[Any] = reifee :: Nil
+
+ @inline final def push[T](reifee: Any)(body: => T): T = {
+ currents ::= reifee
+ try body
+ finally currents = currents.tail
+ }
+ }
+ def currentQuantified = flatCollect(reifyStack.currents)({ case ExistentialType(quantified, _) => quantified })
+ def current = reifyStack.currents.head
+
/**
* Reifies any supported value.
* For internal use only, use ``reified'' instead.
*/
- var currents: List[Any] = reifee :: Nil
- def current = currents.head
- def reify(reifee: Any): Tree = {
- currents = reifee :: currents
- try {
- reifee match {
- // before adding some case here, in global scope, please, consider
- // whether it can be localized like reifyAnnotationInfo or reifyScope
- // this will help reification stay as sane as possible
- case sym: Symbol => reifySymRef(sym)
- case tpe: Type => reifyType(tpe)
- case name: Name => reifyName(name)
- case tree: Tree => reifyTree(tree)
- // disabled because this is a very special case that I plan to remove later
- // why do I dislike annotations? see comments to `reifyAnnotationInfo`
+ def reify(reifee: Any): Tree = reifyStack.push(reifee)(reifee match {
+ // before adding some case here, in global scope, please, consider
+ // whether it can be localized like reifyAnnotationInfo or reifyScope
+ // this will help reification stay as sane as possible
+ case sym: Symbol => reifySymRef(sym)
+ case tpe: Type => reifyType(tpe)
+ case name: Name => reifyName(name)
+ case tree: Tree => reifyTree(tree)
+ // disabled because this is a very special case that I plan to remove later
+ // why do I dislike annotations? see comments to `reifyAnnotationInfo`
// case ann: AnnotationInfo => reifyAnnotationInfo(ann)
- case pos: Position => reifyPosition(pos)
- case mods: mirror.Modifiers => reifyModifiers(mods)
- case xs: List[_] => reifyList(xs)
- case s: String => Literal(Constant(s))
- case v if isAnyVal(v) => Literal(Constant(v))
- case null => Literal(Constant(null))
- case _ =>
- throw new Error("reifee %s of type %s is not supported".format(reifee, reifee.getClass))
- }
- } finally {
- currents = currents.tail
- }
- }
+ case pos: Position => reifyPosition(pos)
+ case mods: mirror.Modifiers => reifyModifiers(mods)
+ case xs: List[_] => reifyList(xs)
+ case s: String => Literal(Constant(s))
+ case v if isAnyVal(v) => Literal(Constant(v))
+ case null => Literal(Constant(null))
+ case _ =>
+ throw new Error("reifee %s of type %s is not supported".format(reifee, reifee.getClass))
+ })
} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index ff58de5f12..5e5b09405c 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -2225,7 +2225,7 @@ abstract class GenICode extends SubComponent {
* jumps to the given basic block.
*/
def patch(code: Code) {
- val map = toPatch map (i => (i -> patch(i))) toMap;
+ val map = mapFrom(toPatch)(patch)
code.blocks foreach (_ subst map)
}
diff --git a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
index 99541ff4b4..9646ee1cf0 100644
--- a/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
+++ b/src/compiler/scala/tools/nsc/interactive/tests/core/CoreTestDefs.scala
@@ -90,8 +90,9 @@ private[tests] trait CoreTestDefs
compiler.askLinkPos(tree.symbol, source, r)
r.get match {
case Left(pos) =>
+ val resolvedPos = if (tree.symbol.pos.isDefined) tree.symbol.pos else pos
withResponseDelimiter {
- reporter.println("[response] found askHyperlinkPos for `" + tree.symbol.name + "` at " + format(pos) + " " + tree.symbol.sourceFile.name)
+ reporter.println("[response] found askHyperlinkPos for `" + tree.symbol.name + "` at " + format(resolvedPos) + " " + tree.symbol.sourceFile.name)
}
case Right(ex) =>
ex.printStackTrace()
diff --git a/src/compiler/scala/tools/nsc/interpreter/IMain.scala b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
index 3d77344091..a9c2ce0d09 100644
--- a/src/compiler/scala/tools/nsc/interpreter/IMain.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/IMain.scala
@@ -369,7 +369,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def flatName(id: String) = optFlatName(id) getOrElse id
def optFlatName(id: String) = requestForIdent(id) map (_ fullFlatName id)
- def allDefinedNames = definedNameMap.keys.toList sortBy (_.toString)
+ def allDefinedNames = definedNameMap.keys.toList.sorted
def pathToType(id: String): String = pathToName(newTypeName(id))
def pathToTerm(id: String): String = pathToName(newTermName(id))
def pathToName(name: Name): String = {
@@ -1007,9 +1007,8 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
def lookupTypeOf(name: Name) = typeOf.getOrElse(name, typeOf(global.encode(name.toString)))
def simpleNameOfType(name: TypeName) = (compilerTypeOf get name) map (_.typeSymbol.simpleName)
- private def typeMap[T](f: Type => T): Map[Name, T] = {
- termNames ++ typeNames map (x => x -> f(cleanMemberDecl(resultSymbol, x))) toMap
- }
+ private def typeMap[T](f: Type => T) =
+ mapFrom[Name, Name, T](termNames ++ typeNames)(x => f(cleanMemberDecl(resultSymbol, x)))
/** Types of variables defined by this request. */
lazy val compilerTypeOf = typeMap[Type](x => x) withDefaultValue NoType
@@ -1024,8 +1023,7 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
typeNames.map(x => x -> compilerTypeOf(x).typeSymbol)
).toMap[Name, Symbol] withDefaultValue NoSymbol
- lazy val typesOfDefinedTerms: Map[Name, Type] =
- termNames map (x => x -> applyToResultMember(x, _.tpe)) toMap
+ lazy val typesOfDefinedTerms = mapFrom[Name, Name, Type](termNames)(x => applyToResultMember(x, _.tpe))
/** load and run the code using reflection */
def loadAndRun: (String, Boolean) = {
diff --git a/src/compiler/scala/tools/nsc/interpreter/Power.scala b/src/compiler/scala/tools/nsc/interpreter/Power.scala
index 01ace0e984..659caad1e1 100644
--- a/src/compiler/scala/tools/nsc/interpreter/Power.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/Power.scala
@@ -231,7 +231,7 @@ class Power[ReplValsImpl <: ReplVals : TypeTag](val intp: IMain, replVals: ReplV
def shortClass = erasure.getName split "[$.]" last
def baseClasses = tpe.baseClasses
- def baseClassDecls = baseClasses map (x => (x, x.info.decls.toList.sortBy(_.name.toString))) toMap
+ def baseClassDecls = mapFrom(baseClasses)(_.info.decls.toList.sortBy(_.name))
def ancestors = baseClasses drop 1
def ancestorDeclares(name: String) = ancestors filter (_.info member newTermName(name) ne NoSymbol)
def baseTypes = tpe.baseTypeSeq.toList
@@ -362,7 +362,6 @@ class Power[ReplValsImpl <: ReplVals : TypeTag](val intp: IMain, replVals: ReplV
else if (s1 isLess s2) -1
else 1
}
- implicit lazy val powerNameOrdering: Ordering[Name] = Ordering[String] on (_.toString)
implicit lazy val powerSymbolOrdering: Ordering[Symbol] = Ordering[Name] on (_.name)
implicit lazy val powerTypeOrdering: Ordering[Type] = Ordering[Symbol] on (_.typeSymbol)
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
index 52648380ec..192cc94b90 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/Pickler.scala
@@ -62,9 +62,16 @@ abstract class Pickler extends SubComponent {
// when we pickle it: so let's report an error instead. We know next
// to nothing about what happened, but our supposition is a lot better
// than "bad type: <error>" in terms of explanatory power.
- for (t <- unit.body ; if t.isErroneous) {
- unit.error(t.pos, "erroneous or inaccessible type")
- return
+ for (t <- unit.body) {
+ if (t.isErroneous) {
+ unit.error(t.pos, "erroneous or inaccessible type")
+ return
+ }
+
+ if (!t.isDef && t.hasSymbol && t.symbol.isTermMacro) {
+ unit.error(t.pos, "macro has not been expanded")
+ return
+ }
}
pickle(unit.body)
diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
index ff671088ac..1fb7fac184 100644
--- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
+++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala
@@ -820,7 +820,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers {
// concise printing of type env
private def pp(env: TypeEnv): String = {
- env.toList.sortBy(_._1.name.toString) map {
+ env.toList.sortBy(_._1.name) map {
case (k, v) =>
val vsym = v.typeSymbol
if (k == vsym) "" + k.name
diff --git a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
index 18c7635b1e..a77df71312 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Analyzer.scala
@@ -24,6 +24,7 @@ trait Analyzer extends AnyRef
with NamesDefaults
with TypeDiagnostics
with ContextErrors
+ with StdAttachments
{
val global : Global
import global._
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 1612253dd6..0d7ef71193 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -831,7 +831,7 @@ trait Implicits {
/** Returns all eligible ImplicitInfos and their SearchResults in a map.
*/
- def findAll() = (eligible map (info => (info, typedImplicit(info, false)))).toMap
+ def findAll() = mapFrom(eligible)(typedImplicit(_, false))
/** Returns the SearchResult of the best match.
*/
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
index ef9bae700e..6d4c543a5a 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala
@@ -294,8 +294,6 @@ trait Macros { self: Analyzer =>
} finally {
openMacros = openMacros.tail
}
- case Delay(result) =>
- result
case Fallback(fallback) =>
typer.typed1(fallback, EXPRmode, WildcardType)
case Other(result) =>
@@ -828,7 +826,7 @@ trait Macros { self: Analyzer =>
case _ =>
}
collectMacroArgs(expandee)
- val context = expandee.attachmentOpt[MacroAttachment].flatMap(_.context).getOrElse(macroContext(typer, prefixTree, expandee))
+ val context = expandee.attachmentOpt[MacroAttachment].flatMap(_.macroContext).getOrElse(macroContext(typer, prefixTree, expandee))
var argss: List[List[Any]] = List(context) :: exprArgs.toList
macroTrace("argss: ")(argss)
@@ -1007,18 +1005,6 @@ trait Macros { self: Analyzer =>
} finally {
openMacros = openMacros.tail
}
- case Delay(expandee) =>
- // need to save the context to preserve enclosures
- macroArgs(typer, expandee) match {
- case Some((context: MacroContext) :: _) =>
- // adapting here would be premature, we must wait until undetparams are inferred
- expandee withAttachment MacroAttachment(delayed = true, context = Some(context))
- case _ =>
- // !!! The correct place to issue an error needs to be clarified.
- // I have the else condition here only as a fallback.
- if (expandee.isErroneous) expandee
- else fail("macros cannot be partially applied", expandee)
- }
case Fallback(fallback) =>
typer.context.withImplicitsEnabled(typer.typed(fallback, EXPRmode, pt))
case Other(result) =>
@@ -1032,8 +1018,8 @@ trait Macros { self: Analyzer =>
private sealed abstract class MacroExpansionResult extends Product with Serializable
private case class Success(expanded: Tree) extends MacroExpansionResult
private case class Fallback(fallback: Tree) extends MacroExpansionResult
- private case class Delay(expandee: Tree) extends MacroExpansionResult
private case class Other(result: Tree) extends MacroExpansionResult
+ private def Delay(expanded: Tree) = Other(expanded)
private def Skip(expanded: Tree) = Other(expanded)
private def Cancel(expandee: Tree) = Other(expandee)
private def Failure(expandee: Tree) = Other(expandee)
@@ -1086,75 +1072,78 @@ trait Macros { self: Analyzer =>
if (!wasDelayed) {
if (macroDebug || macroCopypaste) println("typechecking macro expansion %s at %s".format(expandee, expandee.pos))
- if (nowDelayed) {
- if (macroDebug || macroCopypaste) println("macro expansion is delayed: %s".format(expandee))
- delayed += expandee -> (typer.context, undetparams)
- Delay(expandee)
- } else {
- val args = macroArgs(typer, expandee)
- args match {
- case Some(args) =>
- // adding stuff to openMacros is easy, but removing it is a nightmare
- // it needs to be sprinkled over several different code locations
- val (context: MacroContext) :: _ = args
- openMacros = context :: openMacros
- val expanded: MacroExpansionResult = try {
- val prevNumErrors = reporter.ERROR.count
- expandee.detach(null)
- val expanded = runtime(args)
- val currNumErrors = reporter.ERROR.count
- if (currNumErrors != prevNumErrors) {
- fail(typer, expandee) // errors have been reported by the macro itself
- } else {
- expanded match {
- case expanded: Expr[_] =>
- if (macroDebug || macroCopypaste) {
- if (macroDebug) println("original:")
- println(expanded.tree)
- println(showRaw(expanded.tree))
- }
-
- freeTerms(expanded.tree) foreach (fte => typer.context.error(expandee.pos,
- ("macro expansion contains free term variable %s %s. "+
- "have you forgot to use eval when splicing this variable into a reifee? " +
- "if you have troubles tracking free term variables, consider using -Xlog-free-terms").format(fte.name, fte.origin)))
- freeTypes(expanded.tree) foreach (fty => typer.context.error(expandee.pos,
- ("macro expansion contains free type variable %s %s. "+
- "have you forgot to use c.TypeTag annotation for this type parameter? " +
- "if you have troubles tracking free type variables, consider using -Xlog-free-types").format(fty.name, fty.origin)))
-
- val currNumErrors = reporter.ERROR.count
- if (currNumErrors != prevNumErrors) {
- fail(typer, expandee)
- } else {
- // inherit the position from the first position-ful expandee in macro callstack
- // this is essential for sane error messages
- var tree = expanded.tree
- var position = openMacros.find(c => c.expandee.pos != NoPosition).map(_.expandee.pos).getOrElse(NoPosition)
- tree = atPos(position.focus)(tree)
-
- // now macro expansion gets typechecked against the macro definition return type
- // however, this happens in macroExpand, not here in macroExpand1
- Success(tree)
- }
- case expanded if expanded.isInstanceOf[Expr[_]] =>
- val msg = "macro must return a compiler-specific expr; returned value is Expr, but it doesn't belong to this compiler's universe"
- fail(typer, expandee, msg)
- case expanded =>
- val msg = "macro must return a compiler-specific expr; returned value is of class: %s".format(expanded.getClass)
- fail(typer, expandee, msg)
+ val args = macroArgs(typer, expandee)
+ args match {
+ case Some(args) =>
+ val (context: MacroContext) :: _ = args
+ if (nowDelayed) {
+ if (macroDebug || macroCopypaste) println("macro expansion is delayed: %s".format(expandee))
+ delayed += expandee -> undetparams
+ // need to save typer context for `macroExpandAll`
+ // need to save macro context to preserve enclosures
+ expandee attach MacroAttachment(delayed = true, typerContext = typer.context, macroContext = Some(context))
+ Delay(expandee)
+ } else {
+ val expanded: MacroExpansionResult =
+ try {
+ val prevNumErrors = reporter.ERROR.count
+ openMacros = context :: openMacros
+ val expanded = runtime(args)
+ val currNumErrors = reporter.ERROR.count
+ if (currNumErrors != prevNumErrors) {
+ fail(typer, expandee) // errors have been reported by the macro itself
+ } else {
+ expanded match {
+ case expanded: Expr[_] =>
+ if (macroDebug || macroCopypaste) {
+ if (macroDebug) println("original:")
+ println(expanded.tree)
+ println(showRaw(expanded.tree))
+ }
+
+ freeTerms(expanded.tree) foreach (fte => typer.context.error(expandee.pos,
+ ("macro expansion contains free term variable %s %s. "+
+ "have you forgot to use eval when splicing this variable into a reifee? " +
+ "if you have troubles tracking free term variables, consider using -Xlog-free-terms").format(fte.name, fte.origin)))
+ freeTypes(expanded.tree) foreach (fty => typer.context.error(expandee.pos,
+ ("macro expansion contains free type variable %s %s. "+
+ "have you forgot to use c.TypeTag annotation for this type parameter? " +
+ "if you have troubles tracking free type variables, consider using -Xlog-free-types").format(fty.name, fty.origin)))
+
+ val currNumErrors = reporter.ERROR.count
+ if (currNumErrors != prevNumErrors) {
+ fail(typer, expandee)
+ } else {
+ // inherit the position from the first position-ful expandee in macro callstack
+ // this is essential for sane error messages
+ var tree = expanded.tree
+ var position = openMacros.find(c => c.expandee.pos != NoPosition).map(_.expandee.pos).getOrElse(NoPosition)
+ tree = atPos(position.focus)(tree)
+
+ // now macro expansion gets typechecked against the macro definition return type
+ // however, this happens in macroExpand, not here in macroExpand1
+ Success(tree)
+ }
+ case expanded if expanded.isInstanceOf[Expr[_]] =>
+ val msg = "macro must return a compiler-specific expr; returned value is Expr, but it doesn't belong to this compiler's universe"
+ fail(typer, expandee, msg)
+ case expanded =>
+ val msg = "macro must return a compiler-specific expr; returned value is of class: %s".format(expanded.getClass)
+ fail(typer, expandee, msg)
+ }
}
+ } catch {
+ case ex: Throwable =>
+ openMacros = openMacros.tail
+ throw ex
+ } finally {
+ expandee.detach(classOf[MacroAttachment])
}
- } catch {
- case ex: Throwable =>
- openMacros = openMacros.tail
- throw ex
- }
if (!expanded.isInstanceOf[Success]) openMacros = openMacros.tail
expanded
- case None =>
- fail(typer, expandee) // error has been reported by macroArgs
- }
+ }
+ case None =>
+ fail(typer, expandee) // error has been reported by macroArgs
}
} else {
if (nowDelayed)
@@ -1164,8 +1153,6 @@ trait Macros { self: Analyzer =>
}
} catch {
case ex => handleMacroExpansionException(typer, expandee, ex)
- } finally {
- expandee.detach(classOf[MacroAttachment])
}
private def macroExpandWithoutRuntime(typer: Typer, expandee: Tree): MacroExpansionResult = {
@@ -1261,10 +1248,10 @@ trait Macros { self: Analyzer =>
* 2) undetparams (sym.isTypeParameter && !sym.isSkolem)
*/
var hasPendingMacroExpansions = false
- private val delayed = perRunCaches.newWeakMap[Tree, (Context, collection.mutable.Set[Int])]
+ private val delayed = perRunCaches.newWeakMap[Tree, collection.mutable.Set[Int]]
private def isDelayed(expandee: Tree) = delayed contains expandee
private def calculateUndetparams(expandee: Tree): collection.mutable.Set[Int] =
- delayed.get(expandee).map(_._2).getOrElse {
+ delayed.get(expandee).getOrElse {
val calculated = collection.mutable.Set[Symbol]()
expandee foreach (sub => {
def traverse(sym: Symbol) = if (sym != null && (undetparams contains sym.id)) calculated += sym
@@ -1284,7 +1271,7 @@ trait Macros { self: Analyzer =>
if (macroDebug) (undetNoMore zip inferreds) foreach {case (sym, tpe) => println("undetParam inferred: %s as %s".format(sym, tpe))}
if (!delayed.isEmpty)
delayed.toList foreach {
- case (expandee, (_, undetparams)) if !undetparams.isEmpty =>
+ case (expandee, undetparams) if !undetparams.isEmpty =>
undetparams --= undetNoMore map (_.id)
if (undetparams.isEmpty) {
hasPendingMacroExpansions = true
@@ -1304,7 +1291,7 @@ trait Macros { self: Analyzer =>
override def transform(tree: Tree) = super.transform(tree match {
// todo. expansion should work from the inside out
case wannabe if (delayed contains wannabe) && calculateUndetparams(wannabe).isEmpty =>
- val (context, _) = delayed(wannabe)
+ val context = wannabe.attachment[MacroAttachment].typerContext
delayed -= wannabe
context.implicitsEnabled = typer.context.implicitsEnabled
context.enrichmentEnabled = typer.context.enrichmentEnabled
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
index 96d92e0609..e5dc8e9ca9 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatMatVirtualiser.scala
@@ -46,7 +46,7 @@ trait PatMatVirtualiser extends ast.TreeDSL { self: Analyzer =>
val outer = newTermName("<outer>")
val runOrElse = newTermName("runOrElse")
val zero = newTermName("zero")
- val _match = newTermName("__match") // don't call it __match, since that will trigger virtual pattern matching...
+ val _match = newTermName("__match") // don't call the val __match, since that will trigger virtual pattern matching...
def counted(str: String, i: Int) = newTermName(str+i)
}
@@ -1067,7 +1067,7 @@ class Foo(x: Other) { x._1 } // no error in this order
// assert(owner ne null); assert(owner ne NoSymbol)
def freshSym(pos: Position, tp: Type = NoType, prefix: String = "x") =
- NoSymbol.newTermSymbol(freshName(prefix), pos) setInfo /*repackExistential*/(tp)
+ NoSymbol.newTermSymbol(freshName(prefix), pos) setInfo tp
// codegen relevant to the structure of the translation (how extractors are combined)
trait AbsCodegen {
@@ -1141,7 +1141,7 @@ class Foo(x: Other) { x._1 } // no error in this order
val matchStrategy: Tree
def inMatchMonad(tp: Type): Type = appliedType(oneSig, List(tp)).finalResultType
- def pureType(tp: Type): Type = appliedType(oneSig, List(tp)).paramTypes.head
+ def pureType(tp: Type): Type = appliedType(oneSig, List(tp)).paramTypes.headOption getOrElse NoType // fail gracefully (otherwise we get crashes)
protected def matchMonadSym = oneSig.finalResultType.typeSymbol
import CODE._
diff --git a/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
new file mode 100644
index 0000000000..329a247106
--- /dev/null
+++ b/src/compiler/scala/tools/nsc/typechecker/StdAttachments.scala
@@ -0,0 +1,10 @@
+package scala.tools.nsc
+package typechecker
+
+import scala.reflect.makro.runtime.{Context => MacroContext}
+
+trait StdAttachments {
+ self: Analyzer =>
+
+ case class MacroAttachment(delayed: Boolean, typerContext: Context, macroContext: Option[MacroContext])
+} \ No newline at end of file
diff --git a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
index 4319dd10c7..a6a8d6009f 100644
--- a/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/TreeCheckers.scala
@@ -57,7 +57,7 @@ abstract class TreeCheckers extends Analyzer {
def prev = maps.init.last._2
def latest = maps.last._2
- def sortedNewSyms = newSyms.toList.distinct sortBy (_.name.toString)
+ def sortedNewSyms = newSyms.toList.distinct sortBy (_.name)
def inPrev(sym: Symbol) = {
(maps.size >= 2) && (prev contains sym)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 1414424a0b..934a7567d5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -83,6 +83,9 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
private def isPastTyper = phase.id > currentRun.typerPhase.id
+ // don't translate matches in presentation compiler: it loses vital symbols that are needed to do hyperlinking
+ @inline private def doMatchTranslation = !forInteractive && opt.virtPatmat && (phase.id < currentRun.uncurryPhase.id)
+
abstract class Typer(context0: Context) extends TyperDiagnostics with Adaptation with Tagging with TyperContextErrors {
import context0.unit
import typeDebug.{ ptTree, ptBlock, ptLine }
@@ -2436,7 +2439,7 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
fun.body match {
// later phase indicates scaladoc is calling (where shit is messed up, I tell you)
// -- so fall back to old patmat, which is more forgiving
- case Match(sel, cases) if opt.virtPatmat && (phase.id < currentRun.uncurryPhase.id) =>
+ case Match(sel, cases) if doMatchTranslation =>
// go to outer context -- must discard the context that was created for the Function since we're discarding the function
// thus, its symbol, which serves as the current context.owner, is not the right owner
// you won't know you're using the wrong owner until lambda lift crashes (unless you know better than to use the wrong owner)
@@ -3289,14 +3292,12 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
case tp => tp
}
- (hidden map { s =>
- // Hanging onto lower bound in case anything interesting
- // happens with it.
- (s, s.existentialBound match {
- case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s))
- case _ => hiBound(s)
- })
- }).toMap
+ // Hanging onto lower bound in case anything interesting
+ // happens with it.
+ mapFrom(hidden)(s => s.existentialBound match {
+ case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s))
+ case _ => hiBound(s)
+ })
}
/** Given a set `rawSyms` of term- and type-symbols, and a type
@@ -3830,7 +3831,7 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
}
def typedTranslatedMatch(tree: Tree, selector: Tree, cases: List[CaseDef]): Tree = {
- if (opt.virtPatmat && (phase.id < currentRun.uncurryPhase.id)) {
+ if (doMatchTranslation) {
if (selector ne EmptyTree) {
val (selector1, selectorTp, casesAdapted, ownType, doTranslation) = typedMatch(selector, cases, mode, pt)
typed(translatedMatch(selector1, selectorTp, casesAdapted, ownType, doTranslation), mode, pt)
@@ -4734,9 +4735,8 @@ trait Typers extends Modes with Adaptations with Taggings with PatMatVirtualiser
catches1 = catches1 map (adaptCase(_, mode, owntype))
}
- if((phase.id < currentRun.uncurryPhase.id) && opt.virtPatmat) {
+ if (doMatchTranslation)
catches1 = (MatchTranslator(this)).translateTry(catches1, owntype, tree.pos)
- }
treeCopy.Try(tree, block1, catches1, finalizer1) setType owntype
diff --git a/test/files/presentation/callcc-interpreter/Runner.scala b/test/files/presentation/callcc-interpreter/Runner.scala
index 61b6efd50d..1ef3cf9025 100644
--- a/test/files/presentation/callcc-interpreter/Runner.scala
+++ b/test/files/presentation/callcc-interpreter/Runner.scala
@@ -1,5 +1,3 @@
import scala.tools.nsc.interactive.tests._
-object Test extends InteractiveTest {
- settings.XoldPatmat.value = true // TODO: could this be running into some kind of race condition? sometimes the match has been translated, sometimes it hasn't
-} \ No newline at end of file
+object Test extends InteractiveTest \ No newline at end of file
diff --git a/test/files/presentation/patmat.check b/test/files/presentation/patmat.check
new file mode 100644
index 0000000000..29fd8b8e68
--- /dev/null
+++ b/test/files/presentation/patmat.check
@@ -0,0 +1,36 @@
+reload: PatMatTests.scala
+
+askHyperlinkPos for `CaseOne` at (12,18) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `CaseOne` at (5,12) PatMatTests.scala
+================================================================================
+
+askHyperlinkPos for `first` at (14,21) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `first` at (12,29) PatMatTests.scala
+================================================================================
+
+askHyperlinkPos for `tmp` at (15,19) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `tmp` at (13,13) PatMatTests.scala
+================================================================================
+
+askHyperlinkPos for `CaseTwo` at (17,18) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `CaseTwo` at (6,12) PatMatTests.scala
+================================================================================
+
+askHyperlinkPos for `mystring` at (18,24) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `mystring` at (17,25) PatMatTests.scala
+================================================================================
+
+askHyperlinkPos for `x` at (25,13) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `x` at (23,10) PatMatTests.scala
+================================================================================
+
+askHyperlinkPos for `y` at (25,21) PatMatTests.scala
+================================================================================
+[response] found askHyperlinkPos for `y` at (23,13) PatMatTests.scala
+================================================================================
diff --git a/test/files/presentation/patmat.flags b/test/files/presentation/patmat.flags
new file mode 100644
index 0000000000..468b48c9e3
--- /dev/null
+++ b/test/files/presentation/patmat.flags
@@ -0,0 +1,3 @@
+# This test will fail in the new pattern matcher because
+# it generates trees whose positions are not transparent
+-Xoldpatmat
diff --git a/test/files/presentation/patmat/Runner.scala b/test/files/presentation/patmat/Runner.scala
new file mode 100644
index 0000000000..3d19f2d948
--- /dev/null
+++ b/test/files/presentation/patmat/Runner.scala
@@ -0,0 +1,11 @@
+import scala.tools.nsc.interactive.tests.InteractiveTest
+
+object Test extends InteractiveTest {
+ override def runTests() {
+ // make sure typer is done.. the virtual pattern matcher might translate
+ // some trees and mess up positions. But we'll catch it red handed!
+ sourceFiles foreach (src => askLoadedTyped(src).get)
+ super.runTests()
+ }
+
+} \ No newline at end of file
diff --git a/test/files/presentation/patmat/src/PatMatTests.scala b/test/files/presentation/patmat/src/PatMatTests.scala
new file mode 100644
index 0000000000..bbd0f2e7ed
--- /dev/null
+++ b/test/files/presentation/patmat/src/PatMatTests.scala
@@ -0,0 +1,28 @@
+package patmat
+
+abstract class BaseType
+
+case class CaseOne(x: Int, y: List[Int]) extends BaseType
+case class CaseTwo(str: String) extends BaseType
+
+class PatMatTests {
+
+ def foo(x: BaseType) {
+ x match {
+ case CaseOne/*#*/(10, first :: second :: Nil) =>
+ val tmp = 23
+ println(first/*#*/)
+ println(tmp/*#*/)
+
+ case CaseTwo/*#*/(mystring) =>
+ println(mystring/*#*/)
+ }
+ }
+
+ def multipleAssign() {
+ val (x, y) = ("abc", "def")
+
+ println(x/*#*/, y/*#*/)
+ }
+
+} \ No newline at end of file
diff --git a/test/files/presentation/random.check b/test/files/presentation/random.check
index 1b73720312..fce4b69fb3 100644
--- a/test/files/presentation/random.check
+++ b/test/files/presentation/random.check
@@ -4,8 +4,7 @@ askType at Random.scala(18,14)
================================================================================
[response] askTypeAt at (18,14)
val filter: Int => Boolean = try {
- case <synthetic> val x1: Int = java.this.lang.Integer.parseInt(args.apply(0));
- x1 match {
+ java.this.lang.Integer.parseInt(args.apply(0)) match {
case 1 => ((x: Int) => x.%(2).!=(0))
case 2 => ((x: Int) => x.%(2).==(0))
case _ => ((x: Int) => x.!=(0))
diff --git a/test/pending/run/t5692.flags b/test/pending/run/t5692.flags
new file mode 100644
index 0000000000..cd66464f2f
--- /dev/null
+++ b/test/pending/run/t5692.flags
@@ -0,0 +1 @@
+-language:experimental.macros \ No newline at end of file
diff --git a/test/pending/run/t5692/Impls_Macros_1.scala b/test/pending/run/t5692/Impls_Macros_1.scala
new file mode 100644
index 0000000000..f9c1e5f12b
--- /dev/null
+++ b/test/pending/run/t5692/Impls_Macros_1.scala
@@ -0,0 +1,9 @@
+import scala.reflect.makro.Context
+
+object Impls {
+ def impl[A](c: reflect.makro.Context) = c.reify(())
+}
+
+object Macros {
+ def decl[A] = macro Impls.impl[A]
+} \ No newline at end of file
diff --git a/test/pending/run/t5692/Test_2.scala b/test/pending/run/t5692/Test_2.scala
new file mode 100644
index 0000000000..29251a5ef5
--- /dev/null
+++ b/test/pending/run/t5692/Test_2.scala
@@ -0,0 +1,4 @@
+object Test extends App {
+ val x = Macros.decl
+ def y() { Macros.decl(); }
+} \ No newline at end of file