summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan@lightbend.com>2017-04-07 16:38:20 -0700
committerAdriaan Moors <adriaan@lightbend.com>2017-04-07 16:38:20 -0700
commit1f33863a171567b2fa098a4f6c328400eb4a51e8 (patch)
treea1b4632349bd41f22d0972012d5be66fdc37bd06
parent414b61cf7471456dbe04e10905cd00c9dfc8beed (diff)
parent99f41a15d16be6707b6c33b5a16093e016db81eb (diff)
downloadscala-1f33863a171567b2fa098a4f6c328400eb4a51e8.tar.gz
scala-1f33863a171567b2fa098a4f6c328400eb4a51e8.tar.bz2
scala-1f33863a171567b2fa098a4f6c328400eb4a51e8.zip
Merge 2.11.x into 2.12.x
Include 99f41a1 Merge pull request #5736
-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
-rw-r--r--test/files/pos/t10206.scala15
4 files changed, 43 insertions, 21 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index a7eab21942..33e176a309 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -154,11 +154,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()
@@ -1412,27 +1407,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 _ =>
}
}
@@ -1442,6 +1442,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
}
diff --git a/test/files/pos/t10206.scala b/test/files/pos/t10206.scala
new file mode 100644
index 0000000000..3ddd1ea2fd
--- /dev/null
+++ b/test/files/pos/t10206.scala
@@ -0,0 +1,15 @@
+class Foo(val bar: String)
+
+object Foo {
+ implicit class Enrich(foo: Foo) {
+ def clone(x: Int, y: Int): Int = x + y
+ }
+}
+
+object Main extends App {
+ val foo = new Foo("hello")
+ println(foo.clone(1, 2)) // <- does not compile
+ // the implicit view was being disqualified because a new check in the compiler
+ // that implicit views must not target Any or AnyRef considered an implicit search
+ // for `foo.type => ?{def clone: ?}` to targeted AnyRef.
+}