diff options
24 files changed, 178 insertions, 85 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 6cb935edad..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) @@ -493,8 +493,8 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val NoManifest = getRequiredModule("scala.reflect.NoManifest") lazy val ExprClass = getMember(getRequiredClass("scala.reflect.api.Exprs"), tpnme.Expr) - def ExprTree = getMemberClass(ExprClass, nme.tree) - def ExprTpe = getMemberClass(ExprClass, nme.tpe) + def ExprTree = getMember(ExprClass, nme.tree) + def ExprTpe = getMember(ExprClass, nme.tpe) def ExprEval = getMember(ExprClass, nme.eval) def ExprValue = getMember(ExprClass, nme.value) lazy val ExprModule = getMember(getRequiredClass("scala.reflect.api.Exprs"), nme.Expr) 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/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 48dfe8bcfc..f4878139e9 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -602,7 +602,7 @@ abstract class TreeInfo { object ReifiedTree { def unapply(tree: Tree): Option[(Tree, List[Tree], Tree, Tree)] = tree match { - case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(Apply(_, List(tree)), List(Apply(_, List(tpe))))) if mrDef.name == nme.MIRROR_SHORT => + case reifee @ Block((mrDef @ ValDef(_, _, _, _)) :: symbolTable, Apply(Apply(_, List(tree)), List(Apply(_, tpe :: _)))) if mrDef.name == nme.MIRROR_SHORT => Some(reifee, symbolTable, tree, tpe) case _ => None 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/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/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/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index c13be0e39d..2d1369b11d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -343,6 +343,11 @@ trait ContextErrors { issueNormalTypeError(tree, "macros cannot be eta-expanded") setError(tree) } + + def MacroPartialApplicationError(tree: Tree) = { + issueNormalTypeError(tree, "macros cannot be partially applied") + setError(tree) + } //typedReturn def ReturnOutsideOfDefError(tree: Tree) = { 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 5d4cd0be77..ef9bae700e 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -388,6 +388,7 @@ trait Macros { self: Analyzer => compatibilityError("types incompatible for parameter "+aparam.name+": corresponding is not a vararg parameter") if (!hasErrors) { var atpe = aparam.tpe.substSym(flatactparams, flatreqparams).instantiateTypeParams(tparams, tvars) + atpe = atpe.dealias // SI-5706 // strip the { type PrefixType = ... } refinement off the Context or otherwise we get compatibility errors atpe = atpe match { case RefinedType(List(tpe), Scope(sym)) if tpe == MacroContextClass.tpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe @@ -855,7 +856,7 @@ trait Macros { self: Analyzer => val numParamLists = paramss_without_evidences.length val numArgLists = argss.length if (numParamLists != numArgLists) { - typer.context.error(expandee.pos, "macros cannot be partially applied") + typer.TyperErrorGen.MacroPartialApplicationError(expandee) return None } @@ -953,6 +954,11 @@ trait Macros { self: Analyzer => * the expandee with an error marker set if there has been an error */ def macroExpand(typer: Typer, expandee: Tree, mode: Int = EXPRmode, pt: Type = WildcardType): Tree = { + def fail(what: String, tree: Tree): Tree = { + val err = typer.context.errBuffer.head + this.fail(typer, tree, "failed to perform %s: %s at %s".format(what, err.errMsg, err.errPos)) + return expandee + } val start = startTimer(macroExpandNanos) incCounter(macroExpandCount) try { @@ -979,15 +985,9 @@ trait Macros { self: Analyzer => case _ => ; } - def fail(what: String): Tree = { - val err = typer.context.errBuffer.head - this.fail(typer, expanded, "failed to perform %s: %s at %s".format(what, err.errMsg, err.errPos)) - return expandee - } - if (macroDebug) println("typechecking1 against %s: %s".format(expectedTpe, expanded)) var typechecked = typer.context.withImplicitsEnabled(typer.typed(expanded, EXPRmode, expectedTpe)) - if (typer.context.hasErrors) fail("typecheck1") + if (typer.context.hasErrors) fail("typecheck1", expanded) if (macroDebug) { println("typechecked1:") println(typechecked) @@ -996,7 +996,7 @@ trait Macros { self: Analyzer => if (macroDebug) println("typechecking2 against %s: %s".format(pt, expanded)) typechecked = typer.context.withImplicitsEnabled(typer.typed(typechecked, EXPRmode, pt)) - if (typer.context.hasErrors) fail("typecheck2") + if (typer.context.hasErrors) fail("typecheck2", expanded) if (macroDebug) { println("typechecked2:") println(typechecked) @@ -1009,13 +1009,16 @@ trait Macros { self: Analyzer => } case Delay(expandee) => // need to save the context to preserve enclosures - val args = macroArgs(typer, expandee) - assert(args.isDefined, expandee) - val context = args.get.head.asInstanceOf[MacroContext] - var result = expandee withAttachment MacroAttachment(delayed = true, context = Some(context)) - // adapting here would be premature, we must wait until undetparams are inferred -// result = typer.adapt(result, mode, pt) - result + 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) => 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/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/src/library/scala/reflect/makro/Reifiers.scala b/src/library/scala/reflect/makro/Reifiers.scala index ae6669946c..b1de8d9957 100644 --- a/src/library/scala/reflect/makro/Reifiers.scala +++ b/src/library/scala/reflect/makro/Reifiers.scala @@ -74,4 +74,4 @@ trait Reifiers { case class ReificationError(var pos: reflect.api.Position, val msg: String) extends Throwable(msg) -case class UnexpectedReificationError(val pos: reflect.api.Position, val msg: String, val cause: Throwable = null) extends Throwable(msg)
\ No newline at end of file +case class UnexpectedReificationError(val pos: reflect.api.Position, val msg: String, val cause: Throwable = null) extends Throwable(msg, cause)
\ No newline at end of file diff --git a/test/files/pos/t5706.flags b/test/files/pos/t5706.flags new file mode 100644 index 0000000000..cd66464f2f --- /dev/null +++ b/test/files/pos/t5706.flags @@ -0,0 +1 @@ +-language:experimental.macros
\ No newline at end of file diff --git a/test/files/pos/t5706.scala b/test/files/pos/t5706.scala new file mode 100644 index 0000000000..847acb693f --- /dev/null +++ b/test/files/pos/t5706.scala @@ -0,0 +1,10 @@ +import scala.reflect.makro.Context + +class Logger { + def error(message: String) = macro Impls.error +} + +object Impls { + type LoggerContext = Context { type PrefixType = Logger } + def error(c: LoggerContext)(message: c.Expr[String]): c.Expr[Unit] = ??? +} 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/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/files/run/reify-repl-fail-gracefully.check b/test/files/run/reify-repl-fail-gracefully.check new file mode 100644 index 0000000000..680db12667 --- /dev/null +++ b/test/files/run/reify-repl-fail-gracefully.check @@ -0,0 +1,21 @@ +Type in expressions to have them evaluated. +Type :help for more information. + +scala> + +scala> import language.experimental.macros +import language.experimental.macros + +scala> import scala.reflect.mirror._ +import scala.reflect.mirror._ + +scala> + +scala> reify +<console>:12: error: macros cannot be partially applied + reify + ^ + +scala> + +scala> diff --git a/test/files/run/reify-repl-fail-gracefully.scala b/test/files/run/reify-repl-fail-gracefully.scala new file mode 100644 index 0000000000..d7a06e8da8 --- /dev/null +++ b/test/files/run/reify-repl-fail-gracefully.scala @@ -0,0 +1,10 @@ +import scala.tools.partest.ReplTest + +object Test extends ReplTest { + def code = """ + |import language.experimental.macros + |import scala.reflect.mirror._ + | + |reify + """.stripMargin +} |