@@ -71,6 +71,15 @@ object Implicits {
7171 /** The implicit references */
7272 def refs : List [ImplicitRef ]
7373
74+ private var SingletonClass : ClassSymbol = null
75+
76+ /** Widen type so that it is neither a singleton type nor a type that inherits from scala.Singleton. */
77+ private def widenSingleton (tp : Type )(implicit ctx : Context ): Type = {
78+ if (SingletonClass == null ) SingletonClass = defn.SingletonClass
79+ val wtp = tp.widenSingleton
80+ if (wtp.derivesFrom(SingletonClass )) defn.AnyType else wtp
81+ }
82+
7483 /** Return those references in `refs` that are compatible with type `pt`. */
7584 protected def filterMatching (pt : Type )(implicit ctx : Context ): List [Candidate ] = track(" filterMatching" ) {
7685
@@ -80,15 +89,17 @@ object Implicits {
8089 case mt : MethodType =>
8190 mt.isImplicitMethod ||
8291 mt.paramInfos.lengthCompare(1 ) != 0 ||
83- ! ctx.test(implicit ctx => argType relaxed_<:< mt.paramInfos.head)
92+ ! ctx.test(implicit ctx =>
93+ argType relaxed_<:< widenSingleton(mt.paramInfos.head))
8494 case poly : PolyType =>
8595 // We do not need to call ProtoTypes#constrained on `poly` because
8696 // `refMatches` is always called with mode TypevarsMissContext enabled.
8797 poly.resultType match {
8898 case mt : MethodType =>
8999 mt.isImplicitMethod ||
90100 mt.paramInfos.length != 1 ||
91- ! ctx.test(implicit ctx => argType relaxed_<:< wildApprox(mt.paramInfos.head, null , Set .empty))
101+ ! ctx.test(implicit ctx =>
102+ argType relaxed_<:< wildApprox(widenSingleton(mt.paramInfos.head), null , Set .empty))
92103 case rtp =>
93104 discardForView(wildApprox(rtp, null , Set .empty), argType)
94105 }
@@ -132,14 +143,32 @@ object Implicits {
132143 case _ => false
133144 }
134145
146+ /** Widen singleton arguments of implicit conversions to their underlying type.
147+ * This is necessary so that they can be found eligible for the argument type.
148+ * Note that we always take the underlying type of a singleton type as the argument
149+ * type, so that we get a reasonable implicit cache hit ratio.
150+ */
151+ def adjustSingletonArg (tp : Type ): Type = tp match {
152+ case tp : PolyType =>
153+ val res = adjustSingletonArg(tp.resType)
154+ if (res `eq` tp.resType) tp else tp.derivedLambdaType(resType = res)
155+ case tp : MethodType =>
156+ tp.derivedLambdaType(paramInfos = tp.paramInfos.mapConserve(widenSingleton))
157+ case _ => tp
158+ }
159+
135160 (ref.symbol isAccessibleFrom ref.prefix) && {
136161 if (discard) {
137162 record(" discarded eligible" )
138163 false
139164 }
140165 else {
141166 val ptNorm = normalize(pt, pt) // `pt` could be implicit function types, check i2749
142- NoViewsAllowed .isCompatible(normalize(ref, pt), ptNorm)
167+ val refAdjusted =
168+ if (pt.isInstanceOf [ViewProto ]) adjustSingletonArg(ref.widenSingleton)
169+ else ref
170+ val refNorm = normalize(refAdjusted, pt)
171+ NoViewsAllowed .isCompatible(refNorm, ptNorm)
143172 }
144173 }
145174 }
0 commit comments