Skip to content

Commit d6df02b

Browse files
authored
Merge pull request #4723 from dotty-staging/fix-4611-v2
Fix #4611
2 parents 82b84da + 0281bc7 commit d6df02b

File tree

4 files changed

+96
-2
lines changed

4 files changed

+96
-2
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3868,7 +3868,7 @@ object Types {
38683868
* A type is a SAM type if it is a reference to a class or trait, which
38693869
*
38703870
* - has a single abstract method with a method type (ExprType
3871-
* and PolyType not allowed!)
3871+
* and PolyType not allowed!) whose result type is not an implicit function type
38723872
* - can be instantiated without arguments or with just () as argument.
38733873
*
38743874
* The pattern `SAMType(sam)` matches a SAM type, where `sam` is the
@@ -3910,7 +3910,8 @@ object Types {
39103910
// println(s"absMems: ${absMems map (_.show) mkString ", "}")
39113911
if (absMems.size == 1)
39123912
absMems.head.info match {
3913-
case mt: MethodType if !mt.isParamDependent =>
3913+
case mt: MethodType if !mt.isParamDependent &&
3914+
!defn.isImplicitFunctionType(mt.resultType) =>
39143915
val cls = tp.classSymbol
39153916

39163917
// Given a SAM type such as:

tests/neg/i4611a.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Don't qualify as SAM type because result type is an implicit function type
2+
trait Foo {
3+
def foo(x: Int): implicit Int => Int
4+
}
5+
6+
trait Bar[T] {
7+
def bar(x: Int): T
8+
}
9+
10+
class Test {
11+
val good1 = new Foo {
12+
def foo(x: Int) = 1
13+
}
14+
15+
val good2 = new Bar[implicit Int => Int] {
16+
def bar(x: Int) = 1
17+
}
18+
19+
val bad1: Foo = (x: Int) => 1 // error
20+
val bad2: Bar[implicit Int => Int] = (x: Int) => 1 // error
21+
}

tests/neg/i4611b.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import scala.concurrent.Future
2+
3+
class Response
4+
class Request
5+
object Request {
6+
type To[T] = implicit Request => T
7+
}
8+
9+
// Don't qualify as SAM type because result type is an implicit function type
10+
trait Responder[T] {
11+
def responseFor(value: T): Request.To[Future[Response]]
12+
}
13+
14+
object Responder {
15+
// with SAM
16+
val responseResponder: Responder[Response] =
17+
response => Future.successful(response) // error
18+
19+
// with anonymous class
20+
val futureResponseResponder: Responder[Future[Response]] = new Responder[Future[Response]] {
21+
override def responseFor(value: Future[Response]): Request.To[Future[Response]] =
22+
value
23+
}
24+
}

tests/run/implicitFuns2.scala

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class A
2+
class B
3+
4+
trait Foo {
5+
def foo: implicit A => implicit B => Int
6+
}
7+
8+
class Foo1 extends Foo {
9+
def foo: implicit A => implicit B => Int = 1
10+
}
11+
12+
class Foo2 extends Foo1 {
13+
override def foo: implicit A => implicit B => Int = 2
14+
}
15+
16+
trait Foo3 extends Foo {
17+
override def foo: implicit A => implicit B => Int = 3
18+
}
19+
20+
class Bar[T] {
21+
def bar: implicit A => T = null.asInstanceOf[T]
22+
}
23+
24+
class Bar1 extends Bar[implicit B => Int] {
25+
override def bar: implicit A => implicit B => Int = 1
26+
}
27+
28+
object Test {
29+
def testFoo() = {
30+
implicit val a = new A
31+
implicit val b = new B
32+
assert((new Foo1).foo == 1)
33+
assert((new Foo2).foo == 2)
34+
assert(new Foo3{}.foo == 3)
35+
}
36+
37+
def testBar() = {
38+
implicit val a = new A
39+
implicit val b = new B
40+
assert((new Bar).bar == null)
41+
assert((new Bar1).bar == 1)
42+
}
43+
44+
def main(args: Array[String]): Unit = {
45+
testFoo()
46+
testBar()
47+
}
48+
}

0 commit comments

Comments
 (0)