summaryrefslogtreecommitdiff
path: root/src/compiler
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-06-04 11:50:05 -0700
committerPaul Phillips <paulp@improving.org>2013-06-04 12:25:43 -0700
commit2f0e5ec1e96a6e4806841069736eda844d3a8dd6 (patch)
tree1a72792e2f08519f51e444e98eb19ffa2a855168 /src/compiler
parent803d451a28824af17f0cab446e4c76f51003fd01 (diff)
downloadscala-2f0e5ec1e96a6e4806841069736eda844d3a8dd6.tar.gz
scala-2f0e5ec1e96a6e4806841069736eda844d3a8dd6.tar.bz2
scala-2f0e5ec1e96a6e4806841069736eda844d3a8dd6.zip
SI-6899, prohibit dangerous, useless implicit conversions.
Increase eligibility requirements for implicit conversions, such that T => U is ineligible if T <: Null <or> AnyRef <: U This has the salutary effect of allowing us to ditch 16 ridiculous implicits from Predef, since they existed solely to work around the absence of this restriction. There was one tiny impact on actual source code (one line in one file) shown here, necessitated because the literal null is not eligible to be implicitly converted to A via <:<. def f[A](implicit ev: Null <:< A): A = null // before def f[A](implicit ev: Null <:< A): A = ev(null) // after As impositions go it's on the tame side.
Diffstat (limited to 'src/compiler')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala28
1 files changed, 23 insertions, 5 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
}