summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala19
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala74
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala26
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala9
-rw-r--r--src/library/scala/annotation/implicitAmbiguous.scala34
-rw-r--r--src/library/scala/runtime/Tuple2Zipped.scala2
-rw-r--r--src/library/scala/runtime/Tuple3Zipped.scala2
-rw-r--r--src/reflect/scala/reflect/internal/Definitions.scala1
-rw-r--r--src/reflect/scala/reflect/internal/Symbols.scala9
-rw-r--r--src/reflect/scala/reflect/runtime/JavaUniverseForce.scala1
-rw-r--r--test/files/neg/implicit-ambiguous-2.check4
-rw-r--r--test/files/neg/implicit-ambiguous-2.scala11
-rw-r--r--test/files/neg/implicit-ambiguous-invalid.check7
-rw-r--r--test/files/neg/implicit-ambiguous-invalid.flags1
-rw-r--r--test/files/neg/implicit-ambiguous-invalid.scala6
-rw-r--r--test/files/neg/implicit-ambiguous.check4
-rw-r--r--test/files/neg/implicit-ambiguous.scala11
-rw-r--r--test/files/neg/t6666d.check4
-rw-r--r--test/files/pos/t6666d.scala (renamed from test/files/neg/t6666d.scala)0
-rw-r--r--test/files/run/idempotency-case-classes.check3
-rw-r--r--test/files/run/repl-serialization.check1
-rw-r--r--test/files/run/t9375.check60
-rw-r--r--test/files/run/t9375.scala276
-rw-r--r--test/junit/scala/collection/immutable/StreamTest.scala16
25 files changed, 512 insertions, 71 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index a079a76ce7..00a994fe87 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -778,7 +778,7 @@ abstract class Mixin extends InfoTransform with ast.TreeDSL {
val defSym = clazz.newMethod(nme.newLazyValSlowComputeName(lzyVal.name.toTermName), lzyVal.pos, PRIVATE)
val params = defSym newSyntheticValueParams args.map(_.symbol.tpe)
defSym setInfoAndEnter MethodType(params, lzyVal.tpe.resultType)
- val rhs: Tree = (gen.mkSynchronizedCheck(attrThis, cond, syncBody, stats)).changeOwner(currentOwner -> defSym)
+ val rhs: Tree = gen.mkSynchronizedCheck(attrThis, cond, syncBody, stats).changeOwner(currentOwner -> defSym)
val strictSubst = new TreeSymSubstituterWithCopying(args.map(_.symbol), params)
addDef(position(defSym), DefDef(defSym, strictSubst(BLOCK(rhs, retVal))))
defSym
diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
index 1b2e7f628e..c9d3b3da96 100644
--- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala
@@ -1212,7 +1212,8 @@ trait ContextErrors {
import definitions._
- def AmbiguousImplicitError(info1: ImplicitInfo, info2: ImplicitInfo,
+ def AmbiguousImplicitError(info1: ImplicitInfo, tree1: Tree,
+ info2: ImplicitInfo, tree2: Tree,
pre1: String, pre2: String, trailer: String)
(isView: Boolean, pt: Type, tree: Tree)(implicit context0: Context) = {
if (!info1.tpe.isErroneous && !info2.tpe.isErroneous) {
@@ -1248,10 +1249,20 @@ trait ContextErrors {
if (explanation == "") "" else "\n" + explanation
)
}
+
+ def treeTypeArgs(annotatedTree: Tree) = annotatedTree match {
+ case TypeApply(_, args) => args.map(_.toString)
+ case _ => Nil
+ }
+
context.issueAmbiguousError(AmbiguousImplicitTypeError(tree,
- if (isView) viewMsg
- else s"ambiguous implicit values:\n${coreMsg}match expected type $pt")
- )
+ (tree1.symbol, tree2.symbol) match {
+ case (ImplicitAmbiguousMsg(msg), _) => msg.format(treeTypeArgs(tree1))
+ case (_, ImplicitAmbiguousMsg(msg)) => msg.format(treeTypeArgs(tree2))
+ case (_, _) if isView => viewMsg
+ case (_, _) => s"ambiguous implicit values:\n${coreMsg}match expected type $pt"
+ }
+ ))
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 73e454bf47..2fb3ae41e2 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -887,7 +887,7 @@ trait Implicits {
* - find the most likely one
* - if it matches, forget about all others it improves upon
*/
- @tailrec private def rankImplicits(pending: Infos, acc: Infos): Infos = pending match {
+ @tailrec private def rankImplicits(pending: Infos, acc: List[(SearchResult, ImplicitInfo)]): List[(SearchResult, ImplicitInfo)] = pending match {
case Nil => acc
case firstPending :: otherPending =>
def firstPendingImproves(alt: ImplicitInfo) =
@@ -914,7 +914,7 @@ trait Implicits {
val pendingImprovingBest = undoLog undo {
otherPending filterNot firstPendingImproves
}
- rankImplicits(pendingImprovingBest, firstPending :: acc)
+ rankImplicits(pendingImprovingBest, (newBest, firstPending) :: acc)
}
}
@@ -930,14 +930,14 @@ trait Implicits {
// So if there is any element not improved upon by the first it is an error.
rankImplicits(eligible, Nil) match {
case Nil => ()
- case chosen :: rest =>
- rest find (alt => !improves(chosen, alt)) match {
- case Some(competing) =>
- AmbiguousImplicitError(chosen, competing, "both", "and", "")(isView, pt, tree)(context)
+ case (chosenResult, chosenInfo) :: rest =>
+ rest find { case (_, alt) => !improves(chosenInfo, alt) } match {
+ case Some((competingResult, competingInfo)) =>
+ AmbiguousImplicitError(chosenInfo, chosenResult.tree, competingInfo, competingResult.tree, "both", "and", "")(isView, pt, tree)(context)
return AmbiguousSearchFailure // Stop the search once ambiguity is encountered, see t4457_2.scala
case _ =>
- if (isView) chosen.useCountView += 1
- else chosen.useCountArg += 1
+ if (isView) chosenInfo.useCountView += 1
+ else chosenInfo.useCountArg += 1
}
}
@@ -1447,9 +1447,9 @@ trait Implicits {
}
}
- object ImplicitNotFoundMsg {
- def unapply(sym: Symbol): Option[(Message)] = sym.implicitNotFoundMsg match {
- case Some(m) => Some(new Message(sym, m))
+ class ImplicitAnnotationMsg(f: Symbol => Option[String], clazz: Symbol, annotationName: String) {
+ def unapply(sym: Symbol): Option[(Message)] = f(sym) match {
+ case Some(m) => Some(new Message(sym, m, annotationName))
case None if sym.isAliasType =>
// perform exactly one step of dealiasing
// this is necessary because ClassManifests are now aliased to ClassTags
@@ -1461,41 +1461,45 @@ trait Implicits {
// check the message's syntax: should be a string literal that may contain occurrences of the string "${X}",
// where `X` refers to a type parameter of `sym`
def check(sym: Symbol): Option[String] =
- sym.getAnnotation(ImplicitNotFoundClass).flatMap(_.stringArg(0) match {
- case Some(m) => new Message(sym, m).validate
- case None => Some("Missing argument `msg` on implicitNotFound annotation.")
+ sym.getAnnotation(clazz).flatMap(_.stringArg(0) match {
+ case Some(m) => new Message(sym, m, annotationName).validate
+ case None => Some(s"Missing argument `msg` on $annotationName annotation.")
})
+ }
+
+ object ImplicitNotFoundMsg extends ImplicitAnnotationMsg(_.implicitNotFoundMsg, ImplicitNotFoundClass, "implicitNotFound")
+
+ object ImplicitAmbiguousMsg extends ImplicitAnnotationMsg(_.implicitAmbiguousMsg, ImplicitAmbiguousClass, "implicitAmbiguous")
+ class Message(sym: Symbol, msg: String, annotationName: String) {
// http://dcsobral.blogspot.com/2010/01/string-interpolation-in-scala-with.html
private val Intersobralator = """\$\{\s*([^}\s]+)\s*\}""".r
- class Message(sym: Symbol, msg: String) {
- private def interpolate(text: String, vars: Map[String, String]) =
- Intersobralator.replaceAllIn(text, (_: Regex.Match) match {
- case Regex.Groups(v) => Regex quoteReplacement vars.getOrElse(v, "")
+ private def interpolate(text: String, vars: Map[String, String]) =
+ Intersobralator.replaceAllIn(text, (_: Regex.Match) match {
+ case Regex.Groups(v) => Regex quoteReplacement vars.getOrElse(v, "")
// #3915: need to quote replacement string since it may include $'s (such as the interpreter's $iw)
- })
+ })
- private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName)
- private def typeArgsAtSym(paramTp: Type) = paramTp.baseType(sym).typeArgs
+ private lazy val typeParamNames: List[String] = sym.typeParams.map(_.decodedName)
+ private def typeArgsAtSym(paramTp: Type) = paramTp.baseType(sym).typeArgs
- def format(paramName: Name, paramTp: Type): String = format(typeArgsAtSym(paramTp) map (_.toString))
+ def format(paramName: Name, paramTp: Type): String = format(typeArgsAtSym(paramTp) map (_.toString))
- def format(typeArgs: List[String]): String =
- interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc?
+ def format(typeArgs: List[String]): String =
+ interpolate(msg, Map((typeParamNames zip typeArgs): _*)) // TODO: give access to the name and type of the implicit argument, etc?
- def validate: Option[String] = {
- val refs = Intersobralator.findAllMatchIn(msg).map(_ group 1).toSet
- val decls = typeParamNames.toSet
+ def validate: Option[String] = {
+ val refs = Intersobralator.findAllMatchIn(msg).map(_ group 1).toSet
+ val decls = typeParamNames.toSet
- (refs &~ decls) match {
- case s if s.isEmpty => None
- case unboundNames =>
- val singular = unboundNames.size == 1
- val ess = if (singular) "" else "s"
- val bee = if (singular) "is" else "are"
- Some(s"The type parameter$ess ${unboundNames mkString ", "} referenced in the message of the @implicitNotFound annotation $bee not defined by $sym.")
- }
+ (refs &~ decls) match {
+ case s if s.isEmpty => None
+ case unboundNames =>
+ val singular = unboundNames.size == 1
+ val ess = if (singular) "" else "s"
+ val bee = if (singular) "is" else "are"
+ Some(s"The type parameter$ess ${unboundNames mkString ", "} referenced in the message of the @$annotationName annotation $bee not defined by $sym.")
}
}
}
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 90ac1f466d..7252cae0b5 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1188,20 +1188,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
// set NoType so it will be ignored.
val cdef = ClassDef(module.moduleClass, impl) setType NoType
- // Create the module var unless the immediate owner is a class and
- // the module var already exists there. See SI-5012, SI-6712.
- def findOrCreateModuleVar() = {
- val vsym = (
- if (site.isTerm) NoSymbol
- else site.info decl nme.moduleVarName(moduleName)
- )
- vsym orElse (site newModuleVarSymbol module)
- }
def newInnerObject() = {
- // Create the module var unless it is already in the module owner's scope.
- // The lookup is on module.enclClass and not module.owner lest there be a
- // nullary method between us and the class; see SI-5012.
- val moduleVar = findOrCreateModuleVar()
+ val moduleVar = site newModuleVarSymbol module
val rhs = gen.newModule(module, moduleVar.tpe)
val body = if (site.isTrait) rhs else gen.mkAssignAndReturn(moduleVar, rhs)
val accessor = DefDef(module, body.changeOwner(moduleVar -> module))
@@ -1217,6 +1205,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
}
val newTrees = cdef :: (
if (module.isStatic)
+ // trait T { def f: Object }; object O extends T { object f }. Need to generate method f in O.
if (module.isOverridingSymbol) matchingInnerObject() else Nil
else
newInnerObject()
@@ -1468,10 +1457,13 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
case m: MemberDef =>
val sym = m.symbol
applyChecks(sym.annotations)
- // validate implicitNotFoundMessage
- analyzer.ImplicitNotFoundMsg.check(sym) foreach { warn =>
- reporter.warning(tree.pos, f"Invalid implicitNotFound message for ${sym}%s${sym.locationString}%s:%n$warn")
- }
+
+ def messageWarning(name: String)(warn: String) =
+ reporter.warning(tree.pos, f"Invalid $name message for ${sym}%s${sym.locationString}%s:%n$warn")
+
+ // validate implicitNotFoundMessage and implicitAmbiguousMessage
+ analyzer.ImplicitNotFoundMsg.check(sym) foreach messageWarning("implicitNotFound")
+ analyzer.ImplicitAmbiguousMsg.check(sym) foreach messageWarning("implicitAmbiguous")
case tpt@TypeTree() =>
if(tpt.original != null) {
diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
index d65d2092ad..4ccc183334 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala
@@ -304,6 +304,7 @@ trait SyntheticMethods extends ast.TreeDSL {
clazz.isModuleClass
&& clazz.isSerializable
&& !hasConcreteImpl(nme.readResolve)
+ && clazz.isStatic
)
def synthesize(): List[Tree] = {
@@ -335,16 +336,18 @@ trait SyntheticMethods extends ast.TreeDSL {
}
for ((m, impl) <- methods ; if shouldGenerate(m)) yield impl()
}
- def extras = (
+ def extras = {
if (needsReadResolve) {
// Aha, I finally decoded the original comment.
// This method should be generated as private, but apparently if it is, then
// it is name mangled afterward. (Wonder why that is.) So it's only protected.
// For sure special methods like "readResolve" should not be mangled.
- List(createMethod(nme.readResolve, Nil, ObjectTpe)(m => { m setFlag PRIVATE ; REF(clazz.sourceModule) }))
+ List(createMethod(nme.readResolve, Nil, ObjectTpe)(m => {
+ m setFlag PRIVATE; REF(clazz.sourceModule)
+ }))
}
else Nil
- )
+ }
try impls ++ extras
catch { case _: TypeError if reporter.hasErrors => Nil }
diff --git a/src/library/scala/annotation/implicitAmbiguous.scala b/src/library/scala/annotation/implicitAmbiguous.scala
new file mode 100644
index 0000000000..46eab9ae8f
--- /dev/null
+++ b/src/library/scala/annotation/implicitAmbiguous.scala
@@ -0,0 +1,34 @@
+package scala.annotation
+
+import scala.annotation.meta._
+
+/**
+ * To customize the error message that's emitted when an implicit of type
+ * C[T1,..., TN] is found more than once, annotate the class C
+ * with @implicitAmbiguous. Assuming C has type parameters X1,..., XN, the
+ * error message will be the result of replacing all occurrences of ${Xi} in
+ * the string msg with the string representation of the corresponding type
+ * argument Ti. *
+ *
+ * If more than one @implicitAmbiguous annotation is collected, the compiler is
+ * free to pick any of them to display.
+ *
+ * Nice errors can direct users to fix imports or even tell them why code
+ * intentionally doesn't compile.
+ *
+ * {{{
+ * trait =!=[C, D]
+ *
+ * implicit def neq[E, F] : E =!= F = null
+ *
+ * @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}")
+ * implicit def neqAmbig1[G, H, J] : J =!= J = null
+ * implicit def neqAmbig2[I] : I =!= I = null
+ *
+ * implicitly[Int =!= Int]
+ * }}}
+ *
+ * @author Brian McKenna
+ * @since 2.12.0
+ */
+final class implicitAmbiguous(msg: String) extends scala.annotation.StaticAnnotation {}
diff --git a/src/library/scala/runtime/Tuple2Zipped.scala b/src/library/scala/runtime/Tuple2Zipped.scala
index 512c4fbc27..1c432b0403 100644
--- a/src/library/scala/runtime/Tuple2Zipped.scala
+++ b/src/library/scala/runtime/Tuple2Zipped.scala
@@ -110,6 +110,8 @@ final class Tuple2Zipped[El1, Repr1, El2, Repr2](val colls: (TraversableLike[El1
return
}
}
+
+ override def toString = "(%s, %s).zipped".format(colls._1.toString, colls._2.toString)
}
object Tuple2Zipped {
diff --git a/src/library/scala/runtime/Tuple3Zipped.scala b/src/library/scala/runtime/Tuple3Zipped.scala
index ffd44acf81..3bab86921b 100644
--- a/src/library/scala/runtime/Tuple3Zipped.scala
+++ b/src/library/scala/runtime/Tuple3Zipped.scala
@@ -118,6 +118,8 @@ final class Tuple3Zipped[El1, Repr1, El2, Repr2, El3, Repr3](val colls: (Travers
return
}
}
+
+ override def toString: String = "(%s, %s, %s).zipped".format(colls._1.toString, colls._2.toString, colls._3.toString)
}
object Tuple3Zipped {
diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala
index 06fc453ed5..a3d9368915 100644
--- a/src/reflect/scala/reflect/internal/Definitions.scala
+++ b/src/reflect/scala/reflect/internal/Definitions.scala
@@ -1105,6 +1105,7 @@ trait Definitions extends api.StandardDefinitions {
lazy val BridgeClass = requiredClass[scala.annotation.bridge]
lazy val ElidableMethodClass = requiredClass[scala.annotation.elidable]
lazy val ImplicitNotFoundClass = requiredClass[scala.annotation.implicitNotFound]
+ lazy val ImplicitAmbiguousClass = getClassIfDefined("scala.annotation.implicitAmbiguous")
lazy val MigrationAnnotationClass = requiredClass[scala.annotation.migration]
lazy val ScalaStrictFPAttr = requiredClass[scala.annotation.strictfp]
lazy val SwitchClass = requiredClass[scala.annotation.switch]
diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala
index 8a52f0b9d8..1113da2eff 100644
--- a/src/reflect/scala/reflect/internal/Symbols.scala
+++ b/src/reflect/scala/reflect/internal/Symbols.scala
@@ -884,10 +884,11 @@ 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(0) }
- def migrationVersion = getAnnotation(MigrationAnnotationClass) flatMap { _.stringArg(1) }
- def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) }
- def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) }
+ 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) }
+ def implicitAmbiguousMsg = getAnnotation(ImplicitAmbiguousClass) flatMap { _.stringArg(0) }
def isCompileTimeOnly = hasAnnotation(CompileTimeOnlyAttr)
def compileTimeOnlyMessage = getAnnotation(CompileTimeOnlyAttr) flatMap (_ stringArg 0)
diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
index ea213cadd9..a2232d1963 100644
--- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
+++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala
@@ -370,6 +370,7 @@ trait JavaUniverseForce { self: runtime.JavaUniverse =>
definitions.BridgeClass
definitions.ElidableMethodClass
definitions.ImplicitNotFoundClass
+ definitions.ImplicitAmbiguousClass
definitions.MigrationAnnotationClass
definitions.ScalaStrictFPAttr
definitions.SwitchClass
diff --git a/test/files/neg/implicit-ambiguous-2.check b/test/files/neg/implicit-ambiguous-2.check
new file mode 100644
index 0000000000..4a10b0dd65
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous-2.check
@@ -0,0 +1,4 @@
+implicit-ambiguous-2.scala:10: error: Could not prove Int =!= Int
+ implicitly[Int =!= Int]
+ ^
+one error found
diff --git a/test/files/neg/implicit-ambiguous-2.scala b/test/files/neg/implicit-ambiguous-2.scala
new file mode 100644
index 0000000000..563c8c583f
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous-2.scala
@@ -0,0 +1,11 @@
+object Test {
+ trait =!=[C, D]
+
+ implicit def neq[E, F] : E =!= F = null
+
+ implicit def neqAmbig1[G, H, J] : J =!= J = null
+ @annotation.implicitAmbiguous("Could not prove ${I} =!= ${I}")
+ implicit def neqAmbig2[I] : I =!= I = null
+
+ implicitly[Int =!= Int]
+}
diff --git a/test/files/neg/implicit-ambiguous-invalid.check b/test/files/neg/implicit-ambiguous-invalid.check
new file mode 100644
index 0000000000..68b607c4c2
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous-invalid.check
@@ -0,0 +1,7 @@
+implicit-ambiguous-invalid.scala:5: warning: Invalid implicitAmbiguous message for method neqAmbig1 in object Test:
+The type parameter B referenced in the message of the @implicitAmbiguous annotation is not defined by method neqAmbig1.
+ implicit def neqAmbig1[A] : A =!= A = null
+ ^
+error: No warnings can be incurred under -Xfatal-warnings.
+one warning found
+one error found
diff --git a/test/files/neg/implicit-ambiguous-invalid.flags b/test/files/neg/implicit-ambiguous-invalid.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous-invalid.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/implicit-ambiguous-invalid.scala b/test/files/neg/implicit-ambiguous-invalid.scala
new file mode 100644
index 0000000000..f8f9da655f
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous-invalid.scala
@@ -0,0 +1,6 @@
+object Test {
+ trait =!=[C, D]
+
+ @annotation.implicitAmbiguous("Could not prove ${A} =!= ${B}")
+ implicit def neqAmbig1[A] : A =!= A = null
+}
diff --git a/test/files/neg/implicit-ambiguous.check b/test/files/neg/implicit-ambiguous.check
new file mode 100644
index 0000000000..0b3cebcb6f
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous.check
@@ -0,0 +1,4 @@
+implicit-ambiguous.scala:10: error: Could not prove Int =!= Int
+ implicitly[Int =!= Int]
+ ^
+one error found
diff --git a/test/files/neg/implicit-ambiguous.scala b/test/files/neg/implicit-ambiguous.scala
new file mode 100644
index 0000000000..79b1297915
--- /dev/null
+++ b/test/files/neg/implicit-ambiguous.scala
@@ -0,0 +1,11 @@
+object Test {
+ trait =!=[C, D]
+
+ implicit def neq[E, F] : E =!= F = null
+
+ @annotation.implicitAmbiguous("Could not prove ${J} =!= ${J}")
+ implicit def neqAmbig1[G, H, J] : J =!= J = null
+ implicit def neqAmbig2[I] : I =!= I = null
+
+ implicitly[Int =!= Int]
+}
diff --git a/test/files/neg/t6666d.check b/test/files/neg/t6666d.check
deleted file mode 100644
index b4785f0129..0000000000
--- a/test/files/neg/t6666d.check
+++ /dev/null
@@ -1,4 +0,0 @@
-t6666d.scala:7: error: Implementation restriction: access of object TreeOrd$1 from object TreeOrd$2, would require illegal premature access to the unconstructed `this` of class Test
- implicit object TreeOrd extends Ordering[K](){
- ^
-one error found
diff --git a/test/files/neg/t6666d.scala b/test/files/pos/t6666d.scala
index 49a688f91b..49a688f91b 100644
--- a/test/files/neg/t6666d.scala
+++ b/test/files/pos/t6666d.scala
diff --git a/test/files/run/idempotency-case-classes.check b/test/files/run/idempotency-case-classes.check
index 5a8d0ad9d3..ea698cec59 100644
--- a/test/files/run/idempotency-case-classes.check
+++ b/test/files/run/idempotency-case-classes.check
@@ -47,8 +47,7 @@ C(2,3)
case <synthetic> def unapply(x$0: C): Option[(Int, Int)] = if (x$0.==(null))
scala.this.None
else
- Some.apply[(Int, Int)](scala.Tuple2.apply[Int, Int](x$0.x, x$0.y));
- <synthetic> private def readResolve(): Object = C
+ Some.apply[(Int, Int)](scala.Tuple2.apply[Int, Int](x$0.x, x$0.y))
};
Predef.println(C.apply(2, 3))
}
diff --git a/test/files/run/repl-serialization.check b/test/files/run/repl-serialization.check
index eb62729f5c..bbbf0dcdf1 100644
--- a/test/files/run/repl-serialization.check
+++ b/test/files/run/repl-serialization.check
@@ -20,6 +20,5 @@ u: U = U
evaluating O
constructing A
== reconstituting into a fresh classloader
- evaluating O
== evaluating reconstituted lambda
constructing A
diff --git a/test/files/run/t9375.check b/test/files/run/t9375.check
new file mode 100644
index 0000000000..8f43fab025
--- /dev/null
+++ b/test/files/run/t9375.check
@@ -0,0 +1,60 @@
+ konstruktor: class A
+ konstruktor: class A$O$12$
+ konstruktor: class A$$anon$1
+ konstruktor: class A$A
+ konstruktor: class A$C
+ konstruktor: class C
+ konstruktor: class T$O$15$
+ konstruktor: class T$$anon$2
+ konstruktor: class T$A
+ konstruktor: class T$C
+ konstruktor: class A$N$
+ konstruktor: class T$N$
+serializing outer objects should not initialize any nested objects
+now initializing nested objects
+ konstruktor: class A$O$
+ konstruktor: class A$Op$
+ konstruktor: class A$N$O$
+ konstruktor: class A$N$Op$
+ konstruktor: class A$A$O$
+ konstruktor: class A$A$Op$
+ konstruktor: class A$T$O$
+ konstruktor: class A$T$Op$
+ konstruktor: class A$O$11$
+ konstruktor: class A$O$13$
+ konstruktor: class A$$anon$1$O$
+ konstruktor: class A$$anon$1$Op$
+ konstruktor: class T$O$
+ konstruktor: class T$Op$
+ konstruktor: class T$N$O$
+ konstruktor: class T$N$Op$
+ konstruktor: class T$A$O$
+ konstruktor: class T$A$Op$
+ konstruktor: class T$T$O$
+ konstruktor: class T$T$Op$
+ konstruktor: class T$O$14$
+ konstruktor: class T$O$16$
+ konstruktor: class T$$anon$2$O$
+ konstruktor: class T$$anon$2$Op$
+no object konstruktors called when serializing / deserializing objects (starting at the outer or the object itself)
+deserializing outer objects with non-initialized inners again
+accessing modules triggers initialization
+ konstruktor: class A$O$
+ konstruktor: class A$Op$
+ konstruktor: class A$N$O$
+ konstruktor: class A$N$Op$
+deserializing creates a new object graph, including new scala 'object' instances, no matter where serialization starts
+init static module M and field v
+ konstruktor: class M$
+ konstruktor: class M$O$18$
+serDeser does not initialize nested static modules
+init M.O
+ konstruktor: class M$O$
+serDeser nested static module
+objects declared in field decls are not static modules, so they deserialize to new instances
+init lazy val M.w
+objects declared in lazy val are not static modules either
+ konstruktor: class M$O$19$
+object declared in a function: new instance created on each invocation
+ konstruktor: class M$O$20$
+ konstruktor: class M$O$20$
diff --git a/test/files/run/t9375.scala b/test/files/run/t9375.scala
new file mode 100644
index 0000000000..3995b38666
--- /dev/null
+++ b/test/files/run/t9375.scala
@@ -0,0 +1,276 @@
+import java.io._
+
+object SerDes {
+ def serialize(obj: AnyRef): Array[Byte] = {
+ val buffer = new ByteArrayOutputStream
+ val out = new ObjectOutputStream(buffer)
+ out.writeObject(obj)
+ buffer.toByteArray
+ }
+
+ def deserialize(a: Array[Byte]): AnyRef = {
+ val in = new ObjectInputStream(new ByteArrayInputStream(a))
+ in.readObject
+ }
+
+ def serializeDeserialize[T <: AnyRef](obj: T) = deserialize(serialize(obj)).asInstanceOf[T]
+}
+
+import SerDes._
+
+// tests to make sure that de-serializing an object does not run its constructor
+
+trait S extends Serializable {
+ println(" konstruktor: " + this.getClass)
+}
+
+trait SE extends S {
+ def outer: Object
+}
+
+class A extends S {
+ object O extends SE { def outer = A.this }
+ private[this] object Op extends SE { def outer = A.this }
+ def P: SE = Op
+
+ object N extends S {
+ object O extends SE { def outer = N }
+ private[this] object Op extends SE { def outer = N }
+ def P: SE = Op
+ }
+
+ class A extends S {
+ object O extends SE { def outer = A.this }
+ private[this] object Op extends SE { def outer = A.this }
+ def P: SE = Op
+ }
+
+ trait T extends S {
+ object O extends SE { def outer = T.this }
+ private[this] object Op extends SE { def outer = T.this }
+ def P: SE = Op
+ }
+ class C extends T
+
+ def u: SE = {
+ object O extends SE { def outer = A.this }
+ O
+ }
+
+ val v: SE = {
+ object O extends SE { def outer = A.this }
+ O
+ }
+
+ val f: () => SE = () => {
+ object O extends SE { def outer = A.this }
+ O
+ }
+
+ trait GetObj { def O: SE; def P: SE }
+ val a: GetObj = new GetObj with S {
+ def anonThis = this
+ object O extends SE { def outer = anonThis }
+ private[this] object Op extends SE { def outer = anonThis }
+ def P: SE = Op
+ }
+}
+
+trait T extends S {
+ object O extends SE { def outer = T.this }
+ private[this] object Op extends SE { def outer = T.this }
+ def P: SE = Op
+
+ object N extends S {
+ object O extends SE { def outer = N }
+ private[this] object Op extends SE { def outer = N }
+ def P: SE = Op
+ }
+
+ class A extends S {
+ object O extends SE { def outer = A.this }
+ private[this] object Op extends SE { def outer = A.this }
+ def P: SE = Op
+ }
+
+ trait T extends S {
+ object O extends SE { def outer = T.this }
+ private[this] object Op extends SE { def outer = T.this }
+ def P: SE = Op
+ }
+ class C extends T
+
+ def u: SE = {
+ object O extends SE { def outer = T.this }
+ O
+ }
+
+ val v: SE = {
+ object O extends SE { def outer = T.this }
+ O
+ }
+
+ val f: () => SE = () => {
+ object O extends SE { def outer = T.this }
+ O
+ }
+
+ trait GetObj { def O: SE; def P: SE }
+ val a: GetObj = new GetObj with S {
+ def anonThis = this
+ object O extends SE { def outer = anonThis }
+ private[this] object Op extends SE { def outer = anonThis }
+ def P: SE = Op
+ }
+}
+
+class C extends T
+
+object DeserializeModuleNoConstructor {
+ def t(): Unit = {
+ val a = new A
+ val aa = new a.A
+ val ac = new a.C
+
+ val c = new C
+ val ca = new c.A
+ val cc = new c.C
+
+ val outers: List[Object] = List(
+ a, a.N, aa, ac, a.a,
+ c, c.N, ca, cc, c.a
+ )
+
+ println("serializing outer objects should not initialize any nested objects")
+
+ val serANotInit = serialize(a)
+ outers foreach serializeDeserialize
+
+ println("now initializing nested objects")
+
+ val os: List[(SE, Object)] = List(
+ a.O -> a,
+ a.P -> a,
+ a.N.O -> a.N,
+ a.N.P -> a.N,
+ aa.O -> aa,
+ aa.P -> aa,
+ ac.O -> ac,
+ ac.P -> ac,
+ a.u -> a,
+ a.v -> a,
+ a.f() -> a,
+ a.a.O -> a.a,
+ a.a.P -> a.a,
+
+ c.O -> c,
+ c.P -> c,
+ c.N.O -> c.N,
+ c.N.P -> c.N,
+ ca.O -> ca,
+ ca.P -> ca,
+ cc.O -> cc,
+ cc.P -> cc,
+ c.u -> c,
+ c.v -> c,
+ c.f() -> c,
+ c.a.O -> c.a,
+ c.a.P -> c.a
+ )
+
+ println("no object konstruktors called when serializing / deserializing objects (starting at the outer or the object itself)")
+
+ for ((obj, outer) <- os) {
+ assert(obj.outer eq outer, s"${obj.outer} of $obj -- $outer")
+ serializeDeserialize(obj)
+ serializeDeserialize(outer)
+ }
+
+ println("deserializing outer objects with non-initialized inners again")
+ val aNotInit = deserialize(serANotInit).asInstanceOf[A]
+
+ println("accessing modules triggers initialization")
+ aNotInit.O
+ aNotInit.P
+ aNotInit.N.O
+ aNotInit.N.P
+
+ println("deserializing creates a new object graph, including new scala 'object' instances, no matter where serialization starts")
+ val deserializedAs: List[A] = List(
+ serializeDeserialize(a),
+ serializeDeserialize(a.O).outer.asInstanceOf[A],
+ serializeDeserialize(a.P).outer.asInstanceOf[A],
+ serializeDeserialize(a.v).outer.asInstanceOf[A]
+ )
+ for (aSD <- deserializedAs) {
+ assert(aSD ne a)
+ assert(aSD.O ne a.O)
+ assert(aSD.P ne a.P)
+ assert(aSD.N ne a.N)
+ assert(aSD.N.O ne a.N.O)
+ assert(aSD.N.P ne a.N.P)
+ assert(aSD.v ne a.v)
+ assert(aSD.a.O ne a.a.O)
+ assert(aSD.a.P ne a.a.P)
+ }
+ }
+}
+
+// tests for serializing / deserializing static modules
+
+object M extends S {
+ object O extends S
+
+ def u: S = {
+ object O extends S
+ O
+ }
+
+ val v: S = {
+ object O extends S
+ O
+ }
+
+ lazy val w: S = {
+ object O extends S
+ O
+ }
+
+ val f: () => S = () => {
+ object O extends S
+ O
+ }
+}
+
+object SerializingStaticModules {
+ def t(): Unit = {
+ println("init static module M and field v")
+ M
+
+ println("serDeser does not initialize nested static modules")
+ assert(serializeDeserialize(M) eq M)
+
+ println("init M.O")
+ M.O
+
+ println("serDeser nested static module")
+ assert(serializeDeserialize(M.O) eq M.O)
+
+ println("objects declared in field decls are not static modules, so they deserialize to new instances")
+ assert(serializeDeserialize(M.v) ne M.v)
+
+ println("init lazy val M.w")
+
+ println("objects declared in lazy val are not static modules either")
+ assert(serializeDeserialize(M.w) ne M.w)
+
+ println("object declared in a function: new instance created on each invocation")
+ assert(M.f() ne M.f())
+ }
+}
+
+
+object Test extends App {
+ DeserializeModuleNoConstructor.t()
+ SerializingStaticModules.t()
+}
diff --git a/test/junit/scala/collection/immutable/StreamTest.scala b/test/junit/scala/collection/immutable/StreamTest.scala
index fad4e502eb..1b257aabc4 100644
--- a/test/junit/scala/collection/immutable/StreamTest.scala
+++ b/test/junit/scala/collection/immutable/StreamTest.scala
@@ -107,4 +107,20 @@ class StreamTest {
def withFilter_map_properly_lazy_in_tail: Unit = {
assertStreamOpLazyInTail(_.withFilter(_ % 2 == 0).map(identity), List(1, 2))
}
+
+ @Test
+ def test_si9379() {
+ class Boom {
+ private var i = -1
+ def inc = {
+ i += 1
+ if (i > 1000) throw new NoSuchElementException("Boom! Too many elements!")
+ i
+ }
+ }
+ val b = new Boom
+ val s = Stream.continually(b.inc)
+ // zipped.toString must allow s to short-circuit evaluation
+ assertTrue((s, s).zipped.toString contains s.toString)
+ }
}