Skip to content

Fix #10311: Inaccessible members do not qualify for SelectionProtos #10316

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions compiler/src/dotty/tools/dotc/ast/Desugar.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ object desugar {
import untpd._
import DesugarEnums._

/** If a Select node carries this attachment, suppress the check
* that its type refers to an acessible symbol.
*/
val SuppressAccessCheck: Property.Key[Unit] = Property.Key()

/** An attachment for companion modules of classes that have a `derives` clause.
* The position value indicates the start position of the template of the
* deriving class.
Expand Down
10 changes: 6 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,12 @@ object ProtoTypes {
{
val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name)
def qualifies(m: SingleDenotation) =
memberProto.isRef(defn.UnitClass) ||
tp1.isValueType && compat.normalizedCompatible(NamedType(tp1, name, m), memberProto, keepConstraint)
// Note: can't use `m.info` here because if `m` is a method, `m.info`
// loses knowledge about `m`'s default arguments.
val isAccessible = !m.symbol.exists || m.symbol.isAccessibleFrom(tp1, superAccess = true)
isAccessible
&& (memberProto.isRef(defn.UnitClass)
|| tp1.isValueType && compat.normalizedCompatible(NamedType(tp1, name, m), memberProto, keepConstraint))
// Note: can't use `m.info` here because if `m` is a method, `m.info`
// loses knowledge about `m`'s default arguments.
mbr match { // hasAltWith inlined for performance
case mbr: SingleDenotation => mbr.exists && qualifies(mbr)
case _ => mbr hasAltWith qualifies
Expand Down
6 changes: 2 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,9 @@ trait TypeAssigner {
/** The type of the selection in `tree`, where `qual1` is the typed qualifier part.
* The selection type is additionally checked for accessibility.
*/
def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type = {
def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(using Context): Type =
val ownType = selectionType(tree, qual1)
if (tree.hasAttachment(desugar.SuppressAccessCheck)) ownType
else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.srcPos)
}
ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.srcPos)

/** Type assignment method. Each method takes as parameters
* - an untpd.Tree to which it assigns a type,
Expand Down
3 changes: 2 additions & 1 deletion tests/neg/overloading-specifity.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ object Test extends App {
def foo[T]: Show[T] = new Show[T](2)
}

assert(a.foo[Int].i == 2) // error: no implicit argument of type Test.Context was found for parameter ctx
val b = a.foo[Int] // error: no implicit argument of type context found
assert(b.i == 1) // error
}
15 changes: 15 additions & 0 deletions tests/pos/i10311.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
object Module {
class MyInt(private val x: Int, private val y: Int)
object MyInt {
implicit class Ops(self: MyInt) extends AnyVal {
def x: Int = self.x
}
extension (self: MyInt) def y: Int = self.y
}
}
object test:
import Module._

val a = new MyInt(42, 43)
val b = a.x
val c = a.y
27 changes: 27 additions & 0 deletions tests/run/overloading-specifity-2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Shows that overloading resolution does not test implicits to decide
// applicability. A best alternative is picked first, and then implicits
// are searched for this one.
case class Show[T](val i: Int)
class Show1[T](i: Int) extends Show[T](i)

class Generic
object Generic {
implicit val gen: Generic = new Generic
implicit def showGen[T](implicit gen: Generic): Show[T] = new Show[T](2)
}

object Test extends App {
trait Context
//given ctx as Context

object a {
def foo[T](implicit gen: Generic): Show[T] = new Show[T](1)
def foo[T](implicit gen: Generic, ctx: Context): Show1[T] = new Show1[T](2)
}
object b {
def foo[T](implicit gen: Generic): Show[T] = new Show[T](1)
def foo[T]: Show[T] = new Show[T](2)
}

assert(a.foo[Int].i == 1) // error: no implicit argument of type Test.Context was found for parameter ctx
}