Skip to content

Fix #2066: Don't qualify private members in SelectionProto's... #2080

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
Mar 12, 2017
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
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,10 @@ object SymDenotations {
else
companionNamed(name)(ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next)

/** Is this symbol the same or a linked class of `sym`? */
final def isLinkedWith(sym: Symbol)(implicit ctx: Context): Boolean =
(symbol eq sym) || (linkedClass eq sym)

/** If this is a class, the module class of its companion object.
* If this is a module class, its companion class.
* NoSymbol otherwise.
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/TypeErasure.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,13 +215,13 @@ object TypeErasure {
}

/** The erased least upper bound is computed as follows
* - if both argument are arrays of objects, an array of the lub of the element types
* - if both argument are arrays of objects, an array of the erased lub of the element types
* - if both arguments are arrays of same primitives, an array of this primitive
* - if one argument is array of primitives and the other is array of objects, Object
* - if one argument is an array, Object
* - otherwise a common superclass or trait S of the argument classes, with the
* following two properties:
* S is minimal: no other common superclass or trait derives from S]
* S is minimal: no other common superclass or trait derives from S
* S is last : in the linearization of the first argument type `tp1`
* there are no minimal common superclasses or traits that
* come after S.
Expand Down
10 changes: 8 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -516,15 +516,21 @@ trait Implicits { self: Typer =>
|| (from.tpe isRef defn.NullClass)
|| !(ctx.mode is Mode.ImplicitsEnabled)
|| (from.tpe eq NoPrefix)) NoImplicitMatches
else
try inferImplicit(to.stripTypeVar.widenExpr, from, from.pos)
else {
def adjust(to: Type) = to.stripTypeVar.widenExpr match {
case SelectionProto(name, memberProto, compat, true) =>
SelectionProto(name, memberProto, compat, privateOK = false)
case tp => tp
}
try inferImplicit(adjust(to), from, from.pos)
catch {
case ex: AssertionError =>
implicits.println(s"view $from ==> $to")
implicits.println(ctx.typerState.constraint.show)
implicits.println(TypeComparer.explained(implicit ctx => from.tpe <:< to))
throw ex
}
}
}

/** Find an implicit argument for parameter `formal`.
Expand Down
26 changes: 15 additions & 11 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ object ProtoTypes {
*
* [ ].name: proto
*/
abstract case class SelectionProto(val name: Name, val memberProto: Type, val compat: Compatibility)
abstract case class SelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)
extends CachedProxyType with ProtoType with ValueTypeOrProto {

override def isMatchedBy(tp1: Type)(implicit ctx: Context) = {
name == nme.WILDCARD || {
val mbr = tp1.member(name)
val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name)
def qualifies(m: SingleDenotation) =
memberProto.isRef(defn.UnitClass) ||
compat.normalizedCompatible(m.info, memberProto)
Expand All @@ -110,11 +110,11 @@ object ProtoTypes {

def derivedSelectionProto(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context) =
if ((name eq this.name) && (memberProto eq this.memberProto) && (compat eq this.compat)) this
else SelectionProto(name, memberProto, compat)
else SelectionProto(name, memberProto, compat, privateOK)

override def equals(that: Any): Boolean = that match {
case that: SelectionProto =>
(name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat)
(name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat) && (privateOK == that.privateOK)
case _ =>
false
}
Expand All @@ -124,14 +124,18 @@ object ProtoTypes {

override def deepenProto(implicit ctx: Context) = derivedSelectionProto(name, memberProto.deepenProto, compat)

override def computeHash = addDelta(doHash(name, memberProto), if (compat eq NoViewsAllowed) 1 else 0)
override def computeHash = {
val delta = (if (compat eq NoViewsAllowed) 1 else 0) | (if (privateOK) 2 else 0)
addDelta(doHash(name, memberProto), delta)
}
}

class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility) extends SelectionProto(name, memberProto, compat)
class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)
extends SelectionProto(name, memberProto, compat, privateOK)

object SelectionProto {
def apply(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context): SelectionProto = {
val selproto = new CachedSelectionProto(name, memberProto, compat)
def apply(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)(implicit ctx: Context): SelectionProto = {
val selproto = new CachedSelectionProto(name, memberProto, compat, privateOK)
if (compat eq NoViewsAllowed) unique(selproto) else selproto
}
}
Expand All @@ -143,7 +147,7 @@ object ProtoTypes {
if (name.isConstructorName) WildcardType
else tp match {
case tp: UnapplyFunProto => new UnapplySelectionProto(name)
case tp => SelectionProto(name, IgnoredProto(tp), typer)
case tp => SelectionProto(name, IgnoredProto(tp), typer, privateOK = true)
}

/** A prototype for expressions [] that are in some unspecified selection operation
Expand All @@ -154,10 +158,10 @@ object ProtoTypes {
* operation is further selection. In this case, the expression need not be a value.
* @see checkValue
*/
@sharable object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType, NoViewsAllowed)
@sharable object AnySelectionProto extends SelectionProto(nme.WILDCARD, WildcardType, NoViewsAllowed, true)

/** A prototype for selections in pattern constructors */
class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed)
class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed, true)

trait ApplyingProto extends ProtoType

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1714,7 +1714,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def tryInsertImplicitOnQualifier(tree: Tree, pt: Type)(implicit ctx: Context): Option[Tree] = ctx.traceIndented(i"try insert impl on qualifier $tree $pt") {
tree match {
case Select(qual, name) =>
val qualProto = SelectionProto(name, pt, NoViewsAllowed)
val qualProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
tryEither { implicit ctx =>
val qual1 = adaptInterpolated(qual, qualProto, EmptyTree)
if ((qual eq qual1) || ctx.reporter.hasErrors) None
Expand Down
27 changes: 27 additions & 0 deletions tests/neg/i2066.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Foo

object Test {
implicit def two(x: Foo): Two = new Two(x)

class Two(x: Foo) {
private def meth: Unit = {}

def test2(foo: Foo): Unit = {
foo.meth // error
}
}
}


object Test2 {

class Two(x: Foo) {
implicit def two(x: Foo): Two = new Two(x)

private def meth: Unit = {}

def test2(foo: Foo): Unit = {
foo.meth // error
}
}
}
15 changes: 15 additions & 0 deletions tests/pos/i2066.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class Foo

object Test {
implicit class One(x: Foo) {
def meth: Unit = {}
}

implicit class Two(x: Foo) {
private def meth: Unit = {}
}

def test(foo: Foo): Unit = {
foo.meth
}
}