Skip to content

Commit

Permalink
Avoid shadowing by private definitions in more situations (#18142)
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand authored Jul 5, 2023
2 parents 1d4dec7 + 0f5292d commit 18f355d
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 6 deletions.
12 changes: 11 additions & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,16 @@ object Types {
}
findMember(name, pre, required, excluded)
}

/** The implicit members with given name. If there are none and the denotation
* contains private members, also look for shadowed non-private implicits.
*/
def implicitMembersNamed(name: Name)(using Context): List[SingleDenotation] =
val d = member(name)
val alts = d.altsWith(_.isOneOf(GivenOrImplicitVal))
if alts.isEmpty && d.hasAltWith(_.symbol.is(Private)) then
nonPrivateMember(name).altsWith(_.isOneOf(GivenOrImplicitVal))
else alts

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

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/ImportInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class ImportInfo(symf: Context ?=> Symbol,
else
for
renamed <- reverseMapping.keys
denot <- pre.member(reverseMapping(renamed).nn).altsWith(_.isOneOf(GivenOrImplicitVal))
denot <- pre.implicitMembersNamed(reverseMapping(renamed).nn)
yield
val original = reverseMapping(renamed).nn
val ref = TermRef(pre, original, denot)
Expand Down
11 changes: 7 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -288,16 +288,19 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
case ImportType(expr) =>
val pre = expr.tpe
val denot0 = pre.memberBasedOnFlags(name, required, excluded)
.accessibleFrom(pre)(using refctx)
var accessibleDenot = denot0.accessibleFrom(pre)(using refctx)
if !accessibleDenot.exists && denot0.hasAltWith(_.symbol.is(Private)) then
accessibleDenot = pre.memberBasedOnFlags(name, required, excluded | Private)
.accessibleFrom(pre)(using refctx)
// Pass refctx so that any errors are reported in the context of the
// reference instead of the context of the import scope
if denot0.exists then
if accessibleDenot.exists then
val denot =
if checkBounds then
denot0.filterWithPredicate { mbr =>
accessibleDenot.filterWithPredicate { mbr =>
mbr.matchesImportBound(if mbr.symbol.is(Given) then imp.givenBound else imp.wildcardBound)
}
else denot0
else accessibleDenot
def isScalaJsPseudoUnion =
denot.name == tpnme.raw.BAR && ctx.settings.scalajs.value && denot.symbol == JSDefinitions.jsdefn.PseudoUnionClass
// Just like Scala2Unpickler reinterprets Scala.js pseudo-unions
Expand Down
26 changes: 26 additions & 0 deletions tests/pos/i18135.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Conf

class Bar(_conf: Conf) {
implicit val conf: Conf = _conf
}

class Foo(conf: Conf) extends Bar(conf)
//class Foo(_conf: Conf) extends Bar(_conf)
// using a different name fixes it

class Test {
def test(foo: Foo) = {
import foo.*
//implicit val conf: Conf = foo.conf
// manually redefining it also fixes it
assert(conf != null)
assert(implicitly[Conf] != null)
}
def test2(foo: Foo) = {
import foo.conf
//implicit val conf: Conf = foo.conf
// manually redefining it also fixes it
assert(conf != null)
assert(implicitly[Conf] != null)
}
}

0 comments on commit 18f355d

Please sign in to comment.