diff options
Diffstat (limited to 'src')
7 files changed, 385 insertions, 347 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 819887f959..56ad4738d9 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -86,6 +86,19 @@ class Global(var currentSettings: Settings, var reporter: Reporter) def erasurePhase: Phase = if (currentRun.isDefined) currentRun.erasurePhase else NoPhase + /* Override `newStubSymbol` defined in `SymbolTable` to provide us access + * to the last tree to typer, whose position is the trigger of stub errors. */ + override def newStubSymbol(owner: Symbol, + name: Name, + missingMessage: String): Symbol = { + val stubSymbol = super.newStubSymbol(owner, name, missingMessage) + val stubErrorPosition = { + val lastTreeToTyper = analyzer.lastTreeToTyper + if (lastTreeToTyper != EmptyTree) lastTreeToTyper.pos else stubSymbol.pos + } + stubSymbol.setPos(stubErrorPosition) + } + // platform specific elements protected class GlobalPlatform extends { diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 95f34c1719..f146419a73 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -1061,8 +1061,11 @@ abstract class ClassfileParser { val sflags = jflags.toScalaFlags val owner = ownerForFlags(jflags) val scope = getScope(jflags) - def newStub(name: Name) = - owner.newStubSymbol(name, s"Class file for ${entry.externalName} not found").setFlag(JAVA) + def newStub(name: Name) = { + val stub = owner.newStubSymbol(name, s"Class file for ${entry.externalName} not found") + stub.setPos(owner.pos) + stub.setFlag(JAVA) + } val (innerClass, innerModule) = if (file == NoAbstractFile) { (newStub(name.toTypeName), newStub(name.toTermName)) @@ -1184,7 +1187,11 @@ abstract class ClassfileParser { if (enclosing == clazz) entry.scope lookup name else lookupMemberAtTyperPhaseIfPossible(enclosing, name) } - def newStub = enclosing.newStubSymbol(name, s"Unable to locate class corresponding to inner class entry for $name in owner ${entry.outerName}") + def newStub = { + enclosing + .newStubSymbol(name, s"Unable to locate class corresponding to inner class entry for $name in owner ${entry.outerName}") + .setPos(enclosing.pos) + } member.orElse(newStub) } } diff --git a/src/library/scala/sys/process/ProcessBuilder.scala b/src/library/scala/sys/process/ProcessBuilder.scala index b7966b0341..d0745e5833 100644 --- a/src/library/scala/sys/process/ProcessBuilder.scala +++ b/src/library/scala/sys/process/ProcessBuilder.scala @@ -257,10 +257,9 @@ trait ProcessBuilder extends Source with Sink { */ def run(connectInput: Boolean): Process - /** Starts the process represented by this builder, blocks until it exits, and - * returns the exit code. Standard output and error are sent to the given - * ProcessLogger. The newly started process reads from standard input of the - * current process if `connectInput` is true. + /** Starts the process represented by this builder. Standard output and error + * are sent to the given ProcessLogger. The newly started process reads from + * standard input of the current process if `connectInput` is true. */ def run(log: ProcessLogger, connectInput: Boolean): Process diff --git a/src/library/scala/util/Either.scala b/src/library/scala/util/Either.scala index 523c10c483..d295478698 100644 --- a/src/library/scala/util/Either.scala +++ b/src/library/scala/util/Either.scala @@ -6,54 +6,52 @@ ** |/ ** \* */ - - package scala package util /** Represents a value of one of two possible types (a disjoint union.) - * An instance of Either is either an instance of [[scala.util.Left]] or [[scala.util.Right]]. + * An instance of `Either` is an instance of either [[scala.util.Left]] or [[scala.util.Right]]. * - * A common use of Either is as an alternative to [[scala.Option]] for dealing - * with possible missing values. In this usage, [[scala.None]] is replaced + * A common use of `Either` is as an alternative to [[scala.Option]] for dealing + * with possibly missing values. In this usage, [[scala.None]] is replaced * with a [[scala.util.Left]] which can contain useful information. * [[scala.util.Right]] takes the place of [[scala.Some]]. Convention dictates - * that Left is used for failure and Right is used for success. + * that `Left` is used for failure and `Right` is used for success. * - * For example, you could use `Either[String, Int]` to detect whether a - * received input is a String or an Int. + * For example, you could use `Either[String, Int]` to indicate whether a + * received input is a `String` or an `Int`. * * {{{ - * val in = Console.readLine("Type Either a string or an Int: ") - * val result: Either[String,Int] = try { - * Right(in.toInt) - * } catch { - * case e: Exception => - * Left(in) - * } + * import scala.io.StdIn._ + * val in = readLine("Type Either a string or an Int: ") + * val result: Either[String,Int] = + * try Right(in.toInt) + * catch { + * case e: NumberFormatException => Left(in) + * } * - * println(result match { + * result match { * case Right(x) => s"You passed me the Int: $x, which I will increment. $x + 1 = ${x+1}" * case Left(x) => s"You passed me the String: $x" - * }) + * } * }}} * - * Either is right-biased, which means that Right is assumed to be the default case to - * operate on. If it is Left, operations like map, flatMap, ... return the Left value - * unchanged: + * `Either` is right-biased, which means that `Right` is assumed to be the default case to + * operate on. If it is `Left`, operations like `map` and `flatMap` return the `Left` value unchanged: * * {{{ - * Right(12).map(_ * 2) // Right(24) - * Left(23).map(_ * 2) // Left(23) + * def doubled(i: Int) = i * 2 + * Right(42).map(doubled) // Right(84) + * Left(42).map(doubled) // Left(42) * }}} * - * As Either defines the methods `map` and `flatMap`, it can also be used in for comprehensions: + * Since `Either` defines the methods `map` and `flatMap`, it can also be used in for comprehensions: * {{{ - * val right1: Right[Double, Int] = Right(1) - * val right2 = Right(2) - * val right3 = Right(3) - * val left23: Left[Double, Int] = Left(23.0) - * val left42 = Left(42.0) + * val right1 = Right(1) : Right[Double, Int] + * val right2 = Right(2) + * val right3 = Right(3) + * val left23 = Left(23.0) : Left[Double, Int] + * val left42 = Left(42.0) * * for { * a <- right1 @@ -73,8 +71,9 @@ package util * c <- right2 * } yield a + b + c // Left(23.0) * - * // It is advisable to provide the type of the “missing” value (especially the right value for `Left`) - * // as otherwise that type might be inferred as `Nothing` without context: + * // It may be necessary to provide the type of the “missing” value, especially the type + * // of the right value for `Left`. Otherwise, without any context that constrains the type, + * // it might be inferred as `Nothing`: * for { * a <- left23 * b <- right1 @@ -92,77 +91,69 @@ package util * @since 2.7 */ sealed abstract class Either[+A, +B] extends Product with Serializable { - /** - * Projects this `Either` as a `Left`. - */ + /** Projects this `Either` as a `Left`. */ def left = Either.LeftProjection(this) - /** - * Projects this `Either` as a `Right`. + /** Projects this `Either` as a `Right`. * - * Because `Either` is right-biased, this method is not normally needed. - * (It is retained in the API for now for easy cross-compilation between Scala - * 2.11 and 2.12.) + * Because `Either` is right-biased, this method is not normally needed. */ def right = Either.RightProjection(this) - /** - * Applies `fa` if this is a `Left` or `fb` if this is a `Right`. + /** Applies `fa` if this is a `Left` or `fb` if this is a `Right`. * - * @example {{{ - * val result: Either[Exception, Value] = possiblyFailingOperation() - * log(result.fold( - * ex => s"Operation failed with $ex", - * v => s"Operation produced value: $v" - * )) - * }}} + * @example {{{ + * val result = util.Try("42".toInt).toEither + * result.fold( + * e => s"Operation failed with $e", + * v => s"Operation produced value: $v" + * ) + * }}} * - * @param fa the function to apply if this is a `Left` - * @param fb the function to apply if this is a `Right` - * @return the results of applying the function + * @param fa the function to apply if this is a `Left` + * @param fb the function to apply if this is a `Right` + * @return the results of applying the function */ def fold[C](fa: A => C, fb: B => C): C = this match { case Right(b) => fb(b) case Left(a) => fa(a) } - /** - * If this is a `Left`, then return the left value in `Right` or vice versa. + /** If this is a `Left`, then return the left value in `Right` or vice versa. * - * @example {{{ - * val left: Either[String, Int] = Left("left") - * val right: Either[Int, String] = l.swap // Result: Right("left") - * }}} - * @example {{{ - * val right = Right(2) - * val left = Left(3) - * for { - * r1 <- right - * r2 <- left.swap - * } yield r1 * r2 // Right(6) - * }}} + * @example {{{ + * val left: Either[String, Int] = Left("left") + * val right: Either[Int, String] = left.swap // Result: Right("left") + * }}} + * @example {{{ + * val right = Right(2) + * val left = Left(3) + * for { + * r1 <- right + * r2 <- left.swap + * } yield r1 * r2 // Right(6) + * }}} */ def swap: Either[B, A] = this match { case Left(a) => Right(a) case Right(b) => Left(b) } - /** - * Joins an `Either` through `Right`. + /** Joins an `Either` through `Right`. * - * This method requires that the right side of this Either is itself an - * Either type. That is, this must be some type like: {{{ - * Either[A, Either[A, C]] - * }}} (which respects the type parameter bounds, shown below.) + * This method requires that the right side of this `Either` is itself + * an `Either` type. That is, this must be some type like: {{{ + * Either[A, Either[A, C]] + * }}} (which respects the type parameter bounds, shown below.) * - * If this instance is a Right[Either[A, C]] then the contained Either[A, C] - * will be returned, otherwise this value will be returned unmodified. + * If this instance is a `Right[Either[A, C]]` then the contained `Either[A, C]` + * will be returned, otherwise this value will be returned unmodified. * - * @example {{{ - * Right[String, Either[String, Int]](Right(12)).joinRight // Result: Right(12) - * Right[String, Either[String, Int]](Left("flower")).joinRight // Result: Left("flower") - * Left[String, Either[String, Int]]("flower").joinRight // Result: Left("flower") - * }}} + * @example {{{ + * Right[String, Either[String, Int]](Right(12)).joinRight // Result: Right(12) + * Right[String, Either[String, Int]](Left("flower")).joinRight // Result: Left("flower") + * Left[String, Either[String, Int]]("flower").joinRight // Result: Left("flower") + * }}} * * This method, and `joinLeft`, are analogous to `Option#flatten` */ @@ -172,51 +163,48 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { } - /** - * Joins an `Either` through `Left`. + /** Joins an `Either` through `Left`. * - * This method requires that the left side of this Either is itself an - * Either type. That is, this must be some type like: {{{ - * Either[Either[C, B], B] - * }}} (which respects the type parameter bounds, shown below.) + * This method requires that the left side of this `Either` is itself an + * `Either` type. That is, this must be some type like: {{{ + * Either[Either[C, B], B] + * }}} (which respects the type parameter bounds, shown below.) * - * If this instance is a Left[Either[C, B]] then the contained Either[C, B] - * will be returned, otherwise this value will be returned unmodified. + * If this instance is a `Left[Either[C, B]]` then the contained `Either[C, B]` + * will be returned, otherwise this value will be returned unmodified. * - * {{{ - * Left[Either[Int, String], String](Right("flower")).joinLeft // Result: Right("flower") - * Left[Either[Int, String], String](Left(12)).joinLeft // Result: Left(12) - * Right[Either[Int, String], String]("daisy").joinLeft // Result: Right("daisy") - * }}} + * {{{ + * Left[Either[Int, String], String](Right("flower")).joinLeft // Result: Right("flower") + * Left[Either[Int, String], String](Left(12)).joinLeft // Result: Left(12) + * Right[Either[Int, String], String]("daisy").joinLeft // Result: Right("daisy") + * }}} * - * This method, and `joinRight`, are analogous to `Option#flatten` + * This method, and `joinRight`, are analogous to `Option#flatten`. */ def joinLeft[A1 >: A, B1 >: B, C](implicit ev: A1 <:< Either[C, B1]): Either[C, B1] = this match { case Left(a) => a case Right(b) => this.asInstanceOf[Either[C, B1]] } - /** - * Executes the given side-effecting function if this is a `Right`. + /** Executes the given side-effecting function if this is a `Right`. * - * {{{ - * Right(12).foreach(x => println(x)) // prints "12" - * Left(12).foreach(x => println(x)) // doesn't print - * }}} - * @param f The side-effecting function to execute. + * {{{ + * Right(12).foreach(println) // prints "12" + * Left(12).foreach(println) // doesn't print + * }}} + * @param f The side-effecting function to execute. */ def foreach[U](f: B => U): Unit = this match { case Right(b) => f(b) case Left(_) => } - /** - * Returns the value from this `Right` or the given argument if this is a `Left`. + /** Returns the value from this `Right` or the given argument if this is a `Left`. * - * {{{ - * Right(12).getOrElse(17) // 12 - * Left(12).getOrElse(17) // 17 - * }}} + * {{{ + * Right(12).getOrElse(17) // 12 + * Left(12).getOrElse(17) // 17 + * }}} */ def getOrElse[BB >: B](or: => BB): BB = this match { case Right(b) => b @@ -233,7 +221,7 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { * // Returns false because value of Right is "something" which does not equal "anything". * Right("something") contains "anything" * - * // Returns false because there is no value for Right. + * // Returns false because it's not a Right value. * Left("something") contains "something" * }}} * @@ -245,53 +233,49 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { case Left(_) => false } - /** - * Returns `true` if `Left` or returns the result of the application of - * the given predicate to the `Right` value. + /** Returns `true` if `Left` or returns the result of the application of + * the given predicate to the `Right` value. * - * {{{ - * Right(12).forall(_ > 10) // true - * Right(7).forall(_ > 10) // false - * Left(12).forall(_ > 10) // true - * }}} + * {{{ + * Right(12).forall(_ > 10) // true + * Right(7).forall(_ > 10) // false + * Left(12).forall(_ => false) // true + * }}} */ def forall(f: B => Boolean): Boolean = this match { case Right(b) => f(b) case Left(_) => true } - /** - * Returns `false` if `Left` or returns the result of the application of - * the given predicate to the `Right` value. + /** Returns `false` if `Left` or returns the result of the application of + * the given predicate to the `Right` value. * - * {{{ - * Right(12).exists(_ > 10) // true - * Right(7).exists(_ > 10) // false - * Left(12).exists(_ > 10) // false - * }}} + * {{{ + * Right(12).exists(_ > 10) // true + * Right(7).exists(_ > 10) // false + * Left(12).exists(_ => true) // false + * }}} */ def exists(p: B => Boolean): Boolean = this match { case Right(b) => p(b) case Left(_) => false } - /** - * Binds the given function across `Right`. + /** Binds the given function across `Right`. * - * @param f The function to bind across `Right`. + * @param f The function to bind across `Right`. */ def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = this match { case Right(b) => f(b) case Left(a) => this.asInstanceOf[Either[AA, Y]] } - /** - * The given function is applied if this is a `Right`. + /** The given function is applied if this is a `Right`. * - * {{{ - * Right(12).map(x => "flower") // Result: Right("flower") - * Left(12).map(x => "flower") // Result: Left(12) - * }}} + * {{{ + * Right(12).map(x => "flower") // Result: Right("flower") + * Left(12).map(x => "flower") // Result: Left(12) + * }}} */ def map[Y](f: B => Y): Either[A, Y] = this match { case Right(b) => Right(f(b)) @@ -303,9 +287,9 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { * returns `Left` with the existing value of `Left` if this is a `Left`. * * {{{ - * Right(12).filterOrElse(_ > 10, -1) // Right(12) - * Right(7).filterOrElse(_ > 10, -1) // Left(-1) - * Left(12).filterOrElse(_ > 10, -1) // Left(12) + * Right(12).filterOrElse(_ > 10, -1) // Right(12) + * Right(7).filterOrElse(_ > 10, -1) // Left(-1) + * Left(7).filterOrElse(_ => false, -1) // Left(7) * }}} */ def filterOrElse[AA >: A](p: B => Boolean, zero: => AA): Either[AA, B] = this match { @@ -344,32 +328,29 @@ sealed abstract class Either[+A, +B] extends Product with Serializable { case Left(a) => Failure(a) } - /** - * Returns `true` if this is a `Left`, `false` otherwise. + /** Returns `true` if this is a `Left`, `false` otherwise. * - * {{{ - * Left("tulip").isLeft // true - * Right("venus fly-trap").isLeft // false - * }}} + * {{{ + * Left("tulip").isLeft // true + * Right("venus fly-trap").isLeft // false + * }}} */ def isLeft: Boolean - /** - * Returns `true` if this is a `Right`, `false` otherwise. + /** Returns `true` if this is a `Right`, `false` otherwise. * - * {{{ - * Left("tulip").isRight // false - * Right("venus fly-trap").isRight // true - * }}} + * {{{ + * Left("tulip").isRight // false + * Right("venus fly-trap").isRight // true + * }}} */ def isRight: Boolean } -/** - * The left side of the disjoint union, as opposed to the [[scala.util.Right]] side. +/** The left side of the disjoint union, as opposed to the [[scala.util.Right]] side. * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ final case class Left[+A, +B](@deprecatedName('a, "2.12.0") value: A) extends Either[A, B] { def isLeft = true @@ -378,11 +359,10 @@ final case class Left[+A, +B](@deprecatedName('a, "2.12.0") value: A) extends Ei @deprecated("Use .value instead.", "2.12.0") def a: A = value } -/** - * The right side of the disjoint union, as opposed to the [[scala.util.Left]] side. +/** The right side of the disjoint union, as opposed to the [[scala.util.Left]] side. * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ final case class Right[+A, +B](@deprecatedName('b, "2.12.0") value: B) extends Either[A, B] { def isLeft = false @@ -396,27 +376,26 @@ object Either { /** If the condition is satisfied, return the given `B` in `Right`, * otherwise, return the given `A` in `Left`. * - * {{{ - * val userInput: String = ... - * Either.cond( - * userInput.forall(_.isDigit) && userInput.size == 10, - * PhoneNumber(userInput), - * "The input (%s) does not look like a phone number".format(userInput) - * }}} + * {{{ + * val userInput: String = ... + * Either.cond( + * userInput.forall(_.isDigit) && userInput.size == 10, + * PhoneNumber(userInput), + * "The input (%s) does not look like a phone number".format(userInput) + * }}} */ def cond[X, Y](test: Boolean, right: => Y, left: => X): Either[X, Y] = if (test) Right(right) else Left(left) - /** - * Allows use of a `merge` method to extract values from Either instances - * regardless of whether they are Left or Right. + /** Allows use of a `merge` method to extract values from Either instances + * regardless of whether they are Left or Right. * - * {{{ - * val l = Left(List(1)): Either[List[Int], Vector[Int]] - * val r = Right(Vector(1)): Either[List[Int], Vector[Int]] - * l.merge: Seq[Int] // List(1) - * r.merge: Seq[Int] // Vector(1) - * }}} + * {{{ + * val l = Left(List(1)): Either[List[Int], Vector[Int]] + * val r = Right(Vector(1)): Either[List[Int], Vector[Int]] + * l.merge: Seq[Int] // List(1) + * r.merge: Seq[Int] // Vector(1) + * }}} */ implicit class MergeableEither[A](private val x: Either[A, A]) extends AnyVal { def merge: A = x match { @@ -425,65 +404,58 @@ object Either { } } - /** - * Projects an `Either` into a `Left`. - * - * This allows for-comprehensions over the left side of Either instances, - * reversing Either's usual right-bias. + /** Projects an `Either` into a `Left`. * - * For example {{{ - * for (s <- Left("flower").left) yield s.length // Left(6) - * }}} + * This allows for-comprehensions over the left side of Either instances, + * reversing Either's usual right-bias. * - * Continuing the analogy with [[scala.Option]], a `LeftProjection` declares - * that `Left` should be analogous to `Some` in some code. + * For example {{{ + * for (s <- Left("flower").left) yield s.length // Left(6) + * }}} * - * {{{ - * // using Option: - * def interactWithDB(x: Query): Option[Result] = - * try { - * Some(getResultFromDatabase(x)) - * } catch { - * case ex => None - * } + * Continuing the analogy with [[scala.Option]], a `LeftProjection` declares + * that `Left` should be analogous to `Some` in some code. * - * // this will only be executed if interactWithDB returns a Some - * val report = - * for (r <- interactWithDB(someQuery)) yield generateReport(r) - * if (report.isDefined) - * send(report) - * else - * log("report not generated, not sure why...") - * }}} + * {{{ + * // using Option: + * def interactWithDB(x: Query): Option[Result] = + * try Some(getResultFromDatabase(x)) + * catch { + * case _: SQLException => None + * } + * + * // this will only be executed if interactWithDB returns a Some + * val report = for (result <- interactWithDB(someQuery)) yield generateReport(result) + * report match { + * case Some(r) => send(r) + * case None => log("report not generated, not sure why...") + * }}} * - * {{{ - * // using Either - * def interactWithDB(x: Query): Either[Exception, Result] = - * try { - * Right(getResultFromDatabase(x)) - * } catch { - * case ex => Left(ex) + * {{{ + * // using Either + * def interactWithDB(x: Query): Either[Exception, Result] = + * try Right(getResultFromDatabase(x)) + * catch { + * case e: SQLException => Left(e) + * } + * + * // this will only be executed if interactWithDB returns a Right + * val report = for (result <- interactWithDB(someQuery).right) yield generateReport(result) + * report match { + * case Right(r) => send(r) + * case Left(e) => log(s"report not generated, reason was $e") * } + * }}} * - * // this will only be executed if interactWithDB returns a Right - * val report = - * for (r <- interactWithDB(someQuery).right) yield generateReport(r) - * if (report.isRight) - * send(report) - * else - * log("report not generated, reason was " + report.left.get) - * }}} - * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ final case class LeftProjection[+A, +B](e: Either[A, B]) { - /** - * Returns the value from this `Left` or throws `java.util.NoSuchElementException` - * if this is a `Right`. + /** Returns the value from this `Left` or throws `java.util.NoSuchElementException` + * if this is a `Right`. * * {{{ - * Left(12).left.get // 12 + * Left(12).left.get // 12 * Right(12).left.get // NoSuchElementException * }}} * @@ -494,8 +466,7 @@ object Either { case Right(_) => throw new NoSuchElementException("Either.left.get on Right") } - /** - * Executes the given side-effecting function if this is a `Left`. + /** Executes the given side-effecting function if this is a `Left`. * * {{{ * Left(12).left.foreach(x => println(x)) // prints "12" @@ -508,116 +479,105 @@ object Either { case Right(_) => } - /** - * Returns the value from this `Left` or the given argument if this is a `Right`. - * - * {{{ - * Left(12).left.getOrElse(17) // 12 - * Right(12).left.getOrElse(17) // 17 - * }}} + /** Returns the value from this `Left` or the given argument if this is a `Right`. * + * {{{ + * Left(12).left.getOrElse(17) // 12 + * Right(12).left.getOrElse(17) // 17 + * }}} */ def getOrElse[AA >: A](or: => AA): AA = e match { case Left(a) => a case Right(_) => or } - /** - * Returns `true` if `Right` or returns the result of the application of - * the given function to the `Left` value. - * - * {{{ - * Left(12).left.forall(_ > 10) // true - * Left(7).left.forall(_ > 10) // false - * Right(12).left.forall(_ > 10) // true - * }}} + /** Returns `true` if `Right` or returns the result of the application of + * the given function to the `Left` value. * + * {{{ + * Left(12).left.forall(_ > 10) // true + * Left(7).left.forall(_ > 10) // false + * Right(12).left.forall(_ > 10) // true + * }}} */ def forall(@deprecatedName('f) p: A => Boolean): Boolean = e match { case Left(a) => p(a) case Right(_) => true } - /** - * Returns `false` if `Right` or returns the result of the application of - * the given function to the `Left` value. - * - * {{{ - * Left(12).left.exists(_ > 10) // true - * Left(7).left.exists(_ > 10) // false - * Right(12).left.exists(_ > 10) // false - * }}} + /** Returns `false` if `Right` or returns the result of the application of + * the given function to the `Left` value. * + * {{{ + * Left(12).left.exists(_ > 10) // true + * Left(7).left.exists(_ > 10) // false + * Right(12).left.exists(_ > 10) // false + * }}} */ def exists(@deprecatedName('f) p: A => Boolean): Boolean = e match { case Left(a) => p(a) case Right(_) => false } - /** - * Binds the given function across `Left`. + /** Binds the given function across `Left`. * - * {{{ - * Left(12).left.flatMap(x => Left("scala")) // Left("scala") - * Right(12).left.flatMap(x => Left("scala") // Right(12) - * }}} - * @param f The function to bind across `Left`. + * {{{ + * Left(12).left.flatMap(x => Left("scala")) // Left("scala") + * Right(12).left.flatMap(x => Left("scala")) // Right(12) + * }}} + * @param f The function to bind across `Left`. */ def flatMap[BB >: B, X](f: A => Either[X, BB]): Either[X, BB] = e match { case Left(a) => f(a) case Right(b) => e.asInstanceOf[Either[X, BB]] } - /** - * Maps the function argument through `Left`. + /** Maps the function argument through `Left`. * - * {{{ - * Left(12).left.map(_ + 2) // Left(14) - * Right[Int, Int](12).left.map(_ + 2) // Right(12) - * }}} + * {{{ + * Left(12).left.map(_ + 2) // Left(14) + * Right[Int, Int](12).left.map(_ + 2) // Right(12) + * }}} */ def map[X](f: A => X): Either[X, B] = e match { case Left(a) => Left(f(a)) case Right(b) => e.asInstanceOf[Either[X, B]] } - /** - * Returns `None` if this is a `Right` or if the given predicate - * `p` does not hold for the left value, otherwise, returns a `Left`. + /** Returns `None` if this is a `Right` or if the given predicate + * `p` does not hold for the left value, otherwise, returns a `Left`. * - * {{{ - * Left(12).left.filter(_ > 10) // Some(Left(12)) - * Left(7).left.filter(_ > 10) // None - * Right(12).left.filter(_ > 10) // None - * }}} + * {{{ + * Left(12).left.filter(_ > 10) // Some(Left(12)) + * Left(7).left.filter(_ > 10) // None + * Right(12).left.filter(_ > 10) // None + * }}} */ def filter[Y](p: A => Boolean): Option[Either[A, Y]] = e match { case Left(a) => if(p(a)) Some(Left(a)) else None case Right(b) => None } - /** - * Returns a `Seq` containing the `Left` value if it exists or an empty - * `Seq` if this is a `Right`. + /** Returns a `Seq` containing the `Left` value if it exists or an empty + * `Seq` if this is a `Right`. * - * {{{ - * Left(12).left.toSeq // Seq(12) - * Right(12).left.toSeq // Seq() - * }}} + * {{{ + * Left(12).left.toSeq // Seq(12) + * Right(12).left.toSeq // Seq() + * }}} */ def toSeq: Seq[A] = e match { case Left(a) => Seq(a) case Right(_) => Seq.empty } - /** - * Returns a `Some` containing the `Left` value if it exists or a - * `None` if this is a `Right`. + /** Returns a `Some` containing the `Left` value if it exists or a + * `None` if this is a `Right`. * - * {{{ - * Left(12).left.toOption // Some(12) - * Right(12).left.toOption // None - * }}} + * {{{ + * Left(12).left.toOption // Some(12) + * Right(12).left.toOption // None + * }}} */ def toOption: Option[A] = e match { case Left(a) => Some(a) @@ -625,26 +585,24 @@ object Either { } } - /** - * Projects an `Either` into a `Right`. + /** Projects an `Either` into a `Right`. * - * Because `Either` is already right-biased, this class is not normally needed. - * (It is retained in the library for now for easy cross-compilation between Scala - * 2.11 and 2.12.) + * Because `Either` is already right-biased, this class is not normally needed. + * (It is retained in the library for now for easy cross-compilation between Scala + * 2.11 and 2.12.) * - * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse - * @version 1.0, 11/10/2008 + * @author <a href="mailto:research@workingmouse.com">Tony Morris</a>, Workingmouse + * @version 1.0, 11/10/2008 */ final case class RightProjection[+A, +B](e: Either[A, B]) { - /** - * Returns the value from this `Right` or throws - * `java.util.NoSuchElementException` if this is a `Left`. + /** Returns the value from this `Right` or throws + * `java.util.NoSuchElementException` if this is a `Left`. * - * {{{ - * Right(12).right.get // 12 - * Left(12).right.get // NoSuchElementException - * }}} + * {{{ + * Right(12).right.get // 12 + * Left(12).right.get // NoSuchElementException + * }}} * * @throws java.util.NoSuchElementException if the projection is `Left`. */ @@ -653,80 +611,74 @@ object Either { case Left(_) => throw new NoSuchElementException("Either.right.get on Left") } - /** - * Executes the given side-effecting function if this is a `Right`. + /** Executes the given side-effecting function if this is a `Right`. * - * {{{ - * Right(12).right.foreach(x => println(x)) // prints "12" - * Left(12).right.foreach(x => println(x)) // doesn't print - * }}} - * @param f The side-effecting function to execute. + * {{{ + * Right(12).right.foreach(x => println(x)) // prints "12" + * Left(12).right.foreach(x => println(x)) // doesn't print + * }}} + * @param f The side-effecting function to execute. */ def foreach[U](f: B => U): Unit = e match { case Right(b) => f(b) case Left(_) => } - /** - * Returns the value from this `Right` or the given argument if this is a `Left`. + /** Returns the value from this `Right` or the given argument if this is a `Left`. * - * {{{ - * Right(12).right.getOrElse(17) // 12 - * Left(12).right.getOrElse(17) // 17 - * }}} + * {{{ + * Right(12).right.getOrElse(17) // 12 + * Left(12).right.getOrElse(17) // 17 + * }}} */ def getOrElse[BB >: B](or: => BB): BB = e match { case Right(b) => b case Left(_) => or } - /** - * Returns `true` if `Left` or returns the result of the application of - * the given function to the `Right` value. + /** Returns `true` if `Left` or returns the result of the application of + * the given function to the `Right` value. * - * {{{ - * Right(12).right.forall(_ > 10) // true - * Right(7).right.forall(_ > 10) // false - * Left(12).right.forall(_ > 10) // true - * }}} + * {{{ + * Right(12).right.forall(_ > 10) // true + * Right(7).right.forall(_ > 10) // false + * Left(12).right.forall(_ > 10) // true + * }}} */ def forall(f: B => Boolean): Boolean = e match { case Right(b) => f(b) case Left(_) => true } - /** - * Returns `false` if `Left` or returns the result of the application of - * the given function to the `Right` value. + /** Returns `false` if `Left` or returns the result of the application of + * the given function to the `Right` value. * - * {{{ - * Right(12).right.exists(_ > 10) // true - * Right(7).right.exists(_ > 10) // false - * Left(12).right.exists(_ > 10) // false - * }}} + * {{{ + * Right(12).right.exists(_ > 10) // true + * Right(7).right.exists(_ > 10) // false + * Left(12).right.exists(_ > 10) // false + * }}} */ def exists(@deprecatedName('f) p: B => Boolean): Boolean = e match { case Right(b) => p(b) case Left(_) => false } - /** - * Binds the given function across `Right`. + /** Binds the given function across `Right`. * - * @param f The function to bind across `Right`. + * @param f The function to bind across `Right`. */ def flatMap[AA >: A, Y](f: B => Either[AA, Y]): Either[AA, Y] = e match { case Right(b) => f(b) case Left(a) => e.asInstanceOf[Either[AA, Y]] } - /** - * The given function is applied if this is a `Right`. + /** The given function is applied if this is a `Right`. * - * {{{ - * Right(12).right.map(x => "flower") // Result: Right("flower") - * Left(12).right.map(x => "flower") // Result: Left(12) - * }}} + * {{{ + * Right(12).right.map(x => "flower") // Result: Right("flower") + * Left(12).right.map(x => "flower") // Result: Left(12) + * }}} */ def map[Y](f: B => Y): Either[A, Y] = e match { case Right(b) => Right(f(b)) diff --git a/src/partest-extras/scala/tools/partest/StubErrorMessageTest.scala b/src/partest-extras/scala/tools/partest/StubErrorMessageTest.scala new file mode 100644 index 0000000000..f713b79e75 --- /dev/null +++ b/src/partest-extras/scala/tools/partest/StubErrorMessageTest.scala @@ -0,0 +1,47 @@ +package scala.tools.partest + +trait StubErrorMessageTest extends StoreReporterDirectTest { + // Stub to feed to partest, unused + def code = throw new Error("Use `userCode` instead of `code`.") + + val classpath = List(sys.props("partest.lib"), testOutput.path) + .mkString(sys.props("path.separator")) + + def compileCode(codes: String*) = { + val global = newCompiler("-cp", classpath, "-d", testOutput.path) + val sourceFiles = newSources(codes: _*) + withRun(global)(_ compileSources sourceFiles) + } + + def removeClasses(inPackage: String, classNames: Seq[String]): Unit = { + val pkg = new File(testOutput.path, inPackage) + classNames.foreach { className => + val classFile = new File(pkg, s"$className.class") + assert(classFile.exists) + assert(classFile.delete()) + } + } + + def removeFromClasspath(): Unit + def codeA: String + def codeB: String + def userCode: String + def extraUserCode: String = "" + + def show(): Unit = { + compileCode(codeA) + assert(filteredInfos.isEmpty, filteredInfos) + + compileCode(codeB) + assert(filteredInfos.isEmpty, filteredInfos) + removeFromClasspath() + + if (extraUserCode == "") compileCode(userCode) + else compileCode(userCode, extraUserCode) + import scala.reflect.internal.util.Position + filteredInfos.map { report => + print(if (report.severity == storeReporter.ERROR) "error: " else "") + println(Position.formatMessage(report.pos, report.msg, true)) + } + } +} diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 9d71136fc5..854849d27c 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -193,6 +193,15 @@ trait Symbols extends api.Symbols { self: SymbolTable => private[reflect] case class SymbolKind(accurate: String, sanitized: String, abbreviation: String) + protected def newStubSymbol(owner: Symbol, + name: Name, + missingMessage: String): Symbol = { + name match { + case n: TypeName => new StubClassSymbol(owner, n, missingMessage) + case _ => new StubTermSymbol(owner, name.toTermName, missingMessage) + } + } + /** The class for all symbols */ abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name) extends SymbolContextApiImpl @@ -504,9 +513,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => * failure to the point when that name is used for something, which is * often to the point of never. */ - def newStubSymbol(name: Name, missingMessage: String, isPackage: Boolean = false): Symbol = name match { - case n: TypeName => new StubClassSymbol(this, n, missingMessage) - case _ => new StubTermSymbol(this, name.toTermName, missingMessage) + def newStubSymbol(name: Name, missingMessage: String): Symbol = { + // Invoke the overriden `newStubSymbol` in Global that gives us access to typer + Symbols.this.newStubSymbol(this, name, missingMessage) } /** Given a field, construct a term symbol that represents the source construct that gave rise the field */ @@ -3427,7 +3436,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def fail[T](alt: T): T = { // Avoid issuing lots of redundant errors if (!hasFlag(IS_ERROR)) { - globalError(missingMessage) + globalError(pos, missingMessage) if (settings.debug.value) (new Throwable).printStackTrace diff --git a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala index b4152c9b8c..16fbab7103 100644 --- a/src/reflect/scala/reflect/internal/pickling/UnPickler.scala +++ b/src/reflect/scala/reflect/internal/pickling/UnPickler.scala @@ -246,14 +246,15 @@ abstract class UnPickler { adjust(mirrorThatLoaded(owner).missingHook(owner, name)) orElse { // (4) Create a stub symbol to defer hard failure a little longer. val advice = moduleAdvice(s"${owner.fullName}.$name") + val lazyCompletingSymbol = completingStack.headOption.getOrElse(NoSymbol) val missingMessage = - s"""|missing or invalid dependency detected while loading class file '$filename'. - |Could not access ${name.longString} in ${owner.kindString} ${owner.fullName}, - |because it (or its dependencies) are missing. Check your build definition for - |missing or conflicting dependencies. (Re-run with `-Ylog-classpath` to see the problematic classpath.) + s"""|Symbol '${name.nameKind} ${owner.fullName}.$name' is missing from the classpath. + |This symbol is required by '${lazyCompletingSymbol.kindString} ${lazyCompletingSymbol.fullName}'. + |Make sure that ${name.longString} is in your classpath and check for conflicting dependencies with `-Ylog-classpath`. |A full rebuild may help if '$filename' was compiled against an incompatible version of ${owner.fullName}.$advice""".stripMargin val stubName = if (tag == EXTref) name else name.toTypeName - owner.newStubSymbol(stubName, missingMessage) + // The position of the error message is set by `newStubSymbol` + NoSymbol.newStubSymbol(stubName, missingMessage) } } } @@ -696,11 +697,18 @@ abstract class UnPickler { new TypeError(e.msg) } + /** Keep track of the symbols pending to be initialized. + * + * Useful for reporting on stub errors and cyclic errors. + */ + private var completingStack = List.empty[Symbol] + /** A lazy type which when completed returns type at index `i`. */ private class LazyTypeRef(i: Int) extends LazyType with FlagAgnosticCompleter { private val definedAtRunId = currentRunId private val p = phase protected def completeInternal(sym: Symbol) : Unit = try { + completingStack = sym :: completingStack val tp = at(i, () => readType(sym.isTerm)) // after NMT_TRANSITION, revert `() => readType(sym.isTerm)` to `readType` // This is a temporary fix allowing to read classes generated by an older, buggy pickler. @@ -723,7 +731,10 @@ abstract class UnPickler { } catch { case e: MissingRequirementError => throw toTypeError(e) + } finally { + completingStack = completingStack.tail } + override def complete(sym: Symbol) : Unit = { completeInternal(sym) if (!isCompilerUniverse) markAllCompleted(sym) |