From a285ee47b387c30301d6d2ec0bc46dfa7f3306db Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 13 Jun 2020 13:14:51 +0200 Subject: [PATCH] Fix #9051: Fix accessibility test for implicit candidates If it comes from a type's implicit scope, accessibility from a context should not matter to determine the initially eligible candidates. Accessibility will be tested later when an implicit is tried. --- .../dotty/tools/dotc/typer/Implicits.scala | 24 +++++++++++-------- tests/neg/i9051.scala | 11 +++++++++ tests/pos/i9051.scala | 15 ++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 tests/neg/i9051.scala create mode 100644 tests/pos/i9051.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 3da72a6c680e..b3e476467bf7 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -100,6 +100,8 @@ object Implicits { if (wtp.derivesFrom(SingletonClass)) defn.AnyType else wtp } + protected def isAccessible(ref: TermRef)(using Context): Boolean + /** Return those references in `refs` that are compatible with type `pt`. */ protected def filterMatching(pt: Type)(using Context): List[Candidate] = { record("filterMatching") @@ -198,7 +200,8 @@ object Implicits { case _ => tp var ckind = - if (!ref.symbol.isAccessibleFrom(ref.prefix)) Candidate.None + if !isAccessible(ref) then + Candidate.None else pt match { case pt: ViewProto => viewCandidateKind(ref.widen, pt.argType, pt.resType) @@ -259,6 +262,9 @@ object Implicits { filterMatching(tp) } + override def isAccessible(ref: TermRef)(using Context): Boolean = + ref.symbol.exists && !ref.symbol.is(Private) + override def toString: String = i"OfTypeImplicits($tp), companions = ${companionRefs.toList}%, %; refs = $refs%, %." } @@ -326,6 +332,9 @@ object Implicits { } } + override def isAccessible(ref: TermRef)(using Context): Boolean = + ref.symbol.isAccessibleFrom(ref.prefix) + override def toString: String = { val own = i"(implicits: $refs%, %)" if (isOuterMost) own else own + "\n " + outerImplicits @@ -960,7 +969,6 @@ trait Implicits { self: Typer => implicits.println(i"committing ${result.tstate.constraint} yielding ${ctx.typerState.constraint} in ${ctx.typerState}") result case result: SearchFailure if result.isAmbiguous => - //println(i"FAIL for $pt / $argument: $result0") val deepPt = pt.deepenProto if (deepPt ne pt) inferImplicit(deepPt, argument, span) else if (migrateTo3 && !ctx.mode.is(Mode.OldOverloadingResolution)) @@ -975,10 +983,8 @@ trait Implicits { self: Typer => } else result case NoMatchingImplicitsFailure => - //println(i"FAIL for $pt / $argument: $result0") SearchFailure(new NoMatchingImplicits(pt, argument, ctx.typerState.constraint)) case _ => - //println(i"FAIL for $pt / $argument: $result0") result0 } // If we are at the outermost implicit search then emit the implicit dictionary, if any. @@ -1024,7 +1030,9 @@ trait Implicits { self: Typer => case _ => tryConversion } - if (ctx.reporter.hasErrors) { + if ctx.reporter.hasErrors + || !cand.ref.symbol.isAccessibleFrom(cand.ref.prefix) + then ctx.reporter.removeBufferedMessages adapted.tpe match { case _: SearchFailureType => SearchFailure(adapted) @@ -1036,13 +1044,11 @@ trait Implicits { self: Typer => else SearchFailure(adapted.withType(new MismatchedImplicit(ref, pt, argument))) } - } - else { + else val returned = if (cand.isExtension) Applications.ExtMethodApply(adapted) else adapted SearchSuccess(returned, ref, cand.level)(ctx.typerState, ctx.gadt) - } } /** An implicit search; parameters as in `inferImplicit` */ @@ -1067,8 +1073,6 @@ trait Implicits { self: Typer => val isNot: Boolean = wildProto.classSymbol == defn.NotClass - //println(i"search implicits $pt / ${eligible.map(_.ref)}") - /** Try to type-check implicit reference, after checking that this is not * a diverging search */ diff --git a/tests/neg/i9051.scala b/tests/neg/i9051.scala new file mode 100644 index 000000000000..360f3b20eec7 --- /dev/null +++ b/tests/neg/i9051.scala @@ -0,0 +1,11 @@ +package zio: + + class ZRef + object ZRef: + + private[zio] implicit class ZRefSyntax(private val self: ZRef): + def unsafeUpdate: Boolean = true + +object Main: + val ref = new zio.ZRef + println(ref.unsafeUpdate) // error diff --git a/tests/pos/i9051.scala b/tests/pos/i9051.scala new file mode 100644 index 000000000000..efb530cc1c3e --- /dev/null +++ b/tests/pos/i9051.scala @@ -0,0 +1,15 @@ +package zio + +class ZRef + +object ZRef { + + private[zio] implicit class ZRefSyntax(private val self: ZRef) extends AnyVal { + def unsafeUpdate: Boolean = true + } +} + +object Main extends App { + val ref = new ZRef + println(ref.unsafeUpdate) +} \ No newline at end of file