Skip to content

Commit 3261734

Browse files
committed
Alternative fix of #2066.
Now we never match `? { name: T }` with types that have only a private `name` member. This is what scalac does, too.
1 parent c878f81 commit 3261734

File tree

4 files changed

+51
-16
lines changed

4 files changed

+51
-16
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,15 +516,21 @@ trait Implicits { self: Typer =>
516516
|| (from.tpe isRef defn.NullClass)
517517
|| !(ctx.mode is Mode.ImplicitsEnabled)
518518
|| (from.tpe eq NoPrefix)) NoImplicitMatches
519-
else
520-
try inferImplicit(to.stripTypeVar.widenExpr, from, from.pos)
519+
else {
520+
def adjust(to: Type) = to.stripTypeVar.widenExpr match {
521+
case SelectionProto(name, memberProto, compat, true) =>
522+
SelectionProto(name, memberProto, compat, privateOK = false)
523+
case tp => tp
524+
}
525+
try inferImplicit(adjust(to), from, from.pos)
521526
catch {
522527
case ex: AssertionError =>
523528
implicits.println(s"view $from ==> $to")
524529
implicits.println(ctx.typerState.constraint.show)
525530
implicits.println(TypeComparer.explained(implicit ctx => from.tpe <:< to))
526531
throw ex
527532
}
533+
}
528534
}
529535

530536
/** Find an implicit argument for parameter `formal`.

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,12 @@ object ProtoTypes {
9090
*
9191
* [ ].name: proto
9292
*/
93-
abstract case class SelectionProto(val name: Name, val memberProto: Type, val compat: Compatibility)
93+
abstract case class SelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)
9494
extends CachedProxyType with ProtoType with ValueTypeOrProto {
9595

9696
override def isMatchedBy(tp1: Type)(implicit ctx: Context) = {
9797
name == nme.WILDCARD || {
98-
val mbr =
99-
if (tp1.widen.classSymbol.isLinkedWith(ctx.owner.enclosingClass)) tp1.member(name)
100-
else tp1.nonPrivateMember(name)
98+
val mbr = if (privateOK) tp1.member(name) else tp1.nonPrivateMember(name)
10199
def qualifies(m: SingleDenotation) =
102100
memberProto.isRef(defn.UnitClass) ||
103101
compat.normalizedCompatible(m.info, memberProto)
@@ -112,11 +110,11 @@ object ProtoTypes {
112110

113111
def derivedSelectionProto(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context) =
114112
if ((name eq this.name) && (memberProto eq this.memberProto) && (compat eq this.compat)) this
115-
else SelectionProto(name, memberProto, compat)
113+
else SelectionProto(name, memberProto, compat, privateOK)
116114

117115
override def equals(that: Any): Boolean = that match {
118116
case that: SelectionProto =>
119-
(name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat)
117+
(name eq that.name) && (memberProto == that.memberProto) && (compat eq that.compat) && (privateOK == that.privateOK)
120118
case _ =>
121119
false
122120
}
@@ -126,14 +124,18 @@ object ProtoTypes {
126124

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

129-
override def computeHash = addDelta(doHash(name, memberProto), if (compat eq NoViewsAllowed) 1 else 0)
127+
override def computeHash = {
128+
val delta = (if (compat eq NoViewsAllowed) 1 else 0) | (if (privateOK) 2 else 0)
129+
addDelta(doHash(name, memberProto), delta)
130+
}
130131
}
131132

132-
class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility) extends SelectionProto(name, memberProto, compat)
133+
class CachedSelectionProto(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)
134+
extends SelectionProto(name, memberProto, compat, privateOK)
133135

134136
object SelectionProto {
135-
def apply(name: Name, memberProto: Type, compat: Compatibility)(implicit ctx: Context): SelectionProto = {
136-
val selproto = new CachedSelectionProto(name, memberProto, compat)
137+
def apply(name: Name, memberProto: Type, compat: Compatibility, privateOK: Boolean)(implicit ctx: Context): SelectionProto = {
138+
val selproto = new CachedSelectionProto(name, memberProto, compat, privateOK)
137139
if (compat eq NoViewsAllowed) unique(selproto) else selproto
138140
}
139141
}
@@ -145,7 +147,7 @@ object ProtoTypes {
145147
if (name.isConstructorName) WildcardType
146148
else tp match {
147149
case tp: UnapplyFunProto => new UnapplySelectionProto(name)
148-
case tp => SelectionProto(name, IgnoredProto(tp), typer)
150+
case tp => SelectionProto(name, IgnoredProto(tp), typer, privateOK = true)
149151
}
150152

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

161163
/** A prototype for selections in pattern constructors */
162-
class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed)
164+
class UnapplySelectionProto(name: Name) extends SelectionProto(name, WildcardType, NoViewsAllowed, true)
163165

164166
trait ApplyingProto extends ProtoType
165167

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1714,7 +1714,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
17141714
def tryInsertImplicitOnQualifier(tree: Tree, pt: Type)(implicit ctx: Context): Option[Tree] = ctx.traceIndented(i"try insert impl on qualifier $tree $pt") {
17151715
tree match {
17161716
case Select(qual, name) =>
1717-
val qualProto = SelectionProto(name, pt, NoViewsAllowed)
1717+
val qualProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false)
17181718
tryEither { implicit ctx =>
17191719
val qual1 = adaptInterpolated(qual, qualProto, EmptyTree)
17201720
if ((qual eq qual1) || ctx.reporter.hasErrors) None

tests/neg/i2066.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Foo
2+
3+
object Test {
4+
implicit def two(x: Foo): Two = new Two(x)
5+
6+
class Two(x: Foo) {
7+
private def meth: Unit = {}
8+
9+
def test2(foo: Foo): Unit = {
10+
foo.meth // error
11+
}
12+
}
13+
}
14+
15+
16+
object Test2 {
17+
18+
class Two(x: Foo) {
19+
implicit def two(x: Foo): Two = new Two(x)
20+
21+
private def meth: Unit = {}
22+
23+
def test2(foo: Foo): Unit = {
24+
foo.meth // error
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)