@@ -134,11 +134,6 @@ trait Implicits {
134
134
private val improvesCache = perRunCaches.newMap[(ImplicitInfo , ImplicitInfo ), Boolean ]()
135
135
private val implicitSearchId = { var id = 1 ; () => try id finally id += 1 }
136
136
137
- private def isInvalidConversionSource (tpe : Type ): Boolean = tpe match {
138
- case Function1 (in, _) => in <:< NullClass .tpe
139
- case _ => false
140
- }
141
-
142
137
def resetImplicits () {
143
138
implicitsCache.clear()
144
139
infoMapCache.clear()
@@ -1388,27 +1383,32 @@ trait Implicits {
1388
1383
}
1389
1384
}
1390
1385
if (result.isSuccess && isView) {
1391
- def maybeInvalidConversionError (msg : String ) {
1386
+ def maybeInvalidConversionError (msg : String ): Boolean = {
1392
1387
// We have to check context.ambiguousErrors even though we are calling "issueAmbiguousError"
1393
1388
// which ostensibly does exactly that before issuing the error. Why? I have no idea. Test is pos/t7690.
1394
1389
// AM: I would guess it's because ambiguous errors will be buffered in silent mode if they are not reported
1395
1390
if (context.ambiguousErrors)
1396
1391
context.issueAmbiguousError(AmbiguousImplicitTypeError (tree, msg))
1392
+ true
1397
1393
}
1398
1394
pt match {
1399
- case Function1 (_, out) =>
1400
- // must inline to avoid capturing result
1401
- def prohibit (sym : Symbol ) = (sym.tpe <:< out) && {
1402
- maybeInvalidConversionError(s " the result type of an implicit conversion must be more specific than ${sym.name}" )
1403
- true
1404
- }
1405
- if (prohibit(AnyRefClass ) || (settings.isScala211 && prohibit(AnyValClass )))
1406
- result = SearchFailure
1407
- case _ => false
1408
- }
1409
- if (settings.isScala211 && isInvalidConversionSource(pt)) {
1410
- maybeInvalidConversionError(" an expression of type Null is ineligible for implicit conversion" )
1411
- result = SearchFailure
1395
+ // SI-10206 don't use subtyping to rule out AnyRef/AnyVal:
1396
+ // - there are several valid structural types that are supertypes of AnyRef (e.g., created by HasMember);
1397
+ // typeSymbol will do the trick (AnyRef is a type alias for Object), while ruling out these structural types
1398
+ // - also don't want to accidentally constrain type vars through using <:<
1399
+ case Function1 (in, out) =>
1400
+ val outSym = out.typeSymbol
1401
+
1402
+ val fail =
1403
+ if (out.annotations.isEmpty && (outSym == ObjectClass || (isScala211 && outSym == AnyValClass )))
1404
+ maybeInvalidConversionError(s " the result type of an implicit conversion must be more specific than $out" )
1405
+ else if (isScala211 && in.annotations.isEmpty && in.typeSymbol == NullClass )
1406
+ maybeInvalidConversionError(" an expression of type Null is ineligible for implicit conversion" )
1407
+ else false
1408
+
1409
+ if (fail) result = SearchFailure
1410
+
1411
+ case _ =>
1412
1412
}
1413
1413
}
1414
1414
@@ -1418,6 +1418,9 @@ trait Implicits {
1418
1418
result
1419
1419
}
1420
1420
1421
+ // this setting is expensive to check, actually....
1422
+ private [this ] val isScala211 = settings.isScala211
1423
+
1421
1424
def allImplicits : List [SearchResult ] = {
1422
1425
def search (iss : Infoss , isLocalToCallsite : Boolean ) = applicableInfos(iss, isLocalToCallsite).values
1423
1426
(
0 commit comments