summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala28
-rw-r--r--src/library/scala/Option.scala4
-rw-r--r--src/library/scala/Predef.scala31
-rw-r--r--test/files/neg/no-implicit-to-anyref.check8
-rw-r--r--test/files/neg/t4158.check16
-rw-r--r--test/files/neg/t4727.check8
-rw-r--r--test/files/neg/t6889.check7
-rw-r--r--test/files/neg/t6889.scala18
8 files changed, 54 insertions, 66 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index b53efafdd4..8e79b56814 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -144,6 +144,15 @@ trait Implicits {
private val infoMapCache = new LinkedHashMap[Symbol, InfoMap]
private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]()
+ private def isInvalidConversionTarget(tpe: Type): Boolean = tpe match {
+ case Function1(_, out) => AnyRefClass.tpe <:< out
+ case _ => false
+ }
+ private def isInvalidConversionSource(tpe: Type): Boolean = tpe match {
+ case Function1(in, _) => in <:< NullClass.tpe
+ case _ => false
+ }
+
def resetImplicits() {
implicitsCache.clear()
infoMapCache.clear()
@@ -1357,10 +1366,10 @@ trait Implicits {
val wasAmbigious = result.isAmbiguousFailure // SI-6667, never search companions after an ambiguous error in in-scope implicits
result = materializeImplicit(pt)
-
// `materializeImplicit` does some preprocessing for `pt`
// is it only meant for manifests/tags or we need to do the same for `implicitsOfExpectedType`?
- if (result.isFailure && !wasAmbigious) result = searchImplicit(implicitsOfExpectedType, isLocal = false)
+ if (result.isFailure && !wasAmbigious)
+ result = searchImplicit(implicitsOfExpectedType, isLocal = false)
if (result.isFailure) {
context.updateBuffer(previousErrs)
@@ -1370,9 +1379,18 @@ trait Implicits {
if (Statistics.canEnable) Statistics.incCounter(oftypeImplicitHits)
}
}
-
- if (result.isFailure && settings.debug)
- log("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
+ if (result.isSuccess && isView) {
+ if (isInvalidConversionTarget(pt)) {
+ context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, "the result type of an implicit conversion must be more specific than AnyRef"))
+ result = SearchFailure
+ }
+ else if (isInvalidConversionSource(pt)) {
+ context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, "an expression of type Null is ineligible for implicit conversion"))
+ result = SearchFailure
+ }
+ }
+ if (result.isFailure)
+ debuglog("no implicits found for "+pt+" "+pt.typeSymbol.info.baseClasses+" "+implicitsOfExpectedType)
result
}
diff --git a/src/library/scala/Option.scala b/src/library/scala/Option.scala
index 4b071166c7..905e925f57 100644
--- a/src/library/scala/Option.scala
+++ b/src/library/scala/Option.scala
@@ -128,7 +128,7 @@ sealed abstract class Option[+A] extends Product with Serializable {
* val textField = new JComponent(initalText.orNull,20)
* }}}
*/
- @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse null
+ @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse ev(null)
/** Returns a $some containing the result of applying $f to this $option's
* value if this $option is nonempty.
@@ -210,7 +210,7 @@ sealed abstract class Option[+A] extends Product with Serializable {
}
/** Tests whether the option contains a given value as an element.
- *
+ *
* @param elem the element to test.
* @return `true` if the option has an element that is equal (as
* determined by `==`) to `elem`, `false` otherwise.
diff --git a/src/library/scala/Predef.scala b/src/library/scala/Predef.scala
index 569157de20..5ba38600b6 100644
--- a/src/library/scala/Predef.scala
+++ b/src/library/scala/Predef.scala
@@ -346,19 +346,6 @@ object Predef extends LowPriorityImplicits with DeprecatedPredef {
implicit def double2Double(x: Double) = java.lang.Double.valueOf(x)
implicit def boolean2Boolean(x: Boolean) = java.lang.Boolean.valueOf(x)
- // These next eight implicits exist solely to exclude AnyRef methods from the
- // eight implicits above so that primitives are not coerced to AnyRefs. They
- // only create such conflict for AnyRef methods, so the methods on the java.lang
- // boxed types are unambiguously reachable.
- implicit def byte2ByteConflict(x: Byte) = new AnyRef
- implicit def short2ShortConflict(x: Short) = new AnyRef
- implicit def char2CharacterConflict(x: Char) = new AnyRef
- implicit def int2IntegerConflict(x: Int) = new AnyRef
- implicit def long2LongConflict(x: Long) = new AnyRef
- implicit def float2FloatConflict(x: Float) = new AnyRef
- implicit def double2DoubleConflict(x: Double) = new AnyRef
- implicit def boolean2BooleanConflict(x: Boolean) = new AnyRef
-
implicit def Byte2byte(x: java.lang.Byte): Byte = x.byteValue
implicit def Short2short(x: java.lang.Short): Short = x.shortValue
implicit def Character2char(x: java.lang.Character): Char = x.charValue
@@ -481,24 +468,6 @@ private[scala] abstract class LowPriorityImplicits {
@inline implicit def doubleWrapper(x: Double) = new runtime.RichDouble(x)
@inline implicit def booleanWrapper(x: Boolean) = new runtime.RichBoolean(x)
- // These eight implicits exist solely to exclude Null from the domain of
- // the boxed types, so that e.g. "var x: Int = null" is a compile time
- // error rather than a delayed null pointer exception by way of the
- // conversion from java.lang.Integer. If defined in the same template as
- // Integer2int, they would have higher priority because Null is a subtype
- // of Integer. We balance that out and create conflict by moving the
- // definition into the superclass.
- //
- // Caution: do not adjust tightrope tension without safety goggles in place.
- implicit def Byte2byteNullConflict(x: Null): Byte = sys.error("value error")
- implicit def Short2shortNullConflict(x: Null): Short = sys.error("value error")
- implicit def Character2charNullConflict(x: Null): Char = sys.error("value error")
- implicit def Integer2intNullConflict(x: Null): Int = sys.error("value error")
- implicit def Long2longNullConflict(x: Null): Long = sys.error("value error")
- implicit def Float2floatNullConflict(x: Null): Float = sys.error("value error")
- implicit def Double2doubleNullConflict(x: Null): Double = sys.error("value error")
- implicit def Boolean2booleanNullConflict(x: Null): Boolean = sys.error("value error")
-
implicit def genericWrapArray[T](xs: Array[T]): WrappedArray[T] =
if (xs eq null) null
else WrappedArray.make(xs)
diff --git a/test/files/neg/no-implicit-to-anyref.check b/test/files/neg/no-implicit-to-anyref.check
index d94b57a30a..fe417ad8b0 100644
--- a/test/files/neg/no-implicit-to-anyref.check
+++ b/test/files/neg/no-implicit-to-anyref.check
@@ -1,10 +1,4 @@
-no-implicit-to-anyref.scala:11: error: type mismatch;
- found : Int(1)
- required: AnyRef
-Note: an implicit exists from scala.Int => java.lang.Integer, but
-methods inherited from Object are rendered ambiguous. This is to avoid
-a blanket implicit which would convert any scala.Int to any AnyRef.
-You may wish to use a type ascription: `x: java.lang.Integer`.
+no-implicit-to-anyref.scala:11: error: the result type of an implicit conversion must be more specific than AnyRef
1: AnyRef
^
no-implicit-to-anyref.scala:17: error: type mismatch;
diff --git a/test/files/neg/t4158.check b/test/files/neg/t4158.check
index 3ee2627c5b..af281c52cd 100644
--- a/test/files/neg/t4158.check
+++ b/test/files/neg/t4158.check
@@ -1,19 +1,7 @@
-t4158.scala:3: error: type mismatch;
- found : Null(null)
- required: Int
-Note that implicit conversions are not applicable because they are ambiguous:
- both method Integer2intNullConflict in class LowPriorityImplicits of type (x: Null)Int
- and method Integer2int in object Predef of type (x: Integer)Int
- are possible conversion functions from Null(null) to Int
+t4158.scala:3: error: an expression of type Null is ineligible for implicit conversion
var y = null: Int
^
-t4158.scala:2: error: type mismatch;
- found : Null(null)
- required: Int
-Note that implicit conversions are not applicable because they are ambiguous:
- both method Integer2intNullConflict in class LowPriorityImplicits of type (x: Null)Int
- and method Integer2int in object Predef of type (x: Integer)Int
- are possible conversion functions from Null(null) to Int
+t4158.scala:2: error: an expression of type Null is ineligible for implicit conversion
var x: Int = null
^
two errors found
diff --git a/test/files/neg/t4727.check b/test/files/neg/t4727.check
index 8a4536fec3..a17cdde044 100644
--- a/test/files/neg/t4727.check
+++ b/test/files/neg/t4727.check
@@ -1,10 +1,4 @@
-t4727.scala:5: error: type mismatch;
- found : Null
- required: Int
-Note that implicit conversions are not applicable because they are ambiguous:
- both method Integer2intNullConflict in class LowPriorityImplicits of type (x: Null)Int
- and method Integer2int in object Predef of type (x: Integer)Int
- are possible conversion functions from Null to Int
+t4727.scala:5: error: an expression of type Null is ineligible for implicit conversion
Error occurred in an application involving default arguments.
new C[Int]
^
diff --git a/test/files/neg/t6889.check b/test/files/neg/t6889.check
new file mode 100644
index 0000000000..a77e8a010c
--- /dev/null
+++ b/test/files/neg/t6889.check
@@ -0,0 +1,7 @@
+t6889.scala:16: error: the result type of an implicit conversion must be more specific than AnyRef
+ def f(x: Dingo): AnyRef = x // fail - no conversion to AnyRef
+ ^
+t6889.scala:17: error: an expression of type Null is ineligible for implicit conversion
+ var x: Int = null // fail - no conversion from Null
+ ^
+two errors found
diff --git a/test/files/neg/t6889.scala b/test/files/neg/t6889.scala
new file mode 100644
index 0000000000..ef1963669c
--- /dev/null
+++ b/test/files/neg/t6889.scala
@@ -0,0 +1,18 @@
+package bippy {
+ trait Bippy[A] extends Any
+}
+package foo {
+ package object unrelated {
+ implicit def bippyDingo[A](x: bippy.Bippy[A]): AnyRef = Nil
+ }
+ package unrelated {
+ trait Unrelated
+ }
+}
+
+object Test {
+ trait Dingo extends Any with bippy.Bippy[foo.unrelated.Unrelated]
+
+ def f(x: Dingo): AnyRef = x // fail - no conversion to AnyRef
+ var x: Int = null // fail - no conversion from Null
+}