From 91a6f57c64a2a4ddf96f0eb08a068b8e2f6bba74 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 28 Dec 2017 12:15:46 +0100 Subject: [PATCH] Fix #3692: Generalize implicit function subtyping. With this change, (implicit x: C): D <: (x: C): D but not the other way around. This affects subtyping of dependent implicit function types. Now: (implicit x: C) => D <: (x: C) => D See also #2000. As a second change, prevent crashing on type mismatch errors involving dependent implicit function types. --- .../src/dotty/tools/dotc/core/TypeComparer.scala | 2 +- .../src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- tests/neg/i2000.scala | 2 +- tests/pos/i3692.scala | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i3692.scala diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala index cf36629dd599..3673497e5dc4 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala @@ -513,7 +513,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling { case tp1: MethodOrPoly => (tp1.signature consistentParams tp2.signature) && matchingParams(tp1, tp2) && - tp1.isImplicitMethod == tp2.isImplicitMethod && + (!tp2.isImplicitMethod || tp1.isImplicitMethod) && isSubType(tp1.resultType, tp2.resultType.subst(tp2, tp1)) case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala index 067b9c1e15df..3150220b8f3e 100644 --- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -470,7 +470,7 @@ object ProtoTypes { normalize(et.resultType, pt) case wtp => val iftp = defn.asImplicitFunctionType(wtp) - if (iftp.exists) normalize(iftp.argInfos.last, pt) else tp + if (iftp.exists) normalize(iftp.dropDependentRefinement.argInfos.last, pt) else tp } } diff --git a/tests/neg/i2000.scala b/tests/neg/i2000.scala index aa1250f08561..b035c009bba6 100644 --- a/tests/neg/i2000.scala +++ b/tests/neg/i2000.scala @@ -1,6 +1,6 @@ object test1 { class C[A] { def foo(a: A) = "c" } - class D extends C[String] { override def foo(implicit s: String) = "d" } // error + class D extends C[String] { override def foo(implicit s: String) = "d" } // used to be error, now ok } object test2 { diff --git a/tests/pos/i3692.scala b/tests/pos/i3692.scala new file mode 100644 index 000000000000..8fe924cfc462 --- /dev/null +++ b/tests/pos/i3692.scala @@ -0,0 +1,15 @@ +class C { type T } + +object Main { + + //val a: implicit Int => Int = implicit (x: Int) => x + //val b: Int => Int = a + + def main(args: Array[String]): Unit = { + val choose: implicit (c: C) => Set[Int] = Set.empty + val b0: (C) => Set[Int] = choose + val b1: (c: C) => Set[Int] = choose + def applyF(f: (c: C) => Set[Int]) = f(new C{type T=Int}) + //applyF(choose) + } +}