Skip to content

Commit 981bdfd

Browse files
authored
Merge pull request #5227 from dotty-staging/fix-#5224
Fix #5224: Make implicit shadowing conform to the rules in the spec
2 parents 8031978 + 876fb32 commit 981bdfd

File tree

5 files changed

+66
-16
lines changed

5 files changed

+66
-16
lines changed

compiler/src/dotty/tools/dotc/Driver.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class Driver {
3434
case ex: FatalError =>
3535
ctx.error(ex.getMessage) // signals that we should fail compilation.
3636
ctx.reporter
37+
case ex: Throwable =>
38+
println(s"$ex while compiling ${fileNames.mkString(", ")}")
39+
throw ex
3740
}
3841
else ctx.reporter
3942

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Mode.ImplicitsEnabled
1616
import NameOps._
1717
import NameKinds.LazyImplicitName
1818
import Symbols._
19+
import Denotations._
1920
import Types._
2021
import Decorators._
2122
import Names._
@@ -907,12 +908,6 @@ trait Implicits { self: Typer =>
907908
/** The expected type for the searched implicit */
908909
lazy val fullProto: Type = implicitProto(pt, identity)
909910

910-
lazy val funProto: Type = fullProto match {
911-
case proto: ViewProto =>
912-
FunProto(untpd.TypedSplice(dummyTreeOfType(proto.argType)) :: Nil, proto.resultType)(self)
913-
case proto => proto
914-
}
915-
916911
/** The expected type where parameters and uninstantiated typevars are replaced by wildcard types */
917912
val wildProto: Type = implicitProto(pt, wildApprox(_))
918913

@@ -930,18 +925,31 @@ trait Implicits { self: Typer =>
930925
untpd.Apply(untpd.TypedSplice(generated), untpd.TypedSplice(argument) :: Nil),
931926
pt, locked)
932927
val generated1 = adapt(generated, pt, locked)
928+
933929
lazy val shadowing =
934-
typed(untpd.Ident(cand.implicitRef.implicitName) withPos pos.toSynthetic, funProto)(
930+
typedUnadapted(untpd.Ident(cand.implicitRef.implicitName) withPos pos.toSynthetic)(
935931
nestedContext().addMode(Mode.ImplicitShadowing).setExploreTyperState())
936-
def refSameAs(shadowing: Tree): Boolean =
937-
ref.symbol == closureBody(shadowing).symbol || {
938-
shadowing match {
939-
case Trees.Select(qual, nme.apply) => refSameAs(qual)
940-
case Trees.Apply(fn, _) => refSameAs(fn)
941-
case Trees.TypeApply(fn, _) => refSameAs(fn)
942-
case _ => false
943-
}
932+
933+
/** Is candidate reference the same as the `shadowing` reference? (i.e.
934+
* no actual shadowing occured). This is the case if the
935+
* underlying symbol of the shadowing reference is the same as the
936+
* symbol of the candidate reference, or if they have a common type owner.
937+
*
938+
* The second condition (same owner) is needed because the candidate reference
939+
* and the potential shadowing reference are typechecked with different prototypes.
940+
* so might yield different overloaded symbols. E.g. if the candidate reference
941+
* is to an implicit conversion generated from an implicit class, the shadowing
942+
* reference could go to the companion object of that class instead.
943+
*/
944+
def refSameAs(shadowing: Tree): Boolean = {
945+
def symMatches(sym: Symbol): Boolean =
946+
sym == ref.symbol || sym.owner.isType && sym.owner == ref.symbol.owner
947+
def denotMatches(d: Denotation): Boolean = d match {
948+
case d: SingleDenotation => symMatches(d.symbol)
949+
case d => d.hasAltWith(denotMatches(_))
944950
}
951+
denotMatches(closureBody(shadowing).denot)
952+
}
945953

946954
if (ctx.reporter.hasErrors) {
947955
ctx.reporter.removeBufferedMessages

tests/neg/implicit-shadowing.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,25 @@ object Test {
55
def outer(implicit c: C) = {
66

77
def f(c: C) = implicitly[C] // error: shadowing
8-
def g(c: Int) = implicitly[C] // ok since type is different
8+
def g(c: Int) = implicitly[C] // error: shadowing (even though type is different)
99

1010
f(new C)
1111
}
12+
13+
class C1[X]
14+
class C2[X]
15+
16+
def f[T: C1] = {
17+
def g[U: C2] = {
18+
implicitly[C1[T]] // OK: no shadowing for evidence parameters
19+
implicitly[C2[U]]
20+
}
21+
}
22+
23+
def h[T]: implicit C1[T] => Unit = {
24+
def g[U]: implicit C2[U] => Unit = {
25+
implicitly[C1[T]] // OK: no shadowing for evidence parameters
26+
implicitly[C2[U]]
27+
}
28+
}
1229
}

tests/run/i5224.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
barInt
2+
bar

tests/run/i5224.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object Test extends App {
2+
class Bar[T]
3+
4+
implicit def barInt: Bar[Int] = {
5+
println("barInt")
6+
new Bar[Int]
7+
}
8+
implicit def bar[T]: Bar[T] = {
9+
println("bar")
10+
new Bar[T]
11+
}
12+
13+
implicitly[Bar[Int]]
14+
15+
locally {
16+
def barInt: Unit = ???
17+
18+
implicitly[Bar[Int]]
19+
}
20+
}

0 commit comments

Comments
 (0)