diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 63d82eab1047..e6b2b92d01d9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3868,7 +3868,7 @@ object Types { * A type is a SAM type if it is a reference to a class or trait, which * * - has a single abstract method with a method type (ExprType - * and PolyType not allowed!) + * and PolyType not allowed!) whose result type is not an implicit function type * - can be instantiated without arguments or with just () as argument. * * The pattern `SAMType(sam)` matches a SAM type, where `sam` is the @@ -3910,7 +3910,8 @@ object Types { // println(s"absMems: ${absMems map (_.show) mkString ", "}") if (absMems.size == 1) absMems.head.info match { - case mt: MethodType if !mt.isParamDependent => + case mt: MethodType if !mt.isParamDependent && + !defn.isImplicitFunctionType(mt.resultType) => val cls = tp.classSymbol // Given a SAM type such as: diff --git a/tests/neg/i4611a.scala b/tests/neg/i4611a.scala new file mode 100644 index 000000000000..0bcdd1c33ceb --- /dev/null +++ b/tests/neg/i4611a.scala @@ -0,0 +1,21 @@ +// Don't qualify as SAM type because result type is an implicit function type +trait Foo { + def foo(x: Int): implicit Int => Int +} + +trait Bar[T] { + def bar(x: Int): T +} + +class Test { + val good1 = new Foo { + def foo(x: Int) = 1 + } + + val good2 = new Bar[implicit Int => Int] { + def bar(x: Int) = 1 + } + + val bad1: Foo = (x: Int) => 1 // error + val bad2: Bar[implicit Int => Int] = (x: Int) => 1 // error +} diff --git a/tests/neg/i4611b.scala b/tests/neg/i4611b.scala new file mode 100644 index 000000000000..6e5f1b8a3017 --- /dev/null +++ b/tests/neg/i4611b.scala @@ -0,0 +1,24 @@ +import scala.concurrent.Future + +class Response +class Request +object Request { + type To[T] = implicit Request => T +} + +// Don't qualify as SAM type because result type is an implicit function type +trait Responder[T] { + def responseFor(value: T): Request.To[Future[Response]] +} + +object Responder { + // with SAM + val responseResponder: Responder[Response] = + response => Future.successful(response) // error + + // with anonymous class + val futureResponseResponder: Responder[Future[Response]] = new Responder[Future[Response]] { + override def responseFor(value: Future[Response]): Request.To[Future[Response]] = + value + } +} diff --git a/tests/run/implicitFuns2.scala b/tests/run/implicitFuns2.scala new file mode 100644 index 000000000000..56b815a716f0 --- /dev/null +++ b/tests/run/implicitFuns2.scala @@ -0,0 +1,48 @@ +class A +class B + +trait Foo { + def foo: implicit A => implicit B => Int +} + +class Foo1 extends Foo { + def foo: implicit A => implicit B => Int = 1 +} + +class Foo2 extends Foo1 { + override def foo: implicit A => implicit B => Int = 2 +} + +trait Foo3 extends Foo { + override def foo: implicit A => implicit B => Int = 3 +} + +class Bar[T] { + def bar: implicit A => T = null.asInstanceOf[T] +} + +class Bar1 extends Bar[implicit B => Int] { + override def bar: implicit A => implicit B => Int = 1 +} + +object Test { + def testFoo() = { + implicit val a = new A + implicit val b = new B + assert((new Foo1).foo == 1) + assert((new Foo2).foo == 2) + assert(new Foo3{}.foo == 3) + } + + def testBar() = { + implicit val a = new A + implicit val b = new B + assert((new Bar).bar == null) + assert((new Bar1).bar == 1) + } + + def main(args: Array[String]): Unit = { + testFoo() + testBar() + } +}