summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2017-02-23 15:44:37 -0800
committerAdriaan Moors <adriaan@lightbend.com>2017-02-23 16:22:25 -0800
commit78d917393ea03ef94f892549f87cbc2cabba8ac6 (patch)
tree072959664621782b246a75ae3383fd2719665da4
parent011cc7ec86105640a6d606998f769986630fb62a (diff)
downloadscala-78d917393ea03ef94f892549f87cbc2cabba8ac6.tar.gz
scala-78d917393ea03ef94f892549f87cbc2cabba8ac6.tar.bz2
scala-78d917393ea03ef94f892549f87cbc2cabba8ac6.zip
SI-10206 tighten fix for SI-6889
There are more supertypes of `AnyRef` than you might think: `?{def clone: ?}` is one example...
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala41
-rw-r--r--test/files/neg/t6889.check7
-rw-r--r--test/files/neg/t6889.scala1
3 files changed, 28 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 509ce59104..2333c29b30 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -134,11 +134,6 @@ trait Implicits {
private val improvesCache = perRunCaches.newMap[(ImplicitInfo, ImplicitInfo), Boolean]()
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }
- private def isInvalidConversionSource(tpe: Type): Boolean = tpe match {
- case Function1(in, _) => in <:< NullClass.tpe
- case _ => false
- }
-
def resetImplicits() {
implicitsCache.clear()
infoMapCache.clear()
@@ -1388,27 +1383,32 @@ trait Implicits {
}
}
if (result.isSuccess && isView) {
- def maybeInvalidConversionError(msg: String) {
+ def maybeInvalidConversionError(msg: String): Boolean = {
// We have to check context.ambiguousErrors even though we are calling "issueAmbiguousError"
// which ostensibly does exactly that before issuing the error. Why? I have no idea. Test is pos/t7690.
// AM: I would guess it's because ambiguous errors will be buffered in silent mode if they are not reported
if (context.ambiguousErrors)
context.issueAmbiguousError(AmbiguousImplicitTypeError(tree, msg))
+ true
}
pt match {
- case Function1(_, out) =>
- // must inline to avoid capturing result
- def prohibit(sym: Symbol) = (sym.tpe <:< out) && {
- maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than ${sym.name}")
- true
- }
- if (prohibit(AnyRefClass) || (settings.isScala211 && prohibit(AnyValClass)))
- result = SearchFailure
- case _ => false
- }
- if (settings.isScala211 && isInvalidConversionSource(pt)) {
- maybeInvalidConversionError("an expression of type Null is ineligible for implicit conversion")
- result = SearchFailure
+ // SI-10206 don't use subtyping to rule out AnyRef/AnyVal:
+ // - there are several valid structural types that are supertypes of AnyRef (e.g., created by HasMember);
+ // typeSymbol will do the trick (AnyRef is a type alias for Object), while ruling out these structural types
+ // - also don't want to accidentally constrain type vars through using <:<
+ case Function1(in, out) =>
+ val outSym = out.typeSymbol
+
+ val fail =
+ if (out.annotations.isEmpty && (outSym == ObjectClass || (isScala211 && outSym == AnyValClass)))
+ maybeInvalidConversionError(s"the result type of an implicit conversion must be more specific than $out")
+ else if (isScala211 && in.annotations.isEmpty && in.typeSymbol == NullClass)
+ maybeInvalidConversionError("an expression of type Null is ineligible for implicit conversion")
+ else false
+
+ if (fail) result = SearchFailure
+
+ case _ =>
}
}
@@ -1418,6 +1418,9 @@ trait Implicits {
result
}
+ // this setting is expensive to check, actually....
+ private[this] val isScala211 = settings.isScala211
+
def allImplicits: List[SearchResult] = {
def search(iss: Infoss, isLocalToCallsite: Boolean) = applicableInfos(iss, isLocalToCallsite).values
(
diff --git a/test/files/neg/t6889.check b/test/files/neg/t6889.check
index a77e8a010c..c14c3b09c0 100644
--- a/test/files/neg/t6889.check
+++ b/test/files/neg/t6889.check
@@ -1,7 +1,10 @@
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
+t6889.scala:17: error: the result type of an implicit conversion must be more specific than Object
+ def f2(x: Dingo): Object = x // fail - no conversion to Object
+ ^
+t6889.scala:18: error: an expression of type Null is ineligible for implicit conversion
var x: Int = null // fail - no conversion from Null
^
-two errors found
+three errors found
diff --git a/test/files/neg/t6889.scala b/test/files/neg/t6889.scala
index ef1963669c..3fc235bf7e 100644
--- a/test/files/neg/t6889.scala
+++ b/test/files/neg/t6889.scala
@@ -14,5 +14,6 @@ object Test {
trait Dingo extends Any with bippy.Bippy[foo.unrelated.Unrelated]
def f(x: Dingo): AnyRef = x // fail - no conversion to AnyRef
+ def f2(x: Dingo): Object = x // fail - no conversion to Object
var x: Int = null // fail - no conversion from Null
}