summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala46
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--src/library/scala/collection/Iterable.scala2
-rw-r--r--src/library/scala/collection/SetLike.scala7
-rw-r--r--src/library/scala/collection/Traversable.scala2
-rw-r--r--src/library/scala/collection/convert/DecorateAsScala.scala6
-rw-r--r--src/library/scala/collection/convert/WrapAsScala.scala8
-rw-r--r--src/library/scala/collection/convert/Wrappers.scala11
-rw-r--r--src/library/scala/collection/immutable/Iterable.scala1
-rw-r--r--src/library/scala/collection/immutable/Traversable.scala2
-rw-r--r--src/library/scala/collection/mutable/SetLike.scala17
-rw-r--r--src/library/scala/collection/mutable/UnrolledBuffer.scala48
-rw-r--r--src/library/scala/io/BufferedSource.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Printers.scala41
-rw-r--r--src/reflect/scala/reflect/internal/ReificationSupport.scala2
-rw-r--r--src/repl/scala/tools/nsc/interpreter/JavapClass.scala96
-rw-r--r--src/scaladoc/scala/tools/nsc/doc/DocFactory.scala6
-rw-r--r--test/files/neg/t8675.check11
-rw-r--r--test/files/neg/t8675.scala24
-rw-r--r--test/files/neg/t8675b.check6
-rw-r--r--test/files/neg/t8675b.scala22
-rw-r--r--test/files/run/t8690.check2
-rw-r--r--test/files/run/t8690.scala12
-rw-r--r--test/files/scalacheck/quasiquotes/TermConstructionProps.scala12
-rw-r--r--test/junit/scala/reflect/internal/PrintersTest.scala77
25 files changed, 333 insertions, 132 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 9b9e641cad..b6d37ab9a7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -12,21 +12,47 @@ import scala.collection.{ mutable, immutable }
import mutable.ListBuffer
import symtab.Flags._
-/** This phase adds super accessors for all super calls that either
+/** This phase performs the following functions, each of which could be split out in a
+ * mini-phase:
+ *
+ * (1) Adds super accessors for all super calls that either
* appear in a trait or have as a target a member of some outer class.
- * It also replaces references to parameter accessors with aliases
- * by super references to these aliases. The phase also checks that
- * symbols accessed from super are not abstract, or are overridden by
- * an abstract override. Finally, the phase also mangles the names
- * of class-members which are private up to an enclosing non-package
- * class, in order to avoid overriding conflicts.
*
- * This phase also sets SPECIALIZED flag on type parameters with
+ * (2) Converts references to parameter fields that have the same name as a corresponding
+ * public parameter field in a superclass to a reference to the superclass
+ * field (corresponding = super class field is initialized with subclass field).
+ * This info is pre-computed by the `alias` field in Typer. `dotc` follows a different
+ * route; it computes everything in SuperAccessors and changes the subclass field
+ * to a forwarder instead of manipulating references. This is more modular.
+ *
+ * (3) Adds protected accessors if the access to the protected member happens
+ * in a class which is not a subclass of the member's owner.
+ *
+ * (4) Mangles the names of class-members which are
+ * private up to an enclosing non-package class, in order to avoid overriding conflicts.
+ * This is a dubious, and it would be better to deprecate class-qualified privates.
+ *
+ * (5) This phase also sets SPECIALIZED flag on type parameters with
* `@specialized` annotation. We put this logic here because the
* flag must be set before pickling.
*
- * @author Martin Odersky
- * @version 1.0
+ * It also checks that:
+ *
+ * (1) Symbols accessed from super are not abstract, or are overridden by
+ * an abstract override.
+ *
+ * (2) If a symbol accessed accessed from super is defined in a real class (not a trait),
+ * there are no abstract members which override this member in Java's rules
+ * (see SI-4989; such an access would lead to illegal bytecode)
+ *
+ * (3) Super calls do not go to some synthetic members of Any (see isDisallowed)
+ *
+ * (4) Super calls do not go to synthetic field accessors
+ *
+ * (5) A class and its companion object do not both define a class or module with the
+ * same name.
+ *
+ * TODO: Rename phase to "Accessors" because it handles more than just super accessors
*/
abstract class SuperAccessors extends transform.Transform with transform.TypingTransformers {
import global._
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 66b1c2d87a..9a4d5e3c06 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -4399,7 +4399,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
if (retry) {
val Select(qual, name) = fun
tryTypedArgs(args, forArgMode(fun, mode)) match {
- case Some(args1) =>
+ case Some(args1) if !args1.exists(arg => arg.exists(_.isErroneous)) =>
val qual1 =
if (!pt.isError) adaptToArguments(qual, name, args1, pt, reportAmbiguous = true, saveErrors = true)
else qual
diff --git a/src/library/scala/collection/Iterable.scala b/src/library/scala/collection/Iterable.scala
index a5ab8efd5c..afbffd36c6 100644
--- a/src/library/scala/collection/Iterable.scala
+++ b/src/library/scala/collection/Iterable.scala
@@ -38,7 +38,7 @@ trait Iterable[+A] extends Traversable[A]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
* @define coll iterable collection
* @define Coll `Iterable`
*/
diff --git a/src/library/scala/collection/SetLike.scala b/src/library/scala/collection/SetLike.scala
index 0c5c7e0b29..3e549f72cd 100644
--- a/src/library/scala/collection/SetLike.scala
+++ b/src/library/scala/collection/SetLike.scala
@@ -17,6 +17,9 @@ import parallel.ParSet
/** A template trait for sets.
*
* $setNote
+ * '''Implementation note:'''
+ * This trait provides most of the operations of a `Set` independently of its representation.
+ * It is typically inherited by concrete implementations of sets.
* $setTags
* @since 2.8
*
@@ -24,10 +27,6 @@ import parallel.ParSet
*
* A set is a collection that contains no duplicate elements.
*
- * '''Implementation note:'''
- * This trait provides most of the operations of a `Set` independently of its representation.
- * It is typically inherited by concrete implementations of sets.
- *
* To implement a concrete set, you need to provide implementations of the
* following methods:
* {{{
diff --git a/src/library/scala/collection/Traversable.scala b/src/library/scala/collection/Traversable.scala
index b53724c568..a35750a35f 100644
--- a/src/library/scala/collection/Traversable.scala
+++ b/src/library/scala/collection/Traversable.scala
@@ -87,7 +87,7 @@ trait Traversable[+A] extends TraversableLike[A, Traversable[A]]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
*/
object Traversable extends TraversableFactory[Traversable] { self =>
diff --git a/src/library/scala/collection/convert/DecorateAsScala.scala b/src/library/scala/collection/convert/DecorateAsScala.scala
index c724831c54..5448f5f91c 100644
--- a/src/library/scala/collection/convert/DecorateAsScala.scala
+++ b/src/library/scala/collection/convert/DecorateAsScala.scala
@@ -135,6 +135,12 @@ trait DecorateAsScala {
* If the Java `Map` was previously obtained from an implicit or explicit
* call of `asMap(scala.collection.mutable.Map)` then the original
* Scala `Map` will be returned.
+ *
+ * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`),
+ * it is your responsibility to wrap all
+ * non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
*
* @param m The `Map` to be converted.
* @return An object with an `asScala` method that returns a Scala mutable
diff --git a/src/library/scala/collection/convert/WrapAsScala.scala b/src/library/scala/collection/convert/WrapAsScala.scala
index d4ab451b0d..ab151a6778 100644
--- a/src/library/scala/collection/convert/WrapAsScala.scala
+++ b/src/library/scala/collection/convert/WrapAsScala.scala
@@ -133,7 +133,13 @@ trait WrapAsScala {
* If the Java `Map` was previously obtained from an implicit or
* explicit call of `mapAsScalaMap(scala.collection.mutable.Map)` then
* the original Scala Map will be returned.
- *
+ *
+ * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`),
+ * it is your responsibility to wrap all
+ * non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
+ *
* @param m The Map to be converted.
* @return A Scala mutable Map view of the argument.
*/
diff --git a/src/library/scala/collection/convert/Wrappers.scala b/src/library/scala/collection/convert/Wrappers.scala
index 7d1d6b3781..9f9732c62f 100644
--- a/src/library/scala/collection/convert/Wrappers.scala
+++ b/src/library/scala/collection/convert/Wrappers.scala
@@ -288,6 +288,13 @@ private[collection] trait Wrappers {
override def empty: Repr = null.asInstanceOf[Repr]
}
+ /** Wraps a Java map as a Scala one. If the map is to support concurrent access,
+ * use [[JConcurrentMapWrapper]] instead. If the wrapped map is synchronized
+ * (e.g. from `java.util.Collections.synchronizedMap`), it is your responsibility
+ * to wrap all non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
+ */
case class JMapWrapper[A, B](underlying : ju.Map[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JMapWrapper[A, B]] {
override def empty = JMapWrapper(new ju.HashMap[A, B])
}
@@ -314,6 +321,10 @@ private[collection] trait Wrappers {
def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval)
}
+ /** Wraps a concurrent Java map as a Scala one. Single-element concurrent
+ * access is supported; multi-element operations such as maps and filters
+ * are not guaranteed to be atomic.
+ */
case class JConcurrentMapWrapper[A, B](underlying: juc.ConcurrentMap[A, B]) extends mutable.AbstractMap[A, B] with JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]] with concurrent.Map[A, B] {
override def get(k: A) = {
val v = underlying get k
diff --git a/src/library/scala/collection/immutable/Iterable.scala b/src/library/scala/collection/immutable/Iterable.scala
index 6e4eb1e45f..df322396d0 100644
--- a/src/library/scala/collection/immutable/Iterable.scala
+++ b/src/library/scala/collection/immutable/Iterable.scala
@@ -35,6 +35,7 @@ trait Iterable[+A] extends Traversable[A]
}
/** $factoryInfo
+ * The current default implementation of a $Coll is a `List`.
* @define Coll `immutable.Iterable`
* @define coll immutable iterable collection
*/
diff --git a/src/library/scala/collection/immutable/Traversable.scala b/src/library/scala/collection/immutable/Traversable.scala
index 775d635fae..5fc0607a00 100644
--- a/src/library/scala/collection/immutable/Traversable.scala
+++ b/src/library/scala/collection/immutable/Traversable.scala
@@ -29,7 +29,7 @@ trait Traversable[+A] extends scala.collection.Traversable[A]
}
/** $factoryInfo
- * The current default implementation of a $Coll is a `Vector`.
+ * The current default implementation of a $Coll is a `List`.
* @define coll immutable traversable collection
* @define Coll `immutable.Traversable`
*/
diff --git a/src/library/scala/collection/mutable/SetLike.scala b/src/library/scala/collection/mutable/SetLike.scala
index d749167870..a377b03124 100644
--- a/src/library/scala/collection/mutable/SetLike.scala
+++ b/src/library/scala/collection/mutable/SetLike.scala
@@ -16,19 +16,20 @@ import scala.annotation.migration
import parallel.mutable.ParSet
/** A template trait for mutable sets of type `mutable.Set[A]`.
+ *
+ * This trait provides most of the operations of a `mutable.Set` independently of its representation.
+ * It is typically inherited by concrete implementations of sets.
+ *
+ * $setNote
+ *
* @tparam A the type of the elements of the set
* @tparam This the type of the set itself.
*
- * $setnote
- *
* @author Martin Odersky
* @version 2.8
* @since 2.8
*
- * @define setnote
- * @note
- * This trait provides most of the operations of a `mutable.Set` independently of its representation.
- * It is typically inherited by concrete implementations of sets.
+ * @define setNote
*
* To implement a concrete mutable set, you need to provide implementations
* of the following methods:
@@ -36,13 +37,13 @@ import parallel.mutable.ParSet
* def contains(elem: A): Boolean
* def iterator: Iterator[A]
* def += (elem: A): this.type
- * def -= (elem: A): this.type</pre>
+ * def -= (elem: A): this.type
* }}}
* If you wish that methods like `take`,
* `drop`, `filter` return the same kind of set,
* you should also override:
* {{{
- * def empty: This</pre>
+ * def empty: This
* }}}
* It is also good idea to override methods `foreach` and
* `size` for efficiency.
diff --git a/src/library/scala/collection/mutable/UnrolledBuffer.scala b/src/library/scala/collection/mutable/UnrolledBuffer.scala
index 1f89199bdc..693c47d86e 100644
--- a/src/library/scala/collection/mutable/UnrolledBuffer.scala
+++ b/src/library/scala/collection/mutable/UnrolledBuffer.scala
@@ -300,27 +300,33 @@ object UnrolledBuffer extends ClassTagTraversableFactory[UnrolledBuffer] {
if (next eq null) true else false // checks if last node was thrown out
} else false
- @tailrec final def insertAll(idx: Int, t: scala.collection.Traversable[T], buffer: UnrolledBuffer[T]): Unit = if (idx < size) {
- // divide this node at the appropriate position and insert all into head
- // update new next
- val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff)
- Array.copy(array, idx, newnextnode.array, 0, size - idx)
- newnextnode.size = size - idx
- newnextnode.next = next
-
- // update this
- nullout(idx, size)
- size = idx
- next = null
-
- // insert everything from iterable to this
- var curr = this
- for (elem <- t) curr = curr append elem
- curr.next = newnextnode
-
- // try to merge the last node of this with the newnextnode
- if (curr.tryMergeWithNext()) buffer.lastPtr = curr
- } else insertAll(idx - size, t, buffer)
+ @tailrec final def insertAll(idx: Int, t: scala.collection.Traversable[T], buffer: UnrolledBuffer[T]): Unit = {
+ if (idx < size) {
+ // divide this node at the appropriate position and insert all into head
+ // update new next
+ val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff)
+ Array.copy(array, idx, newnextnode.array, 0, size - idx)
+ newnextnode.size = size - idx
+ newnextnode.next = next
+
+ // update this
+ nullout(idx, size)
+ size = idx
+ next = null
+
+ // insert everything from iterable to this
+ var curr = this
+ for (elem <- t) curr = curr append elem
+ curr.next = newnextnode
+
+ // try to merge the last node of this with the newnextnode
+ if (curr.tryMergeWithNext()) buffer.lastPtr = curr
+ }
+ else if (idx == size) {
+ var curr = this
+ for (elem <- t) curr = curr append elem
+ } else insertAll(idx - size, t, buffer)
+ }
private def nullout(from: Int, until: Int) {
var idx = from
while (idx < until) {
diff --git a/src/library/scala/io/BufferedSource.scala b/src/library/scala/io/BufferedSource.scala
index 1c87a1f421..52fa525b24 100644
--- a/src/library/scala/io/BufferedSource.scala
+++ b/src/library/scala/io/BufferedSource.scala
@@ -93,7 +93,7 @@ class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val cod
val buf = new Array[Char](bufferSize)
var n = 0
while (n != -1) {
- n = charReader.read(buf)
+ n = allReader.read(buf)
if (n>0) sb.appendAll(buf, 0, n)
}
sb.result
diff --git a/src/reflect/scala/reflect/internal/Printers.scala b/src/reflect/scala/reflect/internal/Printers.scala
index fcc377ba32..2ce861898f 100644
--- a/src/reflect/scala/reflect/internal/Printers.scala
+++ b/src/reflect/scala/reflect/internal/Printers.scala
@@ -596,18 +596,26 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
}
- protected def emptyTree(tree: Tree) = tree match {
- case EmptyTree | build.SyntacticEmptyTypeTree() => true
- case _ => false
+ object EmptyTypeTree {
+ def unapply(tt: TypeTree): Boolean = tt match {
+ case build.SyntacticEmptyTypeTree() if tt.wasEmpty || tt.isEmpty => true
+ case _ => false
+ }
}
+ protected def isEmptyTree(tree: Tree) =
+ tree match {
+ case EmptyTree | EmptyTypeTree() => true
+ case _ => false
+ }
+
protected def originalTypeTrees(trees: List[Tree]) =
- trees.filter(!emptyTree(_)) map {
- case tt: TypeTree => tt.original
- case tree => tree
+ trees.filter(!isEmptyTree(_)) map {
+ case tt: TypeTree if tt.original != null => tt.original
+ case tree => tree
}
- val defaultClasses = List(tpnme.AnyRef)
+ val defaultClasses = List(tpnme.AnyRef, tpnme.Object)
val defaultTraitsForCase = List(tpnme.Product, tpnme.Serializable)
protected def removeDefaultTypesFromList(trees: List[Tree])(classesToRemove: List[Name] = defaultClasses)(traitsToRemove: List[Name]) = {
def removeDefaultTraitsFromList(trees: List[Tree], traitsToRemove: List[Name]): List[Tree] =
@@ -623,9 +631,10 @@ trait Printers extends api.Printers { self: SymbolTable =>
removeDefaultTraitsFromList(removeDefaultClassesFromList(trees, classesToRemove), traitsToRemove)
}
- protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
+ protected def removeDefaultClassesFromList(trees: List[Tree], classesToRemove: List[Name] = defaultClasses) =
originalTypeTrees(trees) filter {
case Select(Ident(sc), name) => !(classesToRemove.contains(name) && sc == nme.scala_)
+ case tt: TypeTree if tt.tpe != null => !(classesToRemove contains(newTypeName(tt.tpe.toString())))
case _ => true
}
@@ -637,7 +646,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
}
override def printOpt(prefix: String, tree: Tree) =
- if (!emptyTree(tree)) super.printOpt(prefix, tree)
+ if (!isEmptyTree(tree)) super.printOpt(prefix, tree)
override def printColumn(ts: List[Tree], start: String, sep: String, end: String) = {
super.printColumn(ts.filter(!syntheticToRemove(_)), start, sep, end)
@@ -952,7 +961,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
def printTp = print("(", tp, ")")
tp match {
- case EmptyTree | build.SyntacticEmptyTypeTree() => printTp
+ case EmptyTree | EmptyTypeTree() => printTp
// case for untypechecked trees
case Annotated(annot, arg) if (expr ne null) && (arg ne null) && expr.equalsStructure(arg) => printTp // remove double arg - 5: 5: @unchecked
case tt: TypeTree if tt.original.isInstanceOf[Annotated] => printTp
@@ -963,7 +972,7 @@ trait Printers extends api.Printers { self: SymbolTable =>
// print only fun when targs are TypeTrees with empty original
case TypeApply(fun, targs) =>
- if (targs.exists(emptyTree(_))) {
+ if (targs.exists(isEmptyTree(_))) {
print(fun)
} else super.printTree(tree)
@@ -984,8 +993,8 @@ trait Printers extends api.Printers { self: SymbolTable =>
case treeInfo.Unapplied(body) =>
body match {
case Select(qual, name) if name == nme.unapply => print(qual)
- case TypeApply(Select(qual, name), args) if name == nme.unapply || name == nme.unapplySeq =>
- print(TypeApply(qual, args))
+ case TypeApply(Select(qual, name), _) if name == nme.unapply || name == nme.unapplySeq =>
+ print(qual)
case _ => print(body)
}
case _ => print(fun)
@@ -1061,7 +1070,11 @@ trait Printers extends api.Printers { self: SymbolTable =>
print("(", qualifier, ")#", blankForOperatorName(selector), printedName(selector))
case tt: TypeTree =>
- if (!emptyTree(tt)) print(tt.original)
+ if (!isEmptyTree(tt)) {
+ val original = tt.original
+ if (original != null) print(original)
+ else super.printTree(tree)
+ }
case AppliedTypeTree(tp, args) =>
// it's possible to have (=> String) => String type but Function1[=> String, String] is not correct
diff --git a/src/reflect/scala/reflect/internal/ReificationSupport.scala b/src/reflect/scala/reflect/internal/ReificationSupport.scala
index ad8a2594dd..2caa30d27e 100644
--- a/src/reflect/scala/reflect/internal/ReificationSupport.scala
+++ b/src/reflect/scala/reflect/internal/ReificationSupport.scala
@@ -97,6 +97,8 @@ trait ReificationSupport { self: SymbolTable =>
def toStats(tree: Tree): List[Tree] = tree match {
case EmptyTree => Nil
case SyntacticBlock(stats) => stats
+ case defn if defn.isDef => defn :: Nil
+ case imp: Import => imp :: Nil
case _ => throw new IllegalArgumentException(s"can't flatten $tree")
}
diff --git a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala
index 915fd57bf8..3cb6ba11c1 100644
--- a/src/repl/scala/tools/nsc/interpreter/JavapClass.scala
+++ b/src/repl/scala/tools/nsc/interpreter/JavapClass.scala
@@ -41,16 +41,16 @@ class JavapClass(
* Byte data for filename args is retrieved with findBytes.
*/
def apply(args: Seq[String]): List[JpResult] = {
- val (options, claases) = args partition (s => (s startsWith "-") && s.length > 1)
+ val (options, classes) = args partition (s => (s startsWith "-") && s.length > 1)
val (flags, upgraded) = upgrade(options)
import flags.{ app, fun, help, raw }
- val targets = if (fun && !help) FunFinder(loader, intp).funs(claases) else claases
- if (help || claases.isEmpty)
+ val targets = if (fun && !help) FunFinder(loader, intp).funs(classes) else classes
+ if (help || classes.isEmpty)
List(JpResult(JavapTool.helper(printWriter)))
else if (targets.isEmpty)
List(JpResult("No anonfuns found."))
else
- tool(raw, upgraded)(targets map (claas => targeted(claas, app)))
+ tool(raw, upgraded)(targets map (klass => targeted(klass, app)))
}
/** Cull our tool options. */
@@ -67,17 +67,18 @@ class JavapClass(
case f: Failure[_] => (path, Failure(f.exception))
}
- /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar"). */
+ /** Find bytes. Handle "-", "-app", "Foo#bar" (by ignoring member), "#bar" (by taking "bar").
+ * @return the path to use for filtering, and the byte array
+ */
private def bytesFor(path: String, app: Boolean) = Try {
def last = intp.get.mostRecentVar // fail if no intp
- def req = path match {
- case "-" => last
- case HashSplit(prefix, member) =>
- if (prefix != null) prefix
- else if (member != null) member
- else "#"
+ val req = path match {
+ case "-" => last
+ case HashSplit(prefix, _) if prefix != null => prefix
+ case HashSplit(_, member) if member != null => member
+ case s => s
}
- val targetedBytes = if (app) findAppBody(req) else (req, findBytes(req))
+ val targetedBytes = if (app) findAppBody(req) else (path, findBytes(req))
if (targetedBytes._2.isEmpty) throw new FileNotFoundException(s"Could not find class bytes for '$path'")
targetedBytes
}
@@ -217,27 +218,36 @@ class JavapClass(
// if apply is added here, it's for other than -fun: javap Foo#, perhaps m#?
val filterOn = target.splitHashMember._2 map { s => if (s.isEmpty) "apply" else s }
var filtering = false // true if in region matching filter
- // true to output
- def checkFilter(line: String) = if (filterOn.isEmpty) true else {
+ // turn filtering on/off given the pattern of interest
+ def filterStatus(line: String, pattern: String) = {
// cheap heuristic, todo maybe parse for the java sig.
// method sigs end in paren semi
def isAnyMethod = line.endsWith(");")
def isOurMethod = {
val lparen = line.lastIndexOf('(')
val blank = line.lastIndexOf(' ', lparen)
- (blank >= 0 && line.substring(blank+1, lparen) == filterOn.get)
- }
- filtering = if (filtering) {
- // next blank line terminates section
- // for -public, next line is next method, more or less
- line.trim.nonEmpty && !isAnyMethod
- } else {
- isAnyMethod && isOurMethod
+ if (blank < 0) false
+ else {
+ val method = line.substring(blank+1, lparen)
+ (method == pattern || ((method startsWith pattern+"$") && (method endsWith "$sp")))
+ }
}
+ filtering =
+ if (filtering) {
+ // next blank line terminates section
+ // for -public, next line is next method, more or less
+ line.trim.nonEmpty && !isAnyMethod
+ } else {
+ isAnyMethod && isOurMethod
+ }
filtering
}
- for (line <- Source.fromString(preamble + written).getLines(); if checkFilter(line))
- printWriter write line+lineSeparator
+ // do we output this line?
+ def checkFilter(line: String) = filterOn map (filterStatus(line, _)) getOrElse true
+ for {
+ line <- Source.fromString(preamble + written).getLines()
+ if checkFilter(line)
+ } printWriter write f"$line%n"
printWriter.flush()
}
}
@@ -275,7 +285,7 @@ class JavapClass(
override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] =
(inputs map {
- case (claas, Success(ba)) => JpResult(showable(raw, claas, newPrinter(new ByteArrayInputStream(ba), newEnv(options))))
+ case (klass, Success(ba)) => JpResult(showable(raw, klass, newPrinter(new ByteArrayInputStream(ba), newEnv(options))))
case (_, Failure(e)) => JpResult(e.toString)
}).toList orFailed List(noToolError)
}
@@ -290,10 +300,10 @@ class JavapClass(
//object TaskResult extends Enumeration {
// val Ok, Error, CmdErr, SysErr, Abnormal = Value
//}
- val TaskClaas = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull
- override protected def failed = TaskClaas eq null
+ val TaskClass = loader.tryToInitializeClass[Task](JavapTool.Tool).orNull
+ override protected def failed = TaskClass eq null
- val TaskCtor = TaskClaas.getConstructor(
+ val TaskCtor = TaskClass.getConstructor(
classOf[Writer],
classOf[JavaFileManager],
classOf[DiagnosticListener[_]],
@@ -344,8 +354,12 @@ class JavapClass(
import Kind._
import StandardLocation._
import JavaFileManager.Location
- import java.net.URI
- def uri(name: String): URI = new URI(name) // new URI("jfo:" + name)
+ import java.net.{ URI, URISyntaxException }
+
+ // name#fragment is OK, but otherwise fragile
+ def uri(name: String): URI =
+ try new URI(name) // new URI("jfo:" + name)
+ catch { case _: URISyntaxException => new URI("dummy") }
def inputNamed(name: String): Try[ByteAry] = (managed find (_._1 == name)).get._2
def managedFile(name: String, kind: Kind) = kind match {
@@ -379,19 +393,19 @@ class JavapClass(
def showable(raw: Boolean, target: String): Showable = showWithPreamble(raw, target, reporter.reportable(raw))
// eventually, use the tool interface
- def task(options: Seq[String], claases: Seq[String], inputs: Seq[Input]): Task = {
+ def task(options: Seq[String], classes: Seq[String], inputs: Seq[Input]): Task = {
//ServiceLoader.load(classOf[javax.tools.DisassemblerTool]).
- //getTask(writer, fileManager, reporter, options.asJava, claases.asJava)
+ //getTask(writer, fileManager, reporter, options.asJava, classes.asJava)
import JavaConverters.asJavaIterableConverter
- TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, claases.asJava)
+ TaskCtor.newInstance(writer, fileManager(inputs), reporter, options.asJava, classes.asJava)
.orFailed (throw new IllegalStateException)
}
// a result per input
- private def applyOne(raw: Boolean, options: Seq[String], claas: String, inputs: Seq[Input]): Try[JpResult] =
+ private def applyOne(raw: Boolean, options: Seq[String], klass: String, inputs: Seq[Input]): Try[JpResult] =
Try {
- task(options, Seq(claas), inputs).call()
+ task(options, Seq(klass), inputs).call()
} map {
- case true => JpResult(showable(raw, claas))
+ case true => JpResult(showable(raw, klass))
case _ => JpResult(reporter.reportable(raw))
} recoverWith {
case e: java.lang.reflect.InvocationTargetException => e.getCause match {
@@ -402,7 +416,7 @@ class JavapClass(
reporter.clear()
}
override def apply(raw: Boolean, options: Seq[String])(inputs: Seq[Input]): List[JpResult] = (inputs map {
- case (claas, Success(_)) => applyOne(raw, options, claas, inputs).get
+ case (klass, Success(_)) => applyOne(raw, options, klass, inputs).get
case (_, Failure(e)) => JpResult(e.toString)
}).toList orFailed List(noToolError)
}
@@ -534,6 +548,7 @@ class JavapClass(
private def isTaskable(cl: ScalaClassLoader) = hasClass(cl, Tool)
+ /** Select the tool implementation for this platform. */
def apply() = if (isTaskable(loader)) new JavapTool7 else new JavapTool6
}
}
@@ -545,7 +560,8 @@ object JavapClass {
intp: Option[IMain] = None
) = new JavapClass(loader, printWriter, intp)
- val HashSplit = "(.*?)(?:#([^#]*))?".r
+ val HashSplit = "([^#]+)?(?:#(.+)?)?".r
+
// We enjoy flexibility in specifying either a fully-qualified class name com.acme.Widget
// or a resource path com/acme/Widget.class; but not widget.out
implicit class MaybeClassLike(val s: String) extends AnyVal {
@@ -580,11 +596,11 @@ object JavapClass {
/* only the file location from which the given class is loaded */
def locate(k: String): Option[Path] = {
Try {
- val claas = try cl loadClass k catch {
+ val klass = try cl loadClass k catch {
case _: NoClassDefFoundError => null // let it snow
}
// cf ScalaClassLoader.originOfClass
- claas.getProtectionDomain.getCodeSource.getLocation
+ klass.getProtectionDomain.getCodeSource.getLocation
} match {
case Success(null) => None
case Success(loc) if loc.isFile => Some(Path(new JFile(loc.toURI)))
diff --git a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
index dce52af56a..47ddfb8aa9 100644
--- a/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
+++ b/src/scaladoc/scala/tools/nsc/doc/DocFactory.scala
@@ -95,11 +95,11 @@ class DocFactory(val reporter: Reporter, val settings: doc.Settings) { processor
val documentError: PartialFunction[Throwable, Unit] = {
case NoCompilerRunException =>
reporter.info(null, "No documentation generated with unsuccessful compiler run", force = false)
- case _: ClassNotFoundException =>
- ()
+ case e @ (_:ClassNotFoundException | _:IllegalAccessException | _:InstantiationException | _:SecurityException | _:ClassCastException) =>
+ reporter.error(null, s"Cannot load the doclet class ${settings.docgenerator.value} (specified with ${settings.docgenerator.name}): $e. Leaving the default settings will generate the html version of scaladoc.")
}
- /** Generate document(s) for all `files` containing scaladoc documenataion.
+ /** Generate document(s) for all `files` containing scaladoc documentation.
* @param files The list of paths (relative to the compiler's source path, or absolute) of files to document. */
def document(files: List[String]) {
def generate() = {
diff --git a/test/files/neg/t8675.check b/test/files/neg/t8675.check
new file mode 100644
index 0000000000..4e44fba918
--- /dev/null
+++ b/test/files/neg/t8675.check
@@ -0,0 +1,11 @@
+t8675.scala:13: error: type mismatch;
+ found : Boolean(true)
+ required: String
+ a.update(0, x[A]({new isString(true)})) // !!! allowed
+ ^
+t8675.scala:22: error: type mismatch;
+ found : Boolean(true)
+ required: String
+ new X().m(x[A]({new isString(true)})) // !!! allowed
+ ^
+two errors found
diff --git a/test/files/neg/t8675.scala b/test/files/neg/t8675.scala
new file mode 100644
index 0000000000..ca9bb57ffa
--- /dev/null
+++ b/test/files/neg/t8675.scala
@@ -0,0 +1,24 @@
+class A(s: String) {
+ def foo(x: A) = x
+}
+
+class isString(s: String)
+
+class Test {
+
+ def x[A](a: Any): A = ???
+
+ def test {
+ val a = Array[A]()
+ a.update(0, x[A]({new isString(true)})) // !!! allowed
+
+ // boils down to
+ class X {
+ def m(p: Any) {}
+ }
+ implicit class XOps(x: X) {
+ def m(p: Any) {}
+ }
+ new X().m(x[A]({new isString(true)})) // !!! allowed
+ }
+}
diff --git a/test/files/neg/t8675b.check b/test/files/neg/t8675b.check
new file mode 100644
index 0000000000..cb7ac8af59
--- /dev/null
+++ b/test/files/neg/t8675b.check
@@ -0,0 +1,6 @@
+t8675b.scala:19: error: missing parameter type for expanded function
+The argument types of an anonymous function must be fully known. (SLS 8.5)
+Expected type was: List[Test.Reportable1[?,?]] => Boolean
+ for (path: List[Any] <- (null : Engine1).asRequirement.pathsIncludingSelf.toList) {
+ ^
+one error found
diff --git a/test/files/neg/t8675b.scala b/test/files/neg/t8675b.scala
new file mode 100644
index 0000000000..2c5015b1d0
--- /dev/null
+++ b/test/files/neg/t8675b.scala
@@ -0,0 +1,22 @@
+object Test {
+ trait Engine1
+
+ implicit class EngineTools1[Params, R](e: Engine1) {
+ def asRequirement: Requirement1[Params, R] = ???
+ }
+ trait Requirement1[Params, R] {
+ def pathsIncludingSelf: Traversable[List[Reportable1[Params, R]]]
+ }
+ trait Reportable1[Params, R]
+
+ // "missing paramater type" error was swallowed in 2.11.0 leading to a crash
+ // in the backend.
+ //
+ // This error is itself a regression (or at least a change) in 2.11.0-M7,
+ // specifically in SI-7944. The type paramaters to the implicit view
+ // `EngineTools1` are undetermined, and are now treated as type variables
+ // in the expected type of the closure argument to `withFilter`.
+ for (path: List[Any] <- (null : Engine1).asRequirement.pathsIncludingSelf.toList) {
+ ???
+ }
+}
diff --git a/test/files/run/t8690.check b/test/files/run/t8690.check
new file mode 100644
index 0000000000..72f076c4d8
--- /dev/null
+++ b/test/files/run/t8690.check
@@ -0,0 +1,2 @@
+non-empty iterator
+abcdef
diff --git a/test/files/run/t8690.scala b/test/files/run/t8690.scala
new file mode 100644
index 0000000000..ab8b45b2a7
--- /dev/null
+++ b/test/files/run/t8690.scala
@@ -0,0 +1,12 @@
+import scala.io.Source
+import java.io.ByteArrayInputStream
+
+object Test extends App {
+ val txt = "abcdef"
+
+ val in = new ByteArrayInputStream(txt.getBytes());
+ val source = Source.fromInputStream(in);
+ println(source.toString) // forces the BufferedSource to look at the head of the input
+
+ println(source.mkString) // used to return "bcdef" ...
+}
diff --git a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
index 45392de582..409f07037e 100644
--- a/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
+++ b/test/files/scalacheck/quasiquotes/TermConstructionProps.scala
@@ -310,4 +310,16 @@ object TermConstructionProps extends QuasiquoteProperties("term construction") {
val cases = List(cq"a => b", cq"c => d")
assertEqAst(q"{ case ..$cases }", "{ case a => b case c => d }")
}
+
+ property("SI-8609 a") = test {
+ val q1 = q"val x = 1"
+ val q2 = q"..$q1; val y = 2"
+ assert(q2 ≈ q"{ val x = 1; val y = 2 }")
+ }
+
+ property("SI-8609 b") = test {
+ val q1 = q"import foo.bar"
+ val q2 = q"..$q1; val y = 2"
+ assert(q2 ≈ q"{ import foo.bar; val y = 2 }")
+ }
}
diff --git a/test/junit/scala/reflect/internal/PrintersTest.scala b/test/junit/scala/reflect/internal/PrintersTest.scala
index 4587417a99..1458b942dc 100644
--- a/test/junit/scala/reflect/internal/PrintersTest.scala
+++ b/test/junit/scala/reflect/internal/PrintersTest.scala
@@ -33,10 +33,10 @@ object PrinterHelper {
def wrapCode(source: String) = {
val context = sm"""
|trait PrintersContext {
- | class baz extends scala.annotation.StaticAnnotation;
- | class foo1[A, B] extends scala.annotation.StaticAnnotation;
- | class foo2[A, B](a: scala.Int)(b: scala.Int) extends scala.annotation.StaticAnnotation;
- | class foo3[Af, Bf](a: scala.Int)(b: scala.Float, c: PrintersContext.this.foo1[Af, Bf]) extends scala.annotation.StaticAnnotation;
+ | class baz extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
+ | class foo1[A, B] extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
+ | class foo2[A, B](a: scala.Int)(b: scala.Int) extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
+ | class foo3[Af, Bf](a: scala.Int)(b: scala.Float, c: PrintersContext.this.foo1[Af, Bf]) extends scala.annotation.Annotation with scala.annotation.StaticAnnotation;
| trait A1;
| trait B1;
|${source.trim.lines map {" " + _} mkString s"$LF"}
@@ -54,8 +54,12 @@ object PrinterHelper {
}
}
- def assertTreeCode(tree: Tree)(code: String) = {
- assertEquals("using quasiquote or given tree"+LF, code.trim, normalizeEOL(showCode(tree)))
+ def assertTreeCode(tree: Tree, typecheck: Boolean = false)(code: String) = {
+ if (typecheck) {
+ assertEquals("using quasiquote or given tree (typechecked)"+LF, code.trim, normalizeEOL(showCode(toolbox.typecheck(tree))))
+ } else {
+ assertEquals("using quasiquote or given tree"+LF, code.trim, normalizeEOL(showCode(tree)))
+ }
}
def assertPrintedCode(source: String, checkTypedTree: Boolean = true, wrapCode: Boolean = false) = {
@@ -312,17 +316,17 @@ trait BasePrintTests {
@Test def testFunc1 = assertResultCode(
code = "List(1, 2, 3).map((i: Int) => i - 1)")(
parsedCode = "List(1, 2, 3).map(((i: Int) => i.-(1)))",
- typedCode = sm"scala.collection.immutable.List.apply(1, 2, 3).map(((i: scala.Int) => i.-(1)))(scala.collection.immutable.List.canBuildFrom)")
+ typedCode = sm"scala.collection.immutable.List.apply[Int](1, 2, 3).map[Int, List[Int]](((i: scala.Int) => i.-(1)))(scala.collection.immutable.List.canBuildFrom[Int])")
@Test def testFunc2 = assertResultCode(
code = "val sum: Seq[Int] => Int = _ reduceLeft (_+_)")(
parsedCode = "val sum: _root_.scala.Function1[Seq[Int], Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))",
- typedCode = "val sum: _root_.scala.Function1[scala.`package`.Seq[scala.Int], scala.Int] = ((x$1) => x$1.reduceLeft(((x$2, x$3) => x$2.+(x$3))))")
+ typedCode = "val sum: _root_.scala.Function1[scala.`package`.Seq[scala.Int], scala.Int] = ((x$1: Seq[Int]) => x$1.reduceLeft[Int](((x$2: Int, x$3: Int) => x$2.+(x$3))))")
@Test def testFunc3 = assertResultCode(
code = "List(1, 2, 3) map (_ - 1)")(
parsedCode = "List(1, 2, 3).map(((x$1) => x$1.-(1))) ",
- typedCode = "scala.collection.immutable.List.apply(1, 2, 3).map(((x$1) => x$1.-(1)))(scala.collection.immutable.List.canBuildFrom)")
+ typedCode = "scala.collection.immutable.List.apply[Int](1, 2, 3).map[Int, List[Int]](((x$1: Int) => x$1.-(1)))(scala.collection.immutable.List.canBuildFrom[Int])")
@Test def testFunc4 = assertResultCode(
code = "val x: String => Int = ((str: String) => 1)")(
@@ -401,7 +405,8 @@ trait ClassPrintTests {
@Test def testClassWithImplicitParams = assertPrintedCode("class X(var i: scala.Int)(implicit val d: scala.Double, var f: scala.Float)")
- @Test def testClassWithEarly = assertPrintedCode(sm"""
+ @Test def testClassWithEarly =
+ assertPrintedCode(sm"""
|class X(var i: scala.Int) extends {
| val a = i;
| type B
@@ -419,15 +424,22 @@ trait ClassPrintTests {
| throw Throw2.this.e
|}""")
- /*
- class Test {
- val (a, b) = (1, 2)
- }
- */
- @Test def testClassWithAssignmentWithTuple1 = assertPrintedCode(sm"""
+ @Test def testClassWithAssignmentWithTuple1 = assertResultCode(sm"""
|class Test {
- | private[this] val x$$1 = (scala.Tuple2.apply(1, 2): @scala.unchecked) match {
- | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply(a, b)
+ | val (a, b) = (1, 2)
+ |}""")(
+ parsedCode = sm"""
+ |class Test {
+ | private[this] val x$$1 = (scala.Tuple2(1, 2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2(a, b)
+ | };
+ | val a = x$$1._1;
+ | val b = x$$1._2
+ |}""",
+ typedCode = sm"""
+ |class Test {
+ | private[this] val x$$1 = (scala.Tuple2.apply[Int, Int](1, 2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply[Int, Int](a, b)
| };
| val a = Test.this.x$$1._1;
| val b = Test.this.x$$1._2
@@ -448,8 +460,8 @@ trait ClassPrintTests {
|}""",
typedCode = sm"""
|class Test {
- | private[this] val x$$1 = (scala.Predef.ArrowAssoc(1).->(2): @scala.unchecked) match {
- | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply(a, b)
+ | private[this] val x$$1 = (scala.Predef.ArrowAssoc[Int](1).->[Int](2): @scala.unchecked) match {
+ | case scala.Tuple2((a @ _), (b @ _)) => scala.Tuple2.apply[Int, Int](a, b)
| };
| val a = Test.this.x$$1._1;
| val b = Test.this.x$$1._2
@@ -462,8 +474,8 @@ trait ClassPrintTests {
*/
@Test def testClassWithPatternMatchInAssignment = assertPrintedCode(sm"""
|class Test {
- | private[this] val x$$1 = (scala.collection.immutable.List.apply(1, 3, 5): @scala.unchecked) match {
- | case scala.collection.immutable.List((one @ _), (three @ _), (five @ _)) => scala.Tuple3.apply(one, three, five)
+ | private[this] val x$$1 = (scala.collection.immutable.List.apply[scala.Int](1, 3, 5): @scala.unchecked) match {
+ | case scala.collection.immutable.List((one @ _), (three @ _), (five @ _)) => scala.Tuple3.apply[scala.Int, scala.Int, scala.Int](one, three, five)
| };
| val one = Test.this.x$$1._1;
| val three = Test.this.x$$1._2;
@@ -626,7 +638,7 @@ trait ClassPrintTests {
@Test def testObjectWithPatternMatch1 = assertPrintedCode(sm"""
|object PM1 {
- | scala.collection.immutable.List.apply(1, 2) match {
+ | scala.collection.immutable.List.apply[scala.Int](1, 2) match {
| case (i @ _) => i
| }
|}""")
@@ -715,7 +727,7 @@ trait ClassPrintTests {
|}""",
typedCode = sm"""
|object PM5 {
- | scala.collection.immutable.List.apply(1, 2) match {
+ | scala.collection.immutable.List.apply[Int](1, 2) match {
| case scala.`package`.::((x @ _), (xs @ _)) => x
| }
|}""")
@@ -756,7 +768,7 @@ trait ClassPrintTests {
@Test def testObjectWithPatternMatch8 = assertPrintedCode(sm"""
|{
| object Extractor {
- | def unapply(i: scala.Int) = scala.Some.apply(i)
+ | def unapply(i: scala.Int) = scala.Some.apply[scala.Int](i)
| };
| object PM9 {
| 42 match {
@@ -991,7 +1003,7 @@ trait ValAndDefPrintTests {
@Test def testDefWithLazyVal2 = assertPrintedCode(sm"""
|def a = {
- | lazy val test = {
+ | lazy val test: Unit = {
| scala.Predef.println();
| scala.Predef.println()
| };
@@ -1161,4 +1173,17 @@ trait QuasiTreesPrintTests {
|case class X(x: Int, s: String) {
| def y = "test"
|}""")
+
+ @Test def testQuasiCaseClassWithTypes1 = assertTreeCode(q"""case class X(x: ${typeOf[Int]}, s: ${typeOf[String]}){ def y = "test" }""")(sm"""
+ |case class X(x: Int, s: String) {
+ | def y = "test"
+ |}""")
+
+ @Test def testQuasiCaseClassWithTypes2 = assertTreeCode(q"""case class X(x: ${typeOf[Int]}, s: ${typeOf[String]}){ def y = "test" }""", typecheck = true)(sm"""
+ |{
+ | case class X(x: Int, s: String) {
+ | def y = "test"
+ | };
+ | ()
+ |}""")
} \ No newline at end of file