Skip to content

Commit 2fbefb0

Browse files
authored
Merge pull request #9063 from dotty-staging/fix-#9050
Fix #9050: Allow multidenotations with same signature
2 parents cc8d6c3 + 19e658c commit 2fbefb0

File tree

20 files changed

+267
-395
lines changed

20 files changed

+267
-395
lines changed

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,8 @@ class CommunityBuildTest:
384384
@Test def scodecBits = projects.scodecBits.run()
385385
@Test def scodec = projects.scodec.run()
386386
@Test def scalaParserCombinators = projects.scalaParserCombinators.run()
387-
@Test def dottyCpsAsync = projects.dottyCpsAsync.run()
387+
// blocked on #9074
388+
//@Test def dottyCpsAsync = projects.dottyCpsAsync.run()
388389
@Test def scalaz = projects.scalaz.run()
389390
@Test def endpoints = projects.endpoints.run()
390391
end CommunityBuildTest

compiler/src/dotty/tools/dotc/core/Denotations.scala

Lines changed: 130 additions & 297 deletions
Large diffs are not rendered by default.

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -922,8 +922,8 @@ object SymDenotations {
922922
else true
923923
}
924924

925-
if (pre eq NoPrefix) true
926-
else if (isAbsent()) false
925+
if pre eq NoPrefix then true
926+
else if isAbsent() then false
927927
else {
928928
val boundary = accessBoundary(owner)
929929

@@ -2133,7 +2133,7 @@ object SymDenotations {
21332133
var names = Set[Name]()
21342134
def maybeAdd(name: Name) = if (keepOnly(thisType, name)) names += name
21352135
try {
2136-
for (p <- classParents)
2136+
for (p <- classParents if p.classSymbol.isClass)
21372137
for (name <- p.classSymbol.asClass.memberNames(keepOnly))
21382138
maybeAdd(name)
21392139
val ownSyms =

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,16 +2047,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
20472047
* instantiated TypeVars are dereferenced and annotations are stripped.
20482048
* Finally, refined types with the same refined name are
20492049
* opportunistically merged.
2050-
*
2051-
* Sometimes, the conjunction of two types cannot be formed because
2052-
* the types are in conflict of each other. In particular:
2053-
*
2054-
* 1. Two different class types are conflicting.
2055-
* 2. A class type conflicts with a type bounds that does not include the class reference.
2056-
* 3. Two method or poly types with different (type) parameters but the same
2057-
* signature are conflicting
2058-
*
2059-
* In these cases, a MergeError is thrown.
20602050
*/
20612051
final def andType(tp1: Type, tp2: Type, isErased: Boolean = ctx.erasedTypes): Type =
20622052
andTypeGen(tp1, tp2, AndType(_, _), isErased = isErased)
@@ -2070,10 +2060,6 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
20702060
* ExprType, LambdaType). Also, when forming an `|`,
20712061
* instantiated TypeVars are dereferenced and annotations are stripped.
20722062
*
2073-
* Sometimes, the disjunction of two types cannot be formed because
2074-
* the types are in conflict of each other. (@see `andType` for an enumeration
2075-
* of these cases). In cases of conflict a `MergeError` is raised.
2076-
*
20772063
* @param isErased Apply erasure semantics. If erased is true, instead of creating
20782064
* an OrType, the lub will be computed using TypeCreator#erasedLub.
20792065
*/
@@ -2139,13 +2125,11 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
21392125
// gives =:= types), but it keeps the type smaller.
21402126
tp2 match {
21412127
case tp2: RefinedType if tp1.refinedName == tp2.refinedName =>
2142-
try {
2143-
val jointInfo = Denotations.infoMeet(tp1.refinedInfo, tp2.refinedInfo, NoSymbol, NoSymbol, safeIntersection = false)
2128+
val jointInfo = Denotations.infoMeet(tp1.refinedInfo, tp2.refinedInfo, safeIntersection = false)
2129+
if jointInfo.exists then
21442130
tp1.derivedRefinedType(tp1.parent & tp2.parent, tp1.refinedName, jointInfo)
2145-
}
2146-
catch {
2147-
case ex: MergeError => NoType
2148-
}
2131+
else
2132+
NoType
21492133
case _ =>
21502134
NoType
21512135
}

compiler/src/dotty/tools/dotc/core/TypeErrors.scala

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -163,32 +163,3 @@ object CyclicReference {
163163
}
164164
}
165165

166-
class MergeError(val sym1: Symbol, val sym2: Symbol, val tp1: Type, val tp2: Type, prefix: Type) extends TypeError {
167-
168-
private def showSymbol(sym: Symbol)(implicit ctx: Context): String =
169-
if (sym.exists) sym.showLocated else "[unknown]"
170-
171-
private def showType(tp: Type)(implicit ctx: Context) = tp match {
172-
case ClassInfo(_, cls, _, _, _) => cls.showLocated
173-
case _ => tp.show
174-
}
175-
176-
protected def addendum(implicit ctx: Context): String =
177-
if (prefix `eq` NoPrefix) ""
178-
else {
179-
val owner = prefix match {
180-
case prefix: ThisType => prefix.cls.show
181-
case prefix: TermRef => prefix.symbol.show
182-
case _ => i"type $prefix"
183-
}
184-
s"\nas members of $owner"
185-
}
186-
187-
override def produceMessage(implicit ctx: Context): Message = {
188-
if (ctx.debug) printStackTrace()
189-
i"""cannot merge
190-
| ${showSymbol(sym1)} of type ${showType(tp1)} and
191-
| ${showSymbol(sym2)} of type ${showType(tp2)}$addendum
192-
"""
193-
}
194-
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,7 +675,7 @@ object Types {
675675
pdenot.asSingleDenotation.derivedSingleDenotation(pdenot.symbol, jointInfo)
676676
}
677677
else
678-
val joint = pdenot & (
678+
val joint = pdenot.meet(
679679
new JointRefDenotation(NoSymbol, rinfo, Period.allInRun(ctx.runId), pre),
680680
pre,
681681
safeIntersection = ctx.base.pendingMemberSearches.contains(name))
@@ -726,7 +726,7 @@ object Types {
726726
}
727727

728728
def goAnd(l: Type, r: Type) =
729-
go(l) & (go(r), pre, safeIntersection = ctx.base.pendingMemberSearches.contains(name))
729+
go(l).meet(go(r), pre, safeIntersection = ctx.base.pendingMemberSearches.contains(name))
730730

731731
def goOr(tp: OrType) = tp match {
732732
case OrUncheckedNull(tp1) =>

compiler/src/dotty/tools/dotc/core/tasty/TastyPrinter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class TastyPrinter(bytes: Array[Byte])(implicit ctx: Context) {
8282
printName(); printName()
8383
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | BIND =>
8484
printName(); printTrees()
85-
case REFINEDtype | TERMREFin | TYPEREFin =>
85+
case REFINEDtype | TERMREFin | TYPEREFin | SELECTin =>
8686
printName(); printTree(); printTrees()
8787
case RETURN | HOLE =>
8888
printNat(); printTrees()

compiler/src/dotty/tools/dotc/core/tasty/TreePickler.scala

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import dotty.tools.tasty.TastyBuffer._
99
import ast.Trees._
1010
import ast.{untpd, tpd}
1111
import Contexts._, Symbols._, Types._, Names._, Constants._, Decorators._, Annotations._, Flags._
12+
import Denotations.MultiDenotation
1213
import typer.Inliner
1314
import NameKinds._
1415
import StdNames.nme
@@ -173,22 +174,20 @@ class TreePickler(pickler: TastyPickler) {
173174
case tpe: NamedType =>
174175
val sym = tpe.symbol
175176
def pickleExternalRef(sym: Symbol) = {
176-
def pickleCore() = {
177-
pickleNameAndSig(sym.name, tpe.signature)
178-
pickleType(tpe.prefix)
179-
}
180177
val isShadowedRef =
181178
sym.isClass && tpe.prefix.member(sym.name).symbol != sym
182179
if (sym.is(Flags.Private) || isShadowedRef) {
183180
writeByte(if (tpe.isType) TYPEREFin else TERMREFin)
184181
withLength {
185-
pickleCore()
182+
pickleNameAndSig(sym.name, tpe.symbol.signature)
183+
pickleType(tpe.prefix)
186184
pickleType(sym.owner.typeRef)
187185
}
188186
}
189187
else {
190188
writeByte(if (tpe.isType) TYPEREF else TERMREF)
191-
pickleCore()
189+
pickleNameAndSig(sym.name, tpe.signature)
190+
pickleType(tpe.prefix)
192191
}
193192
}
194193
if (sym.is(Flags.Package)) {
@@ -381,10 +380,23 @@ class TreePickler(pickler: TastyPickler) {
381380
pickleType(tp)
382381
}
383382
case _ =>
384-
writeByte(if (name.isTypeName) SELECTtpt else SELECT)
385383
val sig = tree.tpe.signature
386-
pickleNameAndSig(name, sig)
387-
pickleTree(qual)
384+
val isAmbiguous =
385+
sig != Signature.NotAMethod
386+
&& qual.tpe.nonPrivateMember(name).match
387+
case d: MultiDenotation => d.atSignature(sig).isInstanceOf[MultiDenotation]
388+
case _ => false
389+
if isAmbiguous then
390+
writeByte(SELECTin)
391+
withLength {
392+
pickleNameAndSig(name, tree.symbol.signature)
393+
pickleTree(qual)
394+
pickleType(tree.symbol.owner.typeRef)
395+
}
396+
else
397+
writeByte(if (name.isTypeName) SELECTtpt else SELECT)
398+
pickleNameAndSig(name, sig)
399+
pickleTree(qual)
388400
}
389401
case Apply(fun, args) =>
390402
if (fun.symbol eq defn.throwMethod) {

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Symbols._
99
import Types._
1010
import Scopes._
1111
import SymDenotations._
12+
import Denotations._
1213
import Names._
1314
import NameOps._
1415
import StdNames._
@@ -330,12 +331,12 @@ class TreeUnpickler(reader: TastyReader,
330331
case TERMREFin =>
331332
var sname = readName()
332333
val prefix = readType()
333-
val space = readType()
334+
val owner = readType()
334335
sname match {
335336
case SignedName(name, sig) =>
336-
TermRef(prefix, name, space.decl(name).asSeenFrom(prefix).atSignature(sig))
337+
TermRef(prefix, name, owner.decl(name).atSignature(sig).asSeenFrom(prefix))
337338
case name =>
338-
TermRef(prefix, name, space.decl(name).asSeenFrom(prefix))
339+
TermRef(prefix, name, owner.decl(name).asSeenFrom(prefix))
339340
}
340341
case TYPEREFin =>
341342
val name = readName().toTypeName
@@ -1040,10 +1041,8 @@ class TreeUnpickler(reader: TastyReader,
10401041
}
10411042
}
10421043

1043-
def completeSelect(name: Name, sig: Signature): Select = {
1044-
val qual = readTerm()(ctx)
1044+
def makeSelect(qual: Tree, name: Name, denot: Denotation): Select =
10451045
var qualType = qual.tpe.widenIfUnstable
1046-
val denot = accessibleDenot(qualType, name, sig)
10471046
val owner = denot.symbol.maybeOwner
10481047
if (owner.isPackageObject && qualType.termSymbol.is(Package))
10491048
qualType = qualType.select(owner.sourceModule)
@@ -1052,7 +1051,11 @@ class TreeUnpickler(reader: TastyReader,
10521051
case name: TermName => TermRef(qualType, name, denot)
10531052
}
10541053
ConstFold(untpd.Select(qual, name).withType(tpe))
1055-
}
1054+
1055+
def completeSelect(name: Name, sig: Signature): Select =
1056+
val qual = readTerm()(ctx)
1057+
val denot = accessibleDenot(qual.tpe.widenIfUnstable, name, sig)
1058+
makeSelect(qual, name, denot)
10561059

10571060
def readQualId(): (untpd.Ident, TypeRef) =
10581061
val qual = readTerm().asInstanceOf[untpd.Ident]
@@ -1165,6 +1168,18 @@ class TreeUnpickler(reader: TastyReader,
11651168
case SELECTouter =>
11661169
val levels = readNat()
11671170
readTerm().outerSelect(levels, SkolemType(readType()))
1171+
case SELECTin =>
1172+
var sname = readName()
1173+
val qual = readTerm()
1174+
val owner = readType()
1175+
def select(name: Name, denot: Denotation) =
1176+
val prefix = ctx.typeAssigner.maybeSkolemizePrefix(qual.tpe.widenIfUnstable, name)
1177+
makeSelect(qual, name, denot.asSeenFrom(prefix))
1178+
sname match
1179+
case SignedName(name, sig) =>
1180+
select(name, owner.decl(name).atSignature(sig))
1181+
case name =>
1182+
select(name, owner.decl(name))
11681183
case REPEATED =>
11691184
val elemtpt = readTpt()
11701185
SeqLiteral(until(end)(readTerm()), elemtpt)

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

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -425,22 +425,10 @@ object RefChecks {
425425
}*/
426426
}
427427

428-
try {
429-
val opc = new OverridingPairs.Cursor(clazz)
430-
while (opc.hasNext) {
431-
checkOverride(opc.overriding, opc.overridden)
432-
opc.next()
433-
}
434-
}
435-
catch {
436-
case ex: MergeError =>
437-
val addendum = ex.tp1 match {
438-
case tp1: ClassInfo =>
439-
"\n(Note that having same-named member classes in types of a mixin composition is no longer allowed)"
440-
case _ => ""
441-
}
442-
ctx.error(ex.getMessage + addendum, clazz.sourcePos)
443-
}
428+
val opc = new OverridingPairs.Cursor(clazz)
429+
while opc.hasNext do
430+
checkOverride(opc.overriding, opc.overridden)
431+
opc.next()
444432
printMixinOverrideErrors()
445433

446434
// Verifying a concrete class has nothing unimplemented.

0 commit comments

Comments
 (0)