Skip to content

Commit dcfd963

Browse files
oderskyDarkDimius
authored andcommitted
Shadowed references
In TypeAssigner#ensureAccible we sometimes pick an inherited public member as the denotation of a NamedType instead of an inaccessible private one. The problem is that both are denotations for the same type, which caused a noDoubleBindings assert failure. We now solve this problem by creating a "shadowed" named type to hold the inherited member. The shadowed named type is distinguished by its name, which reads (inherited)originalName In the future, we should make this more robust by using a general tagging scheme to create shadowed names. Another fix is about import symbols. They are now referenced with NonMemberTermRefs. With this fix, the test suite passes with no double def violations.
1 parent ebd7df5 commit dcfd963

File tree

7 files changed

+36
-17
lines changed

7 files changed

+36
-17
lines changed

src/dotty/tools/dotc/config/Config.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ object Config {
1313
final val checkConstraintsNonCyclic = true
1414

1515
final val flagInstantiationToNothing = false
16-
16+
1717
/** Enable noDoubleDef checking if option "-YnoDoubleDefs" is set.
1818
* The reason to have an option as well as the present global switch is
1919
* that the noDoubleDef checking is done in a hotspot, and we do not
2020
* want to incur the overhead of checking an option each time.
2121
*/
22-
final val checkTermRefs = false
22+
final val checkNoDoubleBindings = true
2323

2424
/** Throw an exception if a deep subtype recursion is detected */
2525
final val flagDeepSubTypeRecursions = true

src/dotty/tools/dotc/core/NameOps.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ object NameOps {
5050
implicit class NameDecorator[N <: Name](val name: N) extends AnyVal {
5151
import nme._
5252

53+
def likeTyped(n: Name): N =
54+
(if (name.isTermName) n.toTermName else n.toTypeName).asInstanceOf[N]
55+
5356
def isConstructorName = name == CONSTRUCTOR || name == IMPLCLASS_CONSTRUCTOR
5457
def isExceptionResultName = name startsWith EXCEPTION_RESULT_PREFIX
5558
def isImplClassName = name endsWith IMPL_CLASS_SUFFIX
@@ -62,6 +65,8 @@ object NameOps {
6265
def isTraitSetterName = isSetterName && (name containsSlice TRAIT_SETTER_SEPARATOR)
6366
def isSingletonName = name endsWith SINGLETON_SUFFIX
6467
def isModuleClassName = name endsWith MODULE_SUFFIX
68+
def isImportName = name startsWith IMPORT
69+
def isInheritedName = name.head == '(' && name.startsWith(nme.INHERITED)
6570

6671
def isModuleVarName(name: Name): Boolean =
6772
name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX
@@ -132,6 +137,10 @@ object NameOps {
132137
if (idx < 0) name else (name drop (idx + separator.length)).asInstanceOf[N]
133138
}
134139

140+
def inheritedName: N = likeTyped(nme.INHERITED ++ name)
141+
142+
def revertInherited: N = likeTyped(name.drop(nme.INHERITED.length))
143+
135144
/** Translate a name into a list of simple TypeNames and TermNames.
136145
* In all segments before the last, type/term is determined by whether
137146
* the following separator char is '.' or '#'. The last segment

src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ object StdNames {
100100
val EXPAND_SEPARATOR: N = "$$"
101101
val IMPL_CLASS_SUFFIX: N = "$class"
102102
val IMPORT: N = "<import>"
103+
val INHERITED: N = "(inherited)" // tag to be used until we have proper name kinds
103104
val INTERPRETER_IMPORT_WRAPPER: N = "$iw"
104105
val INTERPRETER_LINE_PREFIX: N = "line"
105106
val INTERPRETER_VAR_PREFIX: N = "res"

src/dotty/tools/dotc/core/SymDenotations.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,8 @@ object SymDenotations {
684684

685685
/** The symbol, in class `inClass`, that is overridden by this denotation. */
686686
final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol =
687-
matchingSymbol(inClass, owner.thisType)
687+
if ((this is Private) && (owner ne inClass)) NoSymbol
688+
else matchingSymbol(inClass, owner.thisType)
688689

689690
/** All symbols overriden by this denotation. */
690691
final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] =
@@ -731,6 +732,9 @@ object SymDenotations {
731732
override def termRefWithSig(implicit ctx: Context): TermRef =
732733
TermRef.withSig(owner.thisType, name.asTermName, signature, this)
733734

735+
def nonMemberTermRef(implicit ctx: Context): TermRef =
736+
TermRef.withNonMemberSym(owner.thisType, name.asTermName, symbol.asTerm)
737+
734738
/** The variance of this type parameter or type member as an Int, with
735739
* +1 = Covariant, -1 = Contravariant, 0 = Nonvariant, or not a type parameter
736740
*/

src/dotty/tools/dotc/core/Types.scala

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -656,15 +656,6 @@ object Types {
656656
if (res.exists) res else TypeRef(this, name, denot)
657657
}
658658

659-
/** The type <this . name> , reduced if possible, with given denotation if unreduced */
660-
def selectNonMember(name: Name, denot: Denotation)(implicit ctx: Context): Type = name match {
661-
case name: TermName =>
662-
TermRef(this, name, denot)
663-
case name: TypeName =>
664-
val res = lookupRefined(name)
665-
if (res.exists) res else TypeRef(this, name, denot)
666-
}
667-
668659
/** The type <this . name> with given symbol, reduced if possible */
669660
def select(sym: Symbol)(implicit ctx: Context): Type =
670661
if (sym.isTerm) TermRef(this, sym.asTerm)
@@ -1079,7 +1070,7 @@ object Types {
10791070
}
10801071

10811072
private[dotc] final def setDenot(denot: Denotation)(implicit ctx: Context): Unit = {
1082-
if (Config.checkTermRefs)
1073+
if (Config.checkNoDoubleBindings)
10831074
if (ctx.settings.YnoDoubleBindings.value)
10841075
checkSymAssign(denot.symbol)
10851076
lastDenotation = denot
@@ -1095,7 +1086,7 @@ object Types {
10951086
}
10961087

10971088
private[dotc] final def setSym(sym: Symbol)(implicit ctx: Context): Unit = {
1098-
if (Config.checkTermRefs)
1089+
if (Config.checkNoDoubleBindings)
10991090
if (ctx.settings.YnoDoubleBindings.value)
11001091
checkSymAssign(sym)
11011092
uncheckedSetSym(sym)
@@ -1111,7 +1102,9 @@ object Types {
11111102
TermRef.withSig(prefix, name.asTermName, sig)
11121103

11131104
protected def loadDenot(implicit ctx: Context) = {
1114-
val d = prefix.member(name)
1105+
val d =
1106+
if (name.isInheritedName) prefix.nonPrivateMember(name.revertInherited)
1107+
else prefix.member(name)
11151108
if (d.exists || ctx.phaseId == FirstPhaseId)
11161109
d
11171110
else {// name has changed; try load in earlier phase and make current
@@ -1172,6 +1165,11 @@ object Types {
11721165
protected def newLikeThis(prefix: Type)(implicit ctx: Context): NamedType =
11731166
NamedType(prefix, name)
11741167

1168+
/** Create a NamedType of the same kind as this type, but with a new name.
1169+
*/
1170+
final def shadowed(implicit ctx: Context): NamedType =
1171+
NamedType(prefix, name.inheritedName)
1172+
11751173
override def equals(that: Any) = that match {
11761174
case that: NamedType =>
11771175
this.name == that.name &&

src/dotty/tools/dotc/typer/TypeAssigner.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ trait TypeAssigner {
110110
// an inherited non-private member with the same name and signature.
111111
val d2 = pre.nonPrivateMember(name)
112112
if (reallyExists(d2) && firstTry)
113-
test(pre.select(name, d2), false)
113+
test(tpe.shadowed.withDenot(d2), false)
114114
else {
115115
val alts = tpe.denot.alternatives.map(_.symbol).filter(_.exists)
116116
val what = alts match {
@@ -326,7 +326,7 @@ trait TypeAssigner {
326326
tree.withType(sym.typeRef)
327327

328328
def assignType(tree: untpd.Import, sym: Symbol)(implicit ctx: Context) =
329-
tree.withType(sym.termRef)
329+
tree.withType(sym.nonMemberTermRef)
330330

331331
def assignType(tree: untpd.Annotated, annot: Tree, arg: Tree)(implicit ctx: Context) =
332332
tree.withType(AnnotatedType(Annotation(annot), arg.tpe))

tests/pos/unions.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,12 @@ object unions {
2121
println(y.f)
2222
println(y.g(1.0))
2323

24+
class C {
25+
private def foo = 0
26+
class D extends C {
27+
private def foo = 1
28+
def test(cd: C | D, dc: D | C) = (cd.foo, dc.foo)
29+
}
30+
}
2431

2532
}

0 commit comments

Comments
 (0)