diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 56646848bab3..f0788665ca17 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -752,10 +752,12 @@ trait Implicits { self: Typer => lazy val shadowing = typed(untpd.Ident(ref.name) withPos pos.toSynthetic, funProto)( nestedContext.addMode(Mode.ImplicitShadowing).setExploreTyperState) - def refMatches(shadowing: Tree): Boolean = + def refSameAs(shadowing: Tree): Boolean = ref.symbol == closureBody(shadowing).symbol || { shadowing match { - case Trees.Select(qual, nme.apply) => refMatches(qual) + case Trees.Select(qual, nme.apply) => refSameAs(qual) + case Trees.Apply(fn, _) => refSameAs(fn) + case Trees.TypeApply(fn, _) => refSameAs(fn) case _ => false } } @@ -782,7 +784,7 @@ trait Implicits { self: Typer => if (ctx.reporter.hasErrors) nonMatchingImplicit(ref, ctx.reporter.removeBufferedMessages) else if (contextual && !ctx.mode.is(Mode.ImplicitShadowing) && - !shadowing.tpe.isError && !refMatches(shadowing)) { + !shadowing.tpe.isError && !refSameAs(shadowing)) { implicits.println(i"SHADOWING $ref in ${ref.termSymbol.owner} is shadowed by $shadowing in ${shadowing.symbol.owner}") shadowedImplicit(ref, methPart(shadowing).tpe) } diff --git a/tests/pos/ho-implicits.scala b/tests/pos/ho-implicits.scala new file mode 100644 index 000000000000..de3874f47c5a --- /dev/null +++ b/tests/pos/ho-implicits.scala @@ -0,0 +1,9 @@ +object Test2 { + + implicit def __1: implicit Int => String = s"implicit: ${implicitly[Int]}" + implicit def __2: Int = 42 + + def f: implicit String => Int = implicitly[String].length + + f: Int +} \ No newline at end of file diff --git a/tests/pos/implicitFuns.scala b/tests/pos/implicitFuns.scala new file mode 100644 index 000000000000..41c57e2a018e --- /dev/null +++ b/tests/pos/implicitFuns.scala @@ -0,0 +1,69 @@ +package cm2 + +case class Person(name: String) +case class Paper(title: String, authors: List[Person], body: String) + +class Viewers(val persons: Set[Person]) + +class ConfManagement(papers: List[Paper], realScore: Map[Paper, Int]) extends App { + + private def hasConflict(ps1: Set[Person], ps2: Iterable[Person]) = + ps2.exists(ps1 contains _) + + type Viewable[T] = implicit Viewers => T + + def vs: Viewable[Viewers] = implicitly + + def viewers: Viewable[Set[Person]] = vs.persons + + def score: Paper => Viewable[Int] = + paper => + if hasConflict(viewers, paper.authors) then -100 + else realScore(paper) + + def viewRankings: Viewable[List[(String, Int)]] = + papers.sortBy(-score(_)).map(p => (p.title, score(p))) + + def delegate[T]: (Viewers => T) => Person => Viewable[T] = + query => p => query(new Viewers(viewers + p)) +} + +object Test extends App { + def bob = Person("Bob") + def peter = Person("Peter") + def p1 = Paper("Bob's paper", List(bob), "") + def p2 = Paper("Peter's paper", List(peter), "") + + implicit def __1: Viewers = new Viewers(Set(bob)) + + val cm = new ConfManagement(List(p1, p2), Map(p1 -> 2, p2 -> 3)) + + println(cm.viewRankings) + println(cm.score(p1)) + println(Orderings.isLess(Nil)(List(1, 2, 3))) +} + +object Orderings extends App { + + trait Ord[T] { def less: T => T => Boolean } + + implicit def __1: Ord[Int] = new Ord[Int] { + def less: Int => Int => Boolean = + x => y => x < y + } + + implicit def __2[T]: implicit Ord[T] => Ord[List[T]] = new Ord[List[T]] { + def less: List[T] => List[T] => Boolean = + xs => ys => + if ys.isEmpty then false + else if xs.isEmpty then true + else if xs.head == ys.head then less(xs.tail)(ys.tail) + else isLess(xs.head)(ys.head) + } + + def isLess[T]: T => T => implicit Ord[T] => Boolean = + x => y => implicitly[Ord[T]].less(x)(y) + + println(isLess(Nil)(List(1, 2, 3))) + println(isLess(List(List(1)))(List(List(1)))) +} diff --git a/tests/run/cochis.scala b/tests/run/cochis.scala new file mode 100644 index 000000000000..07037432965c --- /dev/null +++ b/tests/run/cochis.scala @@ -0,0 +1,15 @@ +import Predef.{$conforms => _, _} + +trait A { + + implicit def id[A] : A => A = x => x // (1) + def trans[A] (x : A) (implicit f : A => A) = f(x) +} +object Test extends A with App { + implicit def succ : Int ⇒ Int = x ⇒ x + 1 // (3) + def bad [A] (x : A) : A = trans[A](x) // (4) incoherent de€nition ! + val v1 = bad [Int] (3) // (5) evaluates to 3 + val v2 = trans [Int] (3) // (6) substituting bad by trans is rejected + assert(v1 == 3) + assert(v2 == 4) +}