summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/reflect/internal/StdNames.scala1
-rw-r--r--src/compiler/scala/reflect/internal/SymbolTable.scala10
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala5
-rw-r--r--src/compiler/scala/tools/nsc/Global.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/UnCurry.scala112
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala18
-rw-r--r--src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala19
-rw-r--r--test/files/continuations-neg/t3718.check4
-rw-r--r--test/files/continuations-neg/t3718.scala3
9 files changed, 109 insertions, 65 deletions
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)
diff --git a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
index e9e9cf0fab..017c8d24fd 100644
--- a/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
+++ b/src/continuations/plugin/scala/tools/selectivecps/SelectiveANFTransform.scala
@@ -110,8 +110,7 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
transExpr(body, None, ext)
}
- debuglog("anf result "+body1)
- debuglog("result is of type "+body1.tpe)
+ debuglog("anf result "+body1+"\nresult is of type "+body1.tpe)
treeCopy.Function(ff, transformValDefs(vparams), body1)
}
@@ -142,7 +141,6 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
transExpr(tree, None, None)
case _ =>
-
if (hasAnswerTypeAnn(tree.tpe)) {
if (!cpsAllowed)
unit.error(tree.pos, "cps code not allowed here / " + tree.getClass + " / " + tree)
@@ -357,7 +355,20 @@ abstract class SelectiveANFTransform extends PluginComponent with Transform with
List(expr)
)
)
- return ((stms, call))
+ // This is today's sick/meaningless heuristic for spotting breakdown so
+ // we don't proceed until stack traces start draping themselves over everything.
+ // If there are wildcard types in the tree and B == Nothing, something went wrong.
+ // (I thought WildcardTypes would be enough, but nope. 'reset0 { 0 }' has them.)
+ //
+ // Code as simple as reset((_: String).length)
+ // will crash meaninglessly without this check. See SI-3718.
+ //
+ // TODO - obviously this should be done earlier, differently, or with
+ // a more skilled hand. Most likely, all three.
+ if ((b.typeSymbol eq NothingClass) && call.tpe.exists(_ eq WildcardType))
+ unit.error(tree.pos, "cannot cps-transform malformed (possibly in shift/reset placement) expression")
+ else
+ return ((stms, call))
}
catch {
case ex:TypeError =>
diff --git a/test/files/continuations-neg/t3718.check b/test/files/continuations-neg/t3718.check
new file mode 100644
index 0000000000..659104c1c6
--- /dev/null
+++ b/test/files/continuations-neg/t3718.check
@@ -0,0 +1,4 @@
+t3718.scala:2: error: cannot cps-transform malformed (possibly in shift/reset placement) expression
+ scala.util.continuations.reset((_: Any).##)
+ ^
+one error found
diff --git a/test/files/continuations-neg/t3718.scala b/test/files/continuations-neg/t3718.scala
new file mode 100644
index 0000000000..a0fcb9d869
--- /dev/null
+++ b/test/files/continuations-neg/t3718.scala
@@ -0,0 +1,3 @@
+object Test {
+ scala.util.continuations.reset((_: Any).##)
+}