Skip to content

Commit cf1f290

Browse files
committed
Fix #5224: Make implicit shadowing conform to the rules in the spec
The previous version of implicit shadowing considered a nested reference as a shadow _only_ if it matched the prototype of the implicit search. This is not backed up by the spec, and is different to what scalac does. Arguably, the spec is right here: We should consider an implicit ineligible if it is not visible as a simple name because a nested reference has the same name, no matter what the type of the nested reference is.
1 parent 7463afe commit cf1f290

File tree

2 files changed

+41
-16
lines changed

2 files changed

+41
-16
lines changed

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+
typed(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 shadowoing occured). This is the case of 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 shadwoing
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
}

0 commit comments

Comments
 (0)