From 3966b082766029a48b3d2e38ff4763851701767c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 26 Jan 2018 11:45:56 +0100 Subject: [PATCH] Fix #1857: Allow lower bounds in to influence implicit search The previous implementation claimed to conform to the spec: We exclude lower bounds to conform to SLS 7.2: "The parts of a type T are: [...] if T is an abstract type, the parts of its upper bound" But in fact we do not need to exclude lower bounds from `namedPartsWith` to do that - TypeRefs are already lifted to classes, which implements SLS 7.2. Including lower bounds does affect wildcard types (i1857.scala) and wildcard parameters in implicits (implicit-lower-bound.scala), but the spec does not exclude either if these. --- .../dotty/tools/dotc/typer/Implicits.scala | 5 +-- tests/pos/i1857.scala | 38 +++++++++++++++++++ tests/{neg => pos}/implicit-lower-bound.scala | 4 +- 3 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 tests/pos/i1857.scala rename tests/{neg => pos}/implicit-lower-bound.scala (85%) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index c49331f43883..ec67d24fad30 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -459,10 +459,7 @@ trait ImplicitRunInfo { self: Run => } tp.classSymbols(liftingCtx) foreach addClassScope case _ => - // We exclude lower bounds to conform to SLS 7.2: - // "The parts of a type T are: [...] if T is an abstract type, the parts of its upper bound" - for (part <- tp.namedPartsWith(_.isType, excludeLowerBounds = true)) - comps ++= iscopeRefs(part) + for (part <- tp.namedPartsWith(_.isType)) comps ++= iscopeRefs(part) } comps } diff --git a/tests/pos/i1857.scala b/tests/pos/i1857.scala new file mode 100644 index 000000000000..635612104fc3 --- /dev/null +++ b/tests/pos/i1857.scala @@ -0,0 +1,38 @@ +package commandeer + + +trait CommandeerDSL[Host] { + trait Operation[T] + type Op[T] <: Operation[T] +} + +object CommandeerDSL { + def apply[Host, DSL <: CommandeerDSL[Host]](host: Host)(implicit dsl: DSL): DSL = dsl +} + +trait Foo { + def bar(a: String, b: Int): Double +} + +object Foo { + implicit val fooDSL: FooDSL = new FooDSL {} +} + +trait FooDSL extends CommandeerDSL[Foo] { + sealed trait FooOperation[T] extends Operation[T] + type Op[T] = FooOperation[T] + + case class Bar(a: String, b: Int) extends FooOperation[Double] +} + +object RunMe { + //import Foo._ + def main(args: Array[String]): Unit = { + println("Hi Mum") + + val kevin = CommandeerDSL(null.asInstanceOf[Foo]) + println(s"Found DSL for Foo: $kevin") + val bar = kevin.Bar("bob", 3) + println(s"Made a bar: $bar") + } +} diff --git a/tests/neg/implicit-lower-bound.scala b/tests/pos/implicit-lower-bound.scala similarity index 85% rename from tests/neg/implicit-lower-bound.scala rename to tests/pos/implicit-lower-bound.scala index 4d5e6389ce57..5729c33ecc0b 100644 --- a/tests/neg/implicit-lower-bound.scala +++ b/tests/pos/implicit-lower-bound.scala @@ -9,6 +9,6 @@ class Test { def get1(implicit lf: List[_ <: Bar]) = {} def get2(implicit lf: List[_ >: Bar]) = {} - get1 // works - get2 // error + get1 + get2 }