Skip to content

Commit 18f355d

Browse files
authored
Avoid shadowing by private definitions in more situations (#18142)
2 parents 1d4dec7 + 0f5292d commit 18f355d

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,16 @@ object Types {
703703
}
704704
findMember(name, pre, required, excluded)
705705
}
706+
707+
/** The implicit members with given name. If there are none and the denotation
708+
* contains private members, also look for shadowed non-private implicits.
709+
*/
710+
def implicitMembersNamed(name: Name)(using Context): List[SingleDenotation] =
711+
val d = member(name)
712+
val alts = d.altsWith(_.isOneOf(GivenOrImplicitVal))
713+
if alts.isEmpty && d.hasAltWith(_.symbol.is(Private)) then
714+
nonPrivateMember(name).altsWith(_.isOneOf(GivenOrImplicitVal))
715+
else alts
706716

707717
/** Find member of this type with given `name`, all `required`
708718
* flags and no `excluded` flag and produce a denotation that contains
@@ -1006,7 +1016,7 @@ object Types {
10061016
final def implicitMembers(using Context): List[TermRef] = {
10071017
record("implicitMembers")
10081018
memberDenots(implicitFilter,
1009-
(name, buf) => buf ++= member(name).altsWith(_.isOneOf(GivenOrImplicitVal)))
1019+
(name, buf) => buf ++= implicitMembersNamed(name))
10101020
.toList.map(d => TermRef(this, d.symbol.asTerm))
10111021
}
10121022

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ class ImportInfo(symf: Context ?=> Symbol,
148148
else
149149
for
150150
renamed <- reverseMapping.keys
151-
denot <- pre.member(reverseMapping(renamed).nn).altsWith(_.isOneOf(GivenOrImplicitVal))
151+
denot <- pre.implicitMembersNamed(reverseMapping(renamed).nn)
152152
yield
153153
val original = reverseMapping(renamed).nn
154154
val ref = TermRef(pre, original, denot)

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -288,16 +288,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
288288
case ImportType(expr) =>
289289
val pre = expr.tpe
290290
val denot0 = pre.memberBasedOnFlags(name, required, excluded)
291-
.accessibleFrom(pre)(using refctx)
291+
var accessibleDenot = denot0.accessibleFrom(pre)(using refctx)
292+
if !accessibleDenot.exists && denot0.hasAltWith(_.symbol.is(Private)) then
293+
accessibleDenot = pre.memberBasedOnFlags(name, required, excluded | Private)
294+
.accessibleFrom(pre)(using refctx)
292295
// Pass refctx so that any errors are reported in the context of the
293296
// reference instead of the context of the import scope
294-
if denot0.exists then
297+
if accessibleDenot.exists then
295298
val denot =
296299
if checkBounds then
297-
denot0.filterWithPredicate { mbr =>
300+
accessibleDenot.filterWithPredicate { mbr =>
298301
mbr.matchesImportBound(if mbr.symbol.is(Given) then imp.givenBound else imp.wildcardBound)
299302
}
300-
else denot0
303+
else accessibleDenot
301304
def isScalaJsPseudoUnion =
302305
denot.name == tpnme.raw.BAR && ctx.settings.scalajs.value && denot.symbol == JSDefinitions.jsdefn.PseudoUnionClass
303306
// Just like Scala2Unpickler reinterprets Scala.js pseudo-unions

tests/pos/i18135.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class Conf
2+
3+
class Bar(_conf: Conf) {
4+
implicit val conf: Conf = _conf
5+
}
6+
7+
class Foo(conf: Conf) extends Bar(conf)
8+
//class Foo(_conf: Conf) extends Bar(_conf)
9+
// using a different name fixes it
10+
11+
class Test {
12+
def test(foo: Foo) = {
13+
import foo.*
14+
//implicit val conf: Conf = foo.conf
15+
// manually redefining it also fixes it
16+
assert(conf != null)
17+
assert(implicitly[Conf] != null)
18+
}
19+
def test2(foo: Foo) = {
20+
import foo.conf
21+
//implicit val conf: Conf = foo.conf
22+
// manually redefining it also fixes it
23+
assert(conf != null)
24+
assert(implicitly[Conf] != null)
25+
}
26+
}

0 commit comments

Comments
 (0)