Skip to content

Commit 69bfb34

Browse files
committed
Fix #3781: Eligibility checks should ignore SingletonType
When checking an implicit conversion for eligibility we should ignore any SingletonType upper bounds in its argument. This give rise to false negatives because we check against the underlying type when determining eligibility.
1 parent d3cd401 commit 69bfb34

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,18 @@ object Implicits {
7676

7777
def refMatches(ref: TermRef)(implicit ctx: Context) = /*trace(i"refMatches $ref $pt")*/ {
7878

79+
/** Widen type so that it is neither a singleton type nor it inherits from scala.Singleton. */
80+
def widenSingleton(tp: Type): Type = {
81+
val wtp = tp.widenSingleton
82+
if (wtp.derivesFrom(defn.SingletonClass)) defn.AnyType else wtp
83+
}
84+
7985
def discardForView(tpw: Type, argType: Type): Boolean = tpw match {
8086
case mt: MethodType =>
8187
mt.isImplicitMethod ||
8288
mt.paramInfos.lengthCompare(1) != 0 ||
8389
!ctx.test(implicit ctx =>
84-
argType relaxed_<:< mt.paramInfos.head.widenSingleton)
90+
argType relaxed_<:< widenSingleton(mt.paramInfos.head))
8591
case poly: PolyType =>
8692
// We do not need to call ProtoTypes#constrained on `poly` because
8793
// `refMatches` is always called with mode TypevarsMissContext enabled.
@@ -90,7 +96,7 @@ object Implicits {
9096
mt.isImplicitMethod ||
9197
mt.paramInfos.length != 1 ||
9298
!ctx.test(implicit ctx =>
93-
argType relaxed_<:< wildApprox(mt.paramInfos.head.widenSingleton, null, Set.empty))
99+
argType relaxed_<:< wildApprox(widenSingleton(mt.paramInfos.head), null, Set.empty))
94100
case rtp =>
95101
discardForView(wildApprox(rtp, null, Set.empty), argType)
96102
}
@@ -144,12 +150,7 @@ object Implicits {
144150
val res = adjustSingletonArg(tp.resType)
145151
if (res `eq` tp.resType) tp else tp.derivedLambdaType(resType = res)
146152
case tp: MethodType =>
147-
tp.paramInfos match {
148-
case (single: SingletonType) :: Nil =>
149-
tp.derivedLambdaType(paramInfos = single.widenSingleton :: Nil)
150-
case _ =>
151-
tp
152-
}
153+
tp.derivedLambdaType(paramInfos = tp.paramInfos.map(widenSingleton))
153154
case _ => tp
154155
}
155156

tests/run/i876.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,16 @@ object Test extends App {
77
val l: Int = s
88
assert(s == "hello")
99
assert(l == 5)
10+
}
11+
12+
object Test3781 {
13+
class Foo[T](val value : T)
14+
object Foo {
15+
implicit def fromXInt[T <: Int with Singleton](i : T): Foo[T] = new Foo[T](i)
16+
}
17+
class FooUser[T] {
18+
def op[T2](that : Foo[T2]) : FooUser[T2] = new FooUser[T2]
19+
}
20+
val f = new FooUser[1]
21+
val f2 = f op 2
1022
}

0 commit comments

Comments
 (0)