diff options
Diffstat (limited to 'src')
9 files changed, 79 insertions, 19 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala index d2c511a2d1..1f832ba81e 100644 --- a/src/compiler/scala/tools/nsc/transform/Delambdafy.scala +++ b/src/compiler/scala/tools/nsc/transform/Delambdafy.scala @@ -113,7 +113,9 @@ abstract class Delambdafy extends Transform with TypingTransformers with ast.Tre // after working on the entire compilation until we'll have a set of // new class definitions to add to the top level override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { - super.transformStats(stats, exprOwner) ++ lambdaClassDefs(exprOwner) + // Need to remove from the lambdaClassDefs map: there may be multiple PackageDef for the same + // package when defining a package object. We only add the lambda class to one. See SI-9097. + super.transformStats(stats, exprOwner) ++ lambdaClassDefs.remove(exprOwner).getOrElse(Nil) } private def optionSymbol(sym: Symbol): Option[Symbol] = if (sym.exists) Some(sym) else None diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 6149e40fa7..fbb0307773 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -166,7 +166,7 @@ abstract class Flatten extends InfoTransform { override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { val stats1 = super.transformStats(stats, exprOwner) if (currentOwner.isPackageClass) { - val lifted = liftedDefs(currentOwner).toList + val lifted = liftedDefs.remove(currentOwner).toList.flatten stats1 ::: lifted } else stats1 diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index fa0c1f797b..a703542587 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -539,12 +539,11 @@ abstract class LambdaLift extends InfoTransform { override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { def addLifted(stat: Tree): Tree = stat match { case ClassDef(_, _, _, _) => - val lifted = liftedDefs get stat.symbol match { + val lifted = liftedDefs remove stat.symbol match { case Some(xs) => xs reverseMap addLifted case _ => log("unexpectedly no lifted defs for " + stat.symbol) ; Nil } - try deriveClassDef(stat)(impl => deriveTemplate(impl)(_ ::: lifted)) - finally liftedDefs -= stat.symbol + deriveClassDef(stat)(impl => deriveTemplate(impl)(_ ::: lifted)) case DefDef(_, _, _, _, _, Block(Nil, expr)) if !stat.symbol.isConstructor => deriveDefDef(stat)(_ => expr) diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 5c36bd9d28..c80aaea160 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -45,6 +45,14 @@ trait ContextErrors { case class NormalTypeError(underlyingTree: Tree, errMsg: String) extends TreeTypeError + /** + * Marks a TypeError that was constructed from a CyclicReference (under silent). + * This is used for named arguments, where we need to know if an assignment expression + * failed with a cyclic reference or some other type error. + */ + class NormalTypeErrorFromCyclicReference(underlyingTree: Tree, errMsg: String) + extends NormalTypeError(underlyingTree, errMsg) + case class AccessTypeError(underlyingTree: Tree, errMsg: String) extends TreeTypeError @@ -1087,8 +1095,9 @@ trait ContextErrors { // hence we (together with reportTypeError in TypeDiagnostics) make sure that this CyclicReference // evades all the handlers on its way and successfully reaches `isCyclicOrErroneous` in Implicits throw ex - case CyclicReference(sym, info: TypeCompleter) => - issueNormalTypeError(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage()) + case c @ CyclicReference(sym, info: TypeCompleter) => + val error = new NormalTypeErrorFromCyclicReference(tree, typer.cyclicReferenceMessage(sym, info.tree) getOrElse ex.getMessage) + issueTypeError(error) case _ => contextNamerErrorGen.issue(TypeErrorWithUnderlyingTree(tree, ex)) } @@ -1275,8 +1284,8 @@ trait ContextErrors { } def WarnAfterNonSilentRecursiveInference(param: Symbol, arg: Tree)(implicit context: Context) = { - val note = "type-checking the invocation of "+ param.owner +" checks if the named argument expression '"+ param.name + " = ...' is a valid assignment\n"+ - "in the current scope. The resulting type inference error (see above) can be fixed by providing an explicit type in the local definition for "+ param.name +"." + val note = "failed to determine if '"+ param.name + " = ...' is a named argument or an assignment expression.\n"+ + "an explicit type is required for the definition mentioned in the error message above." context.warning(arg.pos, note) } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 50f658f68d..39cd610b1c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -521,8 +521,22 @@ trait NamesDefaults { self: Analyzer => WarnAfterNonSilentRecursiveInference(param, arg)(context) res } match { - case SilentResultValue(t) => !t.isErroneous // #4041 - case _ => false + case SilentResultValue(t) => + !t.isErroneous // #4041 + case SilentTypeError(e: NormalTypeErrorFromCyclicReference) => + // If we end up here, the CyclicReference was reported in a silent context. This can + // happen for local definitions, when the completer for a definition is created during + // type checking in silent mode. ContextErrors.TypeSigError catches that cyclic reference + // and transforms it into a NormalTypeErrorFromCyclicReference. + // The cycle needs to be reported, because the program cannot be typed: we don't know + // if we have an assignment or a named arg. + context.issue(e) + // 'err = true' is required because we're in a silent context + WarnAfterNonSilentRecursiveInference(param, arg)(context) + false + case _ => + // We got a type error, so it cannot be an assignment (it doesn't type check as one). + false } catch { // `silent` only catches and returns TypeErrors which are not diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index e4255e5333..3a85d16f55 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -76,7 +76,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case s : SilentTypeError => f(s.reportableErrors) } } - class SilentTypeError private(val errors: List[AbsTypeError]) extends SilentResult[Nothing] { + class SilentTypeError private(val errors: List[AbsTypeError], val warnings: List[(Position, String)]) extends SilentResult[Nothing] { override def isEmpty = true def err: AbsTypeError = errors.head def reportableErrors = errors match { @@ -87,10 +87,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } object SilentTypeError { - def apply(errors: AbsTypeError*): SilentTypeError = new SilentTypeError(errors.toList) + def apply(errors: AbsTypeError*): SilentTypeError = apply(errors.toList, Nil) + def apply(errors: List[AbsTypeError], warnings: List[(Position, String)]): SilentTypeError = new SilentTypeError(errors, warnings) + // todo: this extracts only one error, should be a separate extractor. def unapply(error: SilentTypeError): Option[AbsTypeError] = error.errors.headOption } + // todo: should include reporter warnings in SilentResultValue. + // e.g. tryTypedApply could print warnings on arguments when the typing succeeds. case class SilentResultValue[+T](value: T) extends SilentResult[T] { override def isEmpty = false } def newTyper(context: Context): Typer = new NormalTyper(context) @@ -661,7 +665,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper @inline def wrapResult(reporter: ContextReporter, result: T) = if (reporter.hasErrors) { stopStats() - SilentTypeError(reporter.errors: _*) + SilentTypeError(reporter.errors.toList, reporter.warnings.toList) } else SilentResultValue(result) try { @@ -4435,7 +4439,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper def tryTypedApply(fun: Tree, args: List[Tree]): Tree = { val start = if (Statistics.canEnable) Statistics.startTimer(failedApplyNanos) else null - def onError(typeErrors: Seq[AbsTypeError]): Tree = { + def onError(typeErrors: Seq[AbsTypeError], warnings: Seq[(Position, String)]): Tree = { if (Statistics.canEnable) Statistics.stopTimer(failedApplyNanos, start) // If the problem is with raw types, copnvert to existentials and try again. @@ -4483,10 +4487,14 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } } typeErrors foreach context.issue + warnings foreach { case (p, m) => context.warning(p, m) } setError(treeCopy.Apply(tree, fun, args)) } - silent(_.doTypedApply(tree, fun, args, mode, pt)) orElse onError + silent(_.doTypedApply(tree, fun, args, mode, pt)) match { + case SilentResultValue(value) => value + case e: SilentTypeError => onError(e.errors, e.warnings) + } } def normalTypedApply(tree: Tree, fun: Tree, args: List[Tree]) = { @@ -4537,6 +4545,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper case err: SilentTypeError => onError({ err.reportableErrors foreach context.issue + err.warnings foreach { case (p, m) => context.warning(p, m) } args foreach (arg => typed(arg, mode, ErrorType)) setError(tree) }) diff --git a/src/library/scala/collection/immutable/StringLike.scala b/src/library/scala/collection/immutable/StringLike.scala index f0daaf25a5..1ead894faf 100644 --- a/src/library/scala/collection/immutable/StringLike.scala +++ b/src/library/scala/collection/immutable/StringLike.scala @@ -10,7 +10,7 @@ package scala package collection package immutable -import mutable.Builder +import mutable.{ ArrayBuilder, Builder } import scala.util.matching.Regex import scala.math.ScalaNumber import scala.reflect.ClassTag @@ -203,8 +203,33 @@ self => private def escape(ch: Char): String = "\\Q" + ch + "\\E" - @throws(classOf[java.util.regex.PatternSyntaxException]) - def split(separator: Char): Array[String] = toString.split(escape(separator)) + def split(separator: Char): Array[String] = { + val thisString = toString + var pos = thisString.indexOf(separator) + + if (pos != -1) { + val res = new ArrayBuilder.ofRef[String] + + var prev = 0 + do { + res += thisString.substring(prev, pos) + prev = pos + 1 + pos = thisString.indexOf(separator, prev) + } while (pos != -1) + + if (prev != thisString.size) + res += thisString.substring(prev, thisString.size) + + val initialResult = res.result() + pos = initialResult.length + while (pos > 0 && initialResult(pos - 1).isEmpty) pos = pos - 1 + if (pos != initialResult.length) { + val trimmed = new Array[String](pos) + Array.copy(initialResult, 0, trimmed, 0, pos) + trimmed + } else initialResult + } else Array[String](thisString) + } @throws(classOf[java.util.regex.PatternSyntaxException]) def split(separators: Array[Char]): Array[String] = { diff --git a/src/library/scala/collection/mutable/LinkedHashMap.scala b/src/library/scala/collection/mutable/LinkedHashMap.scala index b64504be3d..275f490675 100644 --- a/src/library/scala/collection/mutable/LinkedHashMap.scala +++ b/src/library/scala/collection/mutable/LinkedHashMap.scala @@ -160,6 +160,7 @@ class LinkedHashMap[A, B] extends AbstractMap[A, B] override def clear() { clearTable() firstEntry = null + lastEntry = null } private def writeObject(out: java.io.ObjectOutputStream) { diff --git a/src/library/scala/collection/mutable/LinkedHashSet.scala b/src/library/scala/collection/mutable/LinkedHashSet.scala index 1768c946ed..756a2f73c1 100644 --- a/src/library/scala/collection/mutable/LinkedHashSet.scala +++ b/src/library/scala/collection/mutable/LinkedHashSet.scala @@ -112,6 +112,7 @@ class LinkedHashSet[A] extends AbstractSet[A] override def clear() { clearTable() firstEntry = null + lastEntry = null } private def writeObject(out: java.io.ObjectOutputStream) { |