Skip to content

Commit 70bf21b

Browse files
committed
Allow multidenotations with same signature
Instead of issuing a merge error, allow multi-denotations with alternatives that have the same signature.
1 parent 587945b commit 70bf21b

File tree

7 files changed

+50
-16
lines changed

7 files changed

+50
-16
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ object Denotations {
407407
}
408408

409409
/** Try to merge single-denotations. */
410-
def mergeSingleDenot(denot1: SingleDenotation, denot2: SingleDenotation): SingleDenotation = {
410+
def mergeSingleDenot(denot1: SingleDenotation, denot2: SingleDenotation): Denotation = {
411411
val info1 = denot1.info
412412
val info2 = denot2.info
413413
val sym1 = denot1.symbol
@@ -465,9 +465,10 @@ object Denotations {
465465
preferSym(sym1, sym2) &&
466466
info1.overrides(info2, sym1.matchNullaryLoosely || sym2.matchNullaryLoosely, checkClassInfo = false)
467467

468-
def handleDoubleDef =
468+
def handleDoubleDef: Denotation =
469469
if (preferSym(sym1, sym2)) denot1
470470
else if (preferSym(sym2, sym1)) denot2
471+
else if sym1.exists then MultiDenotation(denot1, denot2)
471472
else doubleDefError(denot1, denot2, pre)
472473

473474
if (sym2Accessible && prefer(sym2, sym1, info2, info1)) denot2

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

Lines changed: 14 additions & 3 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
@@ -381,10 +382,20 @@ class TreePickler(pickler: TastyPickler) {
381382
pickleType(tp)
382383
}
383384
case _ =>
384-
writeByte(if (name.isTypeName) SELECTtpt else SELECT)
385385
val sig = tree.tpe.signature
386-
pickleNameAndSig(name, sig)
387-
pickleTree(qual)
386+
qual.tpe.nonPrivateMember(name).atSignature(sig) match
387+
case d: MultiDenotation =>
388+
assert(tree.symbol.isTerm)
389+
writeByte(SELECTin)
390+
withLength {
391+
pickleNameAndSig(name, tree.symbol.signature)
392+
pickleTree(qual)
393+
pickleType(tree.symbol.owner.typeRef)
394+
}
395+
case _ =>
396+
writeByte(if (name.isTypeName) SELECTtpt else SELECT)
397+
pickleNameAndSig(name, sig)
398+
pickleTree(qual)
388399
}
389400
case Apply(fun, args) =>
390401
if (fun.symbol eq defn.throwMethod) {

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

Lines changed: 17 additions & 4 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._
@@ -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,16 @@ 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+
val prefix = qual.tpe.widenIfUnstable
1176+
sname match
1177+
case SignedName(name, sig) =>
1178+
makeSelect(qual, name, owner.decl(name).atSignature(sig).asSeenFrom(prefix))
1179+
case name =>
1180+
makeSelect(qual, name, owner.decl(name).asSeenFrom(prefix))
11681181
case REPEATED =>
11691182
val elemtpt = readTpt()
11701183
SeqLiteral(until(end)(readTerm()), elemtpt)

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,11 +1350,11 @@ trait Applications extends Compatibility {
13501350
* Module classes also inherit the relationship from their companions.
13511351
*/
13521352
def compareOwner(sym1: Symbol, sym2: Symbol)(using Context): Int =
1353-
if (sym1 == sym2) 0
1354-
else if (sym1 isSubClass sym2) 1
1355-
else if (sym2 isSubClass sym1) -1
1356-
else if (sym2.is(Module)) compareOwner(sym1, sym2.companionClass)
1357-
else if (sym1.is(Module)) compareOwner(sym1.companionClass, sym2)
1353+
if sym1 == sym2 then 0
1354+
else if sym1.isSubClass(sym2) then 1
1355+
else if sym2.isSubClass(sym1) then -1
1356+
else if sym1.is(Module) && sym2.is(Module) then
1357+
compareOwner(sym1.companionClass, sym2.companionClass)
13581358
else 0
13591359

13601360
/** Compare to alternatives of an overloaded call or an implicit search.

tasty/src/dotty/tools/tasty/TastyFormat.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ Standard-Section: "ASTs" TopLevelStat*
7575
Term = Path -- Paths represent both types and terms
7676
IDENT NameRef Type -- Used when term ident’s type is not a TermRef
7777
SELECT possiblySigned_NameRef qual_Term -- qual.name
78+
SELECTin Length possiblySigned_NameRef qual_Term owner_Type -- qual.name, referring to a symbol declared in owner that has the given signature
7879
QUALTHIS typeIdent_Tree -- id.this, different from THIS in that it contains a qualifier ident with position.
7980
NEW clsType_Term -- new cls
8081
THROW throwableExpr_Term -- throw throwableExpr
@@ -452,6 +453,7 @@ object TastyFormat {
452453
final val ANNOTATION = 173
453454
final val TERMREFin = 174
454455
final val TYPEREFin = 175
456+
final val SELECTin = 176
455457

456458
final val METHODtype = 180
457459

@@ -646,6 +648,7 @@ object TastyFormat {
646648
case SUPERtype => "SUPERtype"
647649
case TERMREFin => "TERMREFin"
648650
case TYPEREFin => "TYPEREFin"
651+
case SELECTin => "SELECTin"
649652

650653
case REFINEDtype => "REFINEDtype"
651654
case REFINEDtpt => "REFINEDtpt"
@@ -675,7 +678,7 @@ object TastyFormat {
675678
*/
676679
def numRefs(tag: Int): Int = tag match {
677680
case VALDEF | DEFDEF | TYPEDEF | TYPEPARAM | PARAM | NAMEDARG | RETURN | BIND |
678-
SELFDEF | REFINEDtype | TERMREFin | TYPEREFin | HOLE => 1
681+
SELFDEF | REFINEDtype | TERMREFin | TYPEREFin | SELECTin | HOLE => 1
679682
case RENAMED | PARAMtype => 2
680683
case POLYtype | TYPELAMBDAtype | METHODtype => -1
681684
case _ => 0

tests/neg/i1240b.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ abstract class A[X] extends T[X] {
99
trait U[X] extends T[X] {
1010
abstract override def foo(x: X): X = super.foo(x)
1111
}
12-
object Test extends A[String] with U[String] // error: accidental override // error: merge error
12+
object Test extends A[String] with U[String] // error: accidental override

tests/pos/i9050.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
object Foo {
3+
val foo = scala.collection.mutable.ArrayBuffer.empty[Seq[Double]]
4+
val bar = Seq.empty[Double]
5+
foo.append(bar)
6+
}

0 commit comments

Comments
 (0)