From 58f6a1346093db2f407879246884d480ff8d7904 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Thu, 3 May 2012 14:36:14 -0700 Subject: Fix for SI-3718. And for a bunch of other tickets where we unleash a stack trace rather than printing a sensible error message. But SI-3718 is a continuations plugin crash, now a reasonable if somewhat vague error. --- src/compiler/scala/reflect/internal/StdNames.scala | 1 + .../scala/reflect/internal/SymbolTable.scala | 10 +- src/compiler/scala/reflect/internal/Types.scala | 5 + src/compiler/scala/tools/nsc/Global.scala | 2 +- .../scala/tools/nsc/transform/UnCurry.scala | 112 +++++++++++---------- .../scala/tools/nsc/typechecker/Typers.scala | 18 ++-- 6 files changed, 87 insertions(+), 61 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index 6413f0ea43..543c8e1a77 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -639,6 +639,7 @@ trait StdNames { val lang: NameType = "lang" val length: NameType = "length" val lengthCompare: NameType = "lengthCompare" + val liftedTree: NameType = "liftedTree" val `macro` : NameType = "macro" val macroThis : NameType = "_this" val macroContext : NameType = "c" diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index aa60fb4aba..76b4f5f53e 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -50,14 +50,18 @@ abstract class SymbolTable extends api.Universe /** Override with final implementation for inlining. */ def debuglog(msg: => String): Unit = if (settings.debug.value) log(msg) def debugwarn(msg: => String): Unit = if (settings.debug.value) Console.err.println(msg) + def throwableAsString(t: Throwable): String = "" + t + + /** Prints a stack trace if -Ydebug or equivalent was given, otherwise does nothing. */ + def debugStack(t: Throwable): Unit = debugwarn(throwableAsString(t)) /** Overridden when we know more about what was happening during a failure. */ def supplementErrorMessage(msg: String): String = msg private[scala] def printCaller[T](msg: String)(result: T) = { - Console.err.println(msg + ": " + result) - Console.err.println("Called from:") - (new Throwable).getStackTrace.drop(2).take(15).foreach(Console.err.println) + Console.err.println("%s: %s\nCalled from: %s".format(msg, result, + (new Throwable).getStackTrace.drop(2).take(15).mkString("\n"))) + result } diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 9867c23c70..66657c4412 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -6730,6 +6730,11 @@ trait Types extends api.Types { self: SymbolTable => case TypeRef(_, sym, _) => !isPrimitiveValueClass(sym) case _ => false } + // Add serializable to a list of parents, unless one of them already is + def addSerializable(ps: Type*): List[Type] = ( + if (ps exists (_ <:< SerializableClass.tpe)) ps.toList + else (ps :+ SerializableClass.tpe).toList + ) def objToAny(tp: Type): Type = if (!phase.erasedTypes && tp.typeSymbol == ObjectClass) AnyClass.tpe diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index ff092416fd..e4cfad53c7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -243,7 +243,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } def logThrowable(t: Throwable): Unit = globalError(throwableAsString(t)) - def throwableAsString(t: Throwable): String = + override def throwableAsString(t: Throwable): String = if (opt.richExes) Exceptional(t).force().context() else util.stackTraceString(t) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index ef70271371..394957c747 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -72,14 +72,13 @@ abstract class UnCurry extends InfoTransform } class UnCurryTransformer(unit: CompilationUnit) extends TypingTransformer(unit) { - - private var needTryLift = false - private var inPattern = false + private var needTryLift = false + private var inPattern = false private var inConstructorFlag = 0L - private val byNameArgs = new mutable.HashSet[Tree] - private val noApply = new mutable.HashSet[Tree] - private val newMembers = mutable.ArrayBuffer[Tree]() - private val repeatedParams = mutable.Map[Symbol, List[ValDef]]() + private val byNameArgs = mutable.HashSet[Tree]() + private val noApply = mutable.HashSet[Tree]() + private val newMembers = mutable.ArrayBuffer[Tree]() + private val repeatedParams = mutable.Map[Symbol, List[ValDef]]() @inline private def withInPattern[T](value: Boolean)(body: => T): T = { inPattern = value @@ -87,30 +86,40 @@ abstract class UnCurry extends InfoTransform finally inPattern = !value } + private def newFunction0(body: Tree): Tree = { + val result = localTyper.typedPos(body.pos)(Function(Nil, body)).asInstanceOf[Function] + log("Change owner from %s to %s in %s".format(currentOwner, result.symbol, result.body)) + result.body changeOwner (currentOwner -> result.symbol) + transformFunction(result) + } + private lazy val serialVersionUIDAnnotation = AnnotationInfo(SerialVersionUIDAttr.tpe, List(Literal(Constant(0))), List()) private var nprinted = 0 - override def transform(tree: Tree): Tree = try { //debug - postTransform(mainTransform(tree)) - } catch { - case ex: Throwable => - if (nprinted < 10) { - Console.println("exception when traversing " + tree) - nprinted += 1 - } - throw ex - } + // I don't have a clue why I'm catching TypeErrors here, but it's better + // than spewing stack traces at end users for internal errors. Examples + // which hit at this point should not be hard to come by, but the immediate + // motivation can be seen in continuations-neg/t3718. + override def transform(tree: Tree): Tree = ( + try postTransform(mainTransform(tree)) + catch { case ex: TypeError => + unit.error(ex.pos, ex.msg) + debugStack(ex) + EmptyTree + } + ) /* Is tree a reference `x` to a call by name parameter that needs to be converted to * x.apply()? Note that this is not the case if `x` is used as an argument to another * call by name parameter. */ - def isByNameRef(tree: Tree): Boolean = - tree.isTerm && tree.hasSymbol && - isByNameParamType(tree.symbol.tpe) && - !byNameArgs(tree) + def isByNameRef(tree: Tree) = ( + tree.isTerm + && !byNameArgs(tree) + && tree.hasSymbolWhich(s => isByNameParamType(s.tpe)) + ) /** Uncurry a type of a tree node. * This function is sensitive to whether or not we are in a pattern -- when in a pattern @@ -241,10 +250,10 @@ abstract class UnCurry extends InfoTransform // only get here when running under -Xoldpatmat synthPartialFunction(fun) case _ => - val parents = - if (isFunctionType(fun.tpe)) List(abstractFunctionForFunctionType(fun.tpe), SerializableClass.tpe) - else List(ObjectClass.tpe, fun.tpe, SerializableClass.tpe) - + val parents = ( + if (isFunctionType(fun.tpe)) addSerializable(abstractFunctionForFunctionType(fun.tpe)) + else addSerializable(ObjectClass.tpe, fun.tpe) + ) val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation anonClass setInfo ClassInfoType(parents, newScope, anonClass) @@ -282,7 +291,7 @@ abstract class UnCurry extends InfoTransform val (formals, restpe) = (targs.init, targs.last) val anonClass = fun.symbol.owner newAnonymousFunctionClass(fun.pos, inConstructorFlag) addAnnotation serialVersionUIDAnnotation - val parents = List(appliedType(AbstractPartialFunctionClass, targs: _*), SerializableClass.tpe) + val parents = addSerializable(appliedType(AbstractPartialFunctionClass, targs: _*)) anonClass setInfo ClassInfoType(parents, newScope, anonClass) // duplicate before applyOrElseMethodDef is run so that it does not mess up our trees and label symbols (we have a fresh set) @@ -409,22 +418,27 @@ abstract class UnCurry extends InfoTransform else if (tp.bounds.hi ne tp) getClassTag(tp.bounds.hi) else localTyper.TyperErrorGen.MissingClassTagError(tree, tp) } + def traversableClassTag(tpe: Type): Tree = { + (tpe baseType TraversableClass).typeArgs match { + case targ :: _ => getClassTag(targ) + case _ => EmptyTree + } + } afterUncurry { localTyper.typedPos(pos) { - Apply(gen.mkAttributedSelect(tree, toArraySym), - List(getClassTag(tree.tpe.baseType(TraversableClass).typeArgs.head))) + gen.mkMethodCall(tree, toArraySym, Nil, List(traversableClassTag(tree.tpe))) } } } var suffix: Tree = if (treeInfo isWildcardStarArgList args) { - val Typed(tree, _) = args.last; + val Typed(tree, _) = args.last if (isJava) if (tree.tpe.typeSymbol == ArrayClass) tree else sequenceToArray(tree) else - if (tree.tpe.typeSymbol isSubClass TraversableClass) tree // @PP: I suspect this should be SeqClass + if (tree.tpe.typeSymbol isSubClass SeqClass) tree else arrayToSequence(tree, varargsElemType) } else { @@ -447,22 +461,18 @@ abstract class UnCurry extends InfoTransform val args1 = if (isVarArgTypes(formals)) transformVarargs(formals.last.typeArgs.head) else args map2(formals, args1) { (formal, arg) => - if (!isByNameParamType(formal)) { + if (!isByNameParamType(formal)) arg - } else if (isByNameRef(arg)) { + else if (isByNameRef(arg)) { byNameArgs += arg - arg setType functionType(List(), arg.tpe) - } else { - if (opt.verboseDebug) { - val posstr = arg.pos.source.path + ":" + arg.pos.line - val permstr = if (fun.isPrivate) "private" else "notprivate" - log("byname | %s | %s | %s".format(posstr, fun.fullName, permstr)) - } - - val result = localTyper.typed( - Function(Nil, arg) setPos arg.pos).asInstanceOf[Function] - new ChangeOwnerTraverser(currentOwner, result.symbol).traverse(arg) - transformFunction(result) + arg setType functionType(Nil, arg.tpe) + } + else { + log("byname | %s | %s | %s".format( + arg.pos.source.path + ":" + arg.pos.line, fun.fullName, + if (fun.isPrivate) "private" else "") + ) + newFunction0(arg) } } } @@ -709,12 +719,12 @@ abstract class UnCurry extends InfoTransform case Apply(Apply(fn, args), args1) => treeCopy.Apply(tree, fn, args ::: args1) case Ident(name) => - assert(name != tpnme.WILDCARD_STAR) + assert(name != tpnme.WILDCARD_STAR, tree) applyUnary() case Select(_, _) | TypeApply(_, _) => applyUnary() - case ret @ Return(expr) if (isNonLocalReturn(ret)) => - debuglog("non local return in "+ret.symbol+" from "+currentOwner.enclMethod) + case ret @ Return(expr) if isNonLocalReturn(ret) => + log("non-local return from %s to %s".format(currentOwner.enclMethod, ret.symbol)) atPos(ret.pos)(nonLocalReturnThrow(expr, ret.symbol)) case TypeTree() => tree @@ -762,10 +772,10 @@ abstract class UnCurry extends InfoTransform ) } - val reps = repeatedParams(dd.symbol) - val rpsymbols = reps.map(_.symbol).toSet - val theTyper = typer.atOwner(dd, currentClass) - val flatparams = flatdd.vparamss.head + val reps = repeatedParams(dd.symbol) + val rpsymbols = reps.map(_.symbol).toSet + val theTyper = typer.atOwner(dd, currentClass) + val flatparams = flatdd.vparamss.head // create the type val forwformals = flatparams map { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index d7413b48f5..6248d27727 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1616,10 +1616,16 @@ trait Typers extends Modes with Adaptations with Taggings { val clazz = mdef.symbol.moduleClass val typedMods = typedModifiers(mdef.mods) assert(clazz != NoSymbol, mdef) + val noSerializable = ( + (linkedClass eq NoSymbol) + || linkedClass.isErroneous + || !linkedClass.isSerializable + || clazz.isSerializable + ) val impl1 = typerReportAnyContextErrors(context.make(mdef.impl, clazz, newScope)) { _.typedTemplate(mdef.impl, { parentTypes(mdef.impl) ++ ( - if (linkedClass == NoSymbol || !linkedClass.isSerializable || clazz.isSerializable) Nil + if (noSerializable) Nil else { clazz.makeSerializable() List(TypeTree(SerializableClass.tpe) setPos clazz.pos.focus) @@ -2293,11 +2299,11 @@ trait Typers extends Modes with Adaptations with Taggings { // need to duplicate the cases before typing them to generate the apply method, or the symbols will be all messed up val casesTrue = if (isPartial) cases map (c => deriveCaseDef(c)(x => TRUE_typed).duplicate) else Nil // println("casesTrue "+ casesTrue) - def parentsPartial(targs: List[Type]) = List(appliedType(AbstractPartialFunctionClass.typeConstructor, targs), SerializableClass.tpe) + def parentsPartial(targs: List[Type]) = addSerializable(appliedType(AbstractPartialFunctionClass.typeConstructor, targs)) def applyMethod = { // rig the show so we can get started typing the method body -- later we'll correct the infos... - anonClass setInfo ClassInfoType(List(ObjectClass.tpe, pt, SerializableClass.tpe), newScope, anonClass) + anonClass setInfo ClassInfoType(addSerializable(ObjectClass.tpe, pt), newScope, anonClass) val methodSym = anonClass.newMethod(nme.apply, tree.pos, if(isPartial) (FINAL | OVERRIDE) else FINAL) val paramSyms = mkParams(methodSym) val selector = mkSel(paramSyms) @@ -2313,10 +2319,10 @@ trait Typers extends Modes with Adaptations with Taggings { val resTp = match_.tpe val methFormals = paramSyms map (_.tpe) - val parents = + val parents = ( if (isPartial) parentsPartial(List(methFormals.head, resTp)) - else List(abstractFunctionType(methFormals, resTp), SerializableClass.tpe) - + else addSerializable(abstractFunctionType(methFormals, resTp)) + ) anonClass setInfo ClassInfoType(parents, newScope, anonClass) methodSym setInfoAndEnter MethodType(paramSyms, resTp) -- cgit v1.2.3