Skip to content

Commit

Permalink
Migration rework #1:
Browse files Browse the repository at this point in the history
 - The @migration annotation can now be used like @Deprecation, old syntax is still supported, but deprecated.
 - Improved the wording and the consistency of most migration messages, migration warnings now also show the version the change occurred.
 - Adjusted test.
 - Partially fixes SI-4990.
  • Loading branch information
soc committed Dec 7, 2011
1 parent 332fec9 commit 298ec94
Show file tree
Hide file tree
Showing 26 changed files with 77 additions and 138 deletions.
4 changes: 2 additions & 2 deletions src/compiler/scala/reflect/internal/Symbols.scala
Original file line number Diff line number Diff line change
Expand Up @@ -494,8 +494,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
// string. So this needs attention. For now the fact that migration is
// private[scala] ought to provide enough protection.
def hasMigrationAnnotation = hasAnnotation(MigrationAnnotationClass)
def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(2) }
def migrationVersion = getAnnotation(MigrationAnnotationClass) map { version => version.intArg(0).get + "." + version.intArg(1).get }
def migrationMessage = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(0) }
def migrationVersion = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(1) }
def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) }
def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) }

Expand Down
6 changes: 4 additions & 2 deletions src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1273,8 +1273,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R
* indicating it has changed semantics between versions.
*/
private def checkMigration(sym: Symbol, pos: Position) = {
for (msg <- sym.migrationMessage)
unit.warning(pos, sym.fullLocationString + " has changed semantics:\n" + msg)
if (sym.hasMigrationAnnotation)
unit.warning(pos, "%s has changed semantics in version %s:\n%s".format(
sym.fullLocationString, sym.migrationVersion.get, sym.migrationMessage.get)
)
}

private def lessAccessible(otherSym: Symbol, memberSym: Symbol): Boolean = (
Expand Down
18 changes: 10 additions & 8 deletions src/library/scala/annotation/migration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ package scala.annotation
* reason or another retain the same name and type signature,
* but some aspect of their behavior is different. An illustrative
* examples is Stack.iterator, which reversed from LIFO to FIFO
* order between scala 2.7 and 2.8.
* order between Scala 2.7 and 2.8.
*
* The version numbers are to mark the scala major/minor release
* version where the change took place.
* @param message A message describing the change, which is emitted
* by the compiler if the flag `-Xmigration` is set.
*
* @param changedIn The version, in which the behaviour change was
* introduced.
*
* @since 2.8
*/
private[scala] final class migration(
majorVersion: Int,
minorVersion: Int,
message: String)
extends annotation.StaticAnnotation {}
private[scala] final class migration(message: String, changedIn: String) extends annotation.StaticAnnotation {
@deprecated("Use the constructor taking two Strings instead.", "2.10")
def this(majorVersion: Int, minorVersion: Int, message: String) = this(message, majorVersion + "." + minorVersion)
}
5 changes: 1 addition & 4 deletions src/library/scala/collection/GenTraversableLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,7 @@ trait GenTraversableLike[+A, +Repr] extends GenTraversableOnce[A] with Paralleli
* @param bf $bfinfo
* @return collection with intermediate results
*/
@migration(2, 9,
"This scanRight definition has changed in 2.9.\n" +
"The previous behavior can be reproduced with scanRight.reverse."
)
@migration("The behavior of `scanRight` has changed. The previous behavior can be reproduced with scanRight.reverse.", "2.9")
def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That

/** Applies a function `f` to all elements of this $coll.
Expand Down
2 changes: 0 additions & 2 deletions src/library/scala/collection/GenTraversableViewLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ package scala.collection
import generic._
import mutable.{ Builder, ArrayBuffer }
import TraversableView.NoBuilder
import annotation.migration



trait GenTraversableViewLike[+A,
Expand Down
17 changes: 7 additions & 10 deletions src/library/scala/collection/Iterator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
package scala.collection

import mutable.ArrayBuffer
import annotation.{ tailrec, migration }
import annotation.migration
import immutable.Stream

/** The `Iterator` object provides various functions for creating specialized iterators.
Expand Down Expand Up @@ -52,7 +52,7 @@ object Iterator {

/** Creates iterator that produces the results of some element computation a number of times.
*
* @param n the number of elements returned by the iterator.
* @param len the number of elements returned by the iterator.
* @param elem the element computation
* @return An iterator that produces the results of `n` evaluations of `elem`.
*/
Expand All @@ -66,7 +66,7 @@ object Iterator {

/** Creates an iterator producing the values of a given function over a range of integer values starting from 0.
*
* @param n The number of elements returned by the iterator
* @param end The number of elements returned by the iterator
* @param f The function computing element values
* @return An iterator that produces the values `f(0), ..., f(n -1)`.
*/
Expand Down Expand Up @@ -410,10 +410,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
* which `pf` is defined the image `pf(x)`.
* @note Reuse: $consumesAndProducesIterator
*/
@migration(2, 8,
"This collect implementation bears no relationship to the one before 2.8.\n"+
"The previous behavior can be reproduced with toSeq."
)
@migration("`collect` has changed. The previous behavior can be reproduced with `toSeq`.", "2.8")
def collect[B](pf: PartialFunction[A, B]): Iterator[B] = {
val self = buffered
new AbstractIterator[B] {
Expand Down Expand Up @@ -1033,9 +1030,9 @@ trait Iterator[+A] extends TraversableOnce[A] {

/** Returns this iterator with patched values.
*
* @param from The start index from which to patch
* @param ps The iterator of patch values
* @param replaced The number of values in the original iterator that are replaced by the patch.
* @param from The start index from which to patch
* @param patchElems The iterator of patch values
* @param replaced The number of values in the original iterator that are replaced by the patch.
* @note Reuse: $consumesTwoAndProducesOneIterator
*/
def patch[B >: A](from: Int, patchElems: Iterator[B], replaced: Int): Iterator[B] = new AbstractIterator[B] {
Expand Down
4 changes: 2 additions & 2 deletions src/library/scala/collection/MapLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,14 @@ self =>
*
* @return the keys of this map as an iterable.
*/
@migration(2, 8, "As of 2.8, keys returns Iterable[A] rather than Iterator[A].")
@migration("`keys` returns `Iterable[A]` rather than `Iterator[A]`.", "2.8")
def keys: Iterable[A] = keySet

/** Collects all values of this map in an iterable collection.
*
* @return the values of this map as an iterable.
*/
@migration(2, 8, "As of 2.8, values returns Iterable[B] rather than Iterator[B].")
@migration("`values` returns `Iterable[B]` rather than `Iterator[B]`.", "2.8")
def values: Iterable[B] = new DefaultValuesIterable

/** The implementation class of the iterable returned by `values`.
Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/SetLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ self =>
// note: this is only overridden here to add the migration annotation,
// which I hope to turn into an Xlint style warning as the migration aspect
// is not central to its importance.
@migration(2, 8, "Set.map now returns a Set, so it will discard duplicate values.")
@migration("Set.map now returns a Set, so it will discard duplicate values.", "2.8")
override def map[B, That](f: A => B)(implicit bf: CanBuildFrom[This, B, That]): That = super.map(f)(bf)

/** Tests if some element is contained in this set.
Expand Down
5 changes: 1 addition & 4 deletions src/library/scala/collection/TraversableLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,7 @@ trait TraversableLike[+A, +Repr] extends HasNewBuilder[A, Repr]
b.result
}

@migration(2, 9,
"This scanRight definition has changed in 2.9.\n" +
"The previous behavior can be reproduced with scanRight.reverse."
)
@migration("The behavior of `scanRight` has changed. The previous behavior can be reproduced with scanRight.reverse.", "2.9")
def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
var scanned = List(z)
var acc = z
Expand Down
5 changes: 1 addition & 4 deletions src/library/scala/collection/TraversableViewLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,7 @@ trait TraversableViewLike[+A,
override def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[This, B, That]): That =
newForced(thisSeq.scanLeft(z)(op)).asInstanceOf[That]

@migration(2, 9,
"This scanRight definition has changed in 2.9.\n" +
"The previous behavior can be reproduced with scanRight.reverse."
)
@migration("The behavior of `scanRight` has changed. The previous behavior can be reproduced with scanRight.reverse.", "2.9")
override def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[This, B, That]): That =
newForced(thisSeq.scanRight(z)(op)).asInstanceOf[That]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ package generic

import mutable.Builder
import annotation.migration
import annotation.bridge
import annotation.unchecked.uncheckedVariance

/** A template class for companion objects of ``regular`` collection classes
Expand Down Expand Up @@ -148,7 +147,7 @@ trait GenericTraversableTemplate[+A, +CC[X] <: GenTraversable[X]] extends HasNew
* @throws `IllegalArgumentException` if all collections in this $coll
* are not of the same size.
*/
@migration(2, 9, "As of 2.9, transpose throws an exception if collections are not uniformly sized.")
@migration("`transpose` throws an `IllegalArgumentException` if collections are not uniformly sized.", "2.9")
def transpose[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]): CC[CC[B] @uncheckedVariance] = {
if (isEmpty)
return genericBuilder[CC[B]].result
Expand Down
22 changes: 5 additions & 17 deletions src/library/scala/collection/mutable/BufferLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
def prepend(elems: A*) { prependAll(elems) }

/** Prepends the elements contained in a traversable object to this buffer.
* @param elems the collection containing the elements to prepend.
* @param xs the collection containing the elements to prepend.
*/
def prependAll(xs: TraversableOnce[A]) { xs ++=: this }

Expand Down Expand Up @@ -220,10 +220,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
* @param xs the traversable object.
* @return a new collection consisting of all the elements of this collection and `xs`.
*/
@migration(2, 8,
"As of 2.8, ++ always creates a new collection, even on Buffers.\n"+
"Use ++= instead if you intend to add by side effect to an existing collection.\n"
)
@migration("`++` creates a new buffer. Use `++=` to add an element from this buffer and return that buffer itself.", "2.8")
def ++(xs: GenTraversableOnce[A]): This = clone() ++= xs.seq

@bridge
Expand All @@ -234,10 +231,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
* @param elem the element to remove.
* @return a new collection consisting of all the elements of this collection except `elem`.
*/
@migration(2, 8,
"As of 2.8, - always creates a new collection, even on Buffers.\n"+
"Use -= instead if you intend to remove by side effect from an existing collection.\n"
)
@migration("`-` creates a new buffer. Use `-=` to remove an element from this buffer and return that buffer itself.", "2.8")
override def -(elem: A): This = clone() -= elem

/** Creates a new collection with all the elements of this collection except the two
Expand All @@ -249,10 +243,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
* @return a new collection consisting of all the elements of this collection except
* `elem1`, `elem2` and those in `elems`.
*/
@migration(2, 8,
"As of 2.8, - always creates a new collection, even on Buffers.\n"+
"Use -= instead if you intend to remove by side effect from an existing collection.\n"
)
@migration("`-` creates a new buffer. Use `-=` to remove an element from this buffer and return that buffer itself.", "2.8")
override def -(elem1: A, elem2: A, elems: A*): This = clone() -= elem1 -= elem2 --= elems

/** Creates a new collection with all the elements of this collection except those
Expand All @@ -262,10 +253,7 @@ trait BufferLike[A, +This <: BufferLike[A, This] with Buffer[A]]
* @return a new collection with all the elements of this collection except
* those in `xs`
*/
@migration(2, 8,
"As of 2.8, -- always creates a new collection, even on Buffers.\n"+
"Use --= instead if you intend to remove by side effect from an existing collection.\n"
)
@migration("`--` creates a new buffer. Use `--=` to remove an element from this buffer and return that buffer itself.", "2.8")
override def --(xs: GenTraversableOnce[A]): This = clone() --= xs.seq

@bridge def --(xs: TraversableOnce[A]): This = --(xs: GenTraversableOnce[A])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ trait DoubleLinkedListLike[A, This <: Seq[A] with DoubleLinkedListLike[A, This]]
* current node, i.e. `this` node itself will still point "into" the list it
* was in.
*/
@migration(2, 9, "Double linked list now removes the current node from the list.")
@migration("Double linked list now removes the current node from the list.", "2.9")
def remove(): Unit = if (nonEmpty) {
next.prev = prev
if (prev ne null) prev.next = next // because this could be the first node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ extends AbstractMap[A, B]

override def keysIterator: Iterator[A] = imap.keysIterator

@migration(2, 8, "As of 2.8, keys returns Iterable[A] rather than Iterator[A].")
@migration("`keys` returns Iterable[A] rather than Iterator[A].", "2.8")
override def keys: collection.Iterable[A] = imap.keys

override def valuesIterator: Iterator[B] = imap.valuesIterator

@migration(2, 8, "As of 2.8, values returns Iterable[B] rather than Iterator[B].")
@migration("`values` returns Iterable[B] rather than Iterator[B].", "2.8")
override def values: collection.Iterable[B] = imap.values

def iterator: Iterator[(A, B)] = imap.iterator
Expand Down
30 changes: 6 additions & 24 deletions src/library/scala/collection/mutable/MapLike.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
* @param kv the key/value mapping to be added
* @return a new map containing mappings of this map and the mapping `kv`.
*/
@migration(2, 8,
"As of 2.8, this operation creates a new map. To add an element as a\n"+
"side effect to an existing map and return that map itself, use +=."
)
@migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8")
def + [B1 >: B] (kv: (A, B1)): Map[A, B1] = clone().asInstanceOf[Map[A, B1]] += kv

/** Creates a new map containing two or more key/value mappings and all the key/value
Expand All @@ -106,10 +103,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
* @param elems the remaining elements to add.
* @return a new map containing mappings of this map and two or more specified mappings.
*/
@migration(2, 8,
"As of 2.8, this operation creates a new map. To add an element as a\n"+
"side effect to an existing map and return that map itself, use +=."
)
@migration("`+` creates a new map. Use `+=` to add an element to this map and return that map itself.", "2.8")
override def + [B1 >: B] (elem1: (A, B1), elem2: (A, B1), elems: (A, B1) *): Map[A, B1] =
clone().asInstanceOf[Map[A, B1]] += elem1 += elem2 ++= elems

Expand All @@ -121,10 +115,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
* @param xs the traversable object.
* @return a new map containing mappings of this map and those provided by `xs`.
*/
@migration(2, 8,
"As of 2.8, this operation creates a new map. To add the elements as a\n"+
"side effect to an existing map and return that map itself, use ++=."
)
@migration("`++` creates a new map. Use `++=` to add an element to this map and return that map itself.", "2.8")
override def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] =
clone().asInstanceOf[Map[A, B1]] ++= xs.seq

Expand Down Expand Up @@ -154,10 +145,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
* @param key the key to be removed
* @return a new map with all the mappings of this map except that with a key `key`.
*/
@migration(2, 8,
"As of 2.8, this operation creates a new map. To remove an element as a\n"+
"side effect to an existing map and return that map itself, use -=."
)
@migration("`-` creates a new map. Use `-=` to remove an element from this map and return that map itself.", "2.8")
override def -(key: A): This = clone() -= key

/** Removes all bindings from the map. After this operation has completed,
Expand Down Expand Up @@ -223,10 +211,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
* @return a new map containing all the mappings of this map except mappings
* with a key equal to `elem1`, `elem2` or any of `elems`.
*/
@migration(2, 8,
"As of 2.8, this operation creates a new map. To remove an element as a\n"+
"side effect to an existing map and return that map itself, use -=."
)
@migration("`-` creates a new map. Use `-=` to remove an element from this map and return that map itself.", "2.8")
override def -(elem1: A, elem2: A, elems: A*): This =
clone() -= elem1 -= elem2 --= elems

Expand All @@ -237,10 +222,7 @@ trait MapLike[A, B, +This <: MapLike[A, B, This] with Map[A, B]]
* @return a new map with all the key/value mappings of this map except mappings
* with a key equal to a key from `xs`.
*/
@migration(2, 8,
"As of 2.8, this operation creates a new map. To remove the elements as a\n"+
"side effect to an existing map and return that map itself, use --=."
)
@migration("`--` creates a new map. Use `--=` to remove an element from this map and return that map itself.", "2.8")
override def --(xs: GenTraversableOnce[A]): This = clone() --= xs.seq

@bridge def --(xs: TraversableOnce[A]): This = --(xs: GenTraversableOnce[A])
Expand Down
2 changes: 1 addition & 1 deletion src/library/scala/collection/mutable/PriorityQueue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ package scala.collection
package mutable

import generic._
import annotation.{migration, bridge}
import annotation.bridge

/** This class implements priority queues using a heap.
* To prioritize elements of type A there must be an implicit
Expand Down
Loading

0 comments on commit 298ec94

Please sign in to comment.