Skip to content

Commit 56f9ab8

Browse files
committed
Merge pull request #846 from dotty-staging/fix-#827
Fix #827
2 parents b927f66 + a62ec3c commit 56f9ab8

File tree

5 files changed

+43
-44
lines changed

5 files changed

+43
-44
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,17 @@ object Denotations {
308308
else if (!sym2.exists) sym1
309309
else if (preferSym(sym2, sym1)) sym2
310310
else sym1
311-
new JointRefDenotation(sym, info1 & info2, denot1.validFor & denot2.validFor)
311+
val jointInfo =
312+
try info1 & info2
313+
catch {
314+
case ex: MergeError =>
315+
if (pre.widen.classSymbol.is(Scala2x))
316+
info1 // follow Scala2 linearization -
317+
// compare with way merge is performed in SymDenotation#computeMembersNamed
318+
else
319+
throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}")
320+
}
321+
new JointRefDenotation(sym, jointInfo, denot1.validFor & denot2.validFor)
312322
}
313323
}
314324
} else NoDenotation

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

Lines changed: 16 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -874,11 +874,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
874874
* 3. Two method or poly types with different (type) parameters but the same
875875
* signature are conflicting
876876
*
877-
* In these cases, one of the types is picked (@see andConflict).
878-
* This is arbitrary, but I believe it is analogous to forming
879-
* infeasible TypeBounds (where low bound is not a subtype of high bound).
880-
* Such TypeBounds can also be arbitrarily instantiated. In both cases we need to
881-
* make sure that such types do not actually arise in source programs.
877+
* In these cases, a MergeError is thrown.
882878
*/
883879
final def andType(tp1: Type, tp2: Type, erased: Boolean = ctx.erasedTypes) = ctx.traceIndented(s"glb(${tp1.show}, ${tp2.show})", subtyping, show = true) {
884880
val t1 = distributeAnd(tp1, tp2)
@@ -943,13 +939,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
943939
tp2 match {
944940
case tp2: TypeBounds => tp1 & tp2
945941
case tp2: ClassInfo if tp1 contains tp2.typeRef => tp2
946-
case _ => andConflict(tp1, tp2)
942+
case _ => mergeConflict(tp1, tp2)
947943
}
948944
case tp1: ClassInfo =>
949945
tp2 match {
950946
case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix & tp2.prefix)
951947
case tp2: TypeBounds if tp2 contains tp1.typeRef => tp1
952-
case _ => andConflict(tp1, tp2)
948+
case _ => mergeConflict(tp1, tp2)
953949
}
954950
case tp1 @ MethodType(names1, formals1) =>
955951
tp2 match {
@@ -960,7 +956,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
960956
mergeNames(names1, names2, nme.syntheticParamName),
961957
formals1, tp1.resultType & tp2.resultType.subst(tp2, tp1))
962958
case _ =>
963-
andConflict(tp1, tp2)
959+
mergeConflict(tp1, tp2)
964960
}
965961
case tp1: PolyType =>
966962
tp2 match {
@@ -969,7 +965,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
969965
mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
970966
tp1.paramBounds, tp1.resultType & tp2.resultType.subst(tp2, tp1))
971967
case _ =>
972-
andConflict(tp1, tp2)
968+
mergeConflict(tp1, tp2)
973969
}
974970
case ExprType(rt1) =>
975971
tp2 match {
@@ -1002,13 +998,13 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
1002998
tp2 match {
1003999
case tp2: TypeBounds => tp1 | tp2
10041000
case tp2: ClassInfo if tp1 contains tp2.typeRef => tp1
1005-
case _ => orConflict(tp1, tp2)
1001+
case _ => mergeConflict(tp1, tp2)
10061002
}
10071003
case tp1: ClassInfo =>
10081004
tp2 match {
10091005
case tp2: ClassInfo if tp1.cls eq tp2.cls => tp1.derivedClassInfo(tp1.prefix | tp2.prefix)
10101006
case tp2: TypeBounds if tp2 contains tp1.typeRef => tp2
1011-
case _ => orConflict(tp1, tp2)
1007+
case _ => mergeConflict(tp1, tp2)
10121008
}
10131009
case tp1 @ MethodType(names1, formals1) =>
10141010
tp2 match {
@@ -1019,7 +1015,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
10191015
mergeNames(names1, names2, nme.syntheticParamName),
10201016
formals1, tp1.resultType | tp2.resultType.subst(tp2, tp1))
10211017
case _ =>
1022-
orConflict(tp1, tp2)
1018+
mergeConflict(tp1, tp2)
10231019
}
10241020
case tp1: PolyType =>
10251021
tp2 match {
@@ -1028,7 +1024,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
10281024
mergeNames(tp1.paramNames, tp2.paramNames, tpnme.syntheticTypeParamName),
10291025
tp1.paramBounds, tp1.resultType | tp2.resultType.subst(tp2, tp1))
10301026
case _ =>
1031-
orConflict(tp1, tp2)
1027+
mergeConflict(tp1, tp2)
10321028
}
10331029
case ExprType(rt1) =>
10341030
ExprType(rt1 | tp2.widenExpr)
@@ -1040,31 +1036,16 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
10401036
NoType
10411037
}
10421038

1043-
/** Handle `&`-conflict. If `tp2` is strictly better than `tp1` as determined
1044-
* by @see `isAsGood`, pick `tp2` as the winner otherwise pick `tp1`.
1045-
* Issue a warning and return the winner.
1046-
*/
1047-
private def andConflict(tp1: Type, tp2: Type): Type = {
1048-
// println(disambiguated(implicit ctx => TypeComparer.explained(_.typeComparer.isSubType(tp1, tp2)))) !!!DEBUG
1049-
val winner = if (isAsGood(tp2, tp1) && !isAsGood(tp1, tp2)) tp2 else tp1
1050-
def msg = disambiguated { implicit ctx =>
1051-
s"${mergeErrorMsg(tp1, tp2)} as members of one type; keeping only ${showType(winner)}"
1039+
/** Handle merge conflict by throwing a `MergeError` exception */
1040+
private def mergeConflict(tp1: Type, tp2: Type): Type = {
1041+
def showType(tp: Type) = tp match {
1042+
case ClassInfo(_, cls, _, _, _) => cls.showLocated
1043+
case bounds: TypeBounds => i"type bounds $bounds"
1044+
case _ => tp.show
10521045
}
1053-
/* !!! DEBUG
1054-
println("right not a subtype of left because:")
1055-
println(TypeComparer.explained { implicit ctx => tp2 <:< tp1})
1056-
println("left not a subtype of right because:")
1057-
println(TypeComparer.explained { implicit ctx => tp1 <:< tp2})
1058-
assert(false, s"andConflict ${tp1.show} and ${tp2.show}")
1059-
*/
1060-
ctx.warning(msg, ctx.tree.pos)
1061-
winner
1046+
throw new MergeError(s"cannot merge ${showType(tp1)} with ${showType(tp2)}")
10621047
}
10631048

1064-
/** Handle `|`-conflict by raising a `MergeError` exception */
1065-
private def orConflict(tp1: Type, tp2: Type): Type =
1066-
throw new MergeError(mergeErrorMsg(tp1, tp2))
1067-
10681049
/** Merge two lists of names. If names in corresponding positions match, keep them,
10691050
* otherwise generate new synthetic names.
10701051
*/
@@ -1080,10 +1061,6 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
10801061
case _ => tp.show
10811062
}
10821063

1083-
/** The error message kernel for a merge conflict */
1084-
private def mergeErrorMsg(tp1: Type, tp2: Type)(implicit ctx: Context) =
1085-
s"cannot merge ${showType(tp1)} with ${showType(tp2)}"
1086-
10871064
/** A comparison function to pick a winner in case of a merge conflict */
10881065
private def isAsGood(tp1: Type, tp2: Type): Boolean = tp1 match {
10891066
case tp1: ClassInfo =>

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,10 +492,8 @@ object Types {
492492

493493
try go(this)
494494
catch {
495-
case ex: MergeError =>
496-
throw new MergeError(s"${ex.getMessage} as members of type ${pre.show}")
497495
case ex: Throwable =>
498-
ctx.println(i"findMember exception for $this member $name")
496+
core.println(i"findMember exception for $this member $name")
499497
throw ex // DEBUG
500498
}
501499
finally {

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,14 @@ class Namer { typer: Typer =>
575575
def checkedParentType(parent: untpd.Tree): Type = {
576576
val ptype = parentType(parent)(ctx.superCallContext)
577577
if (cls.isRefinementClass) ptype
578-
else checkClassTypeWithStablePrefix(ptype, parent.pos, traitReq = parent ne parents.head)
578+
else {
579+
val pt = checkClassTypeWithStablePrefix(ptype, parent.pos, traitReq = parent ne parents.head)
580+
if (pt.derivesFrom(cls)) {
581+
ctx.error(i"cyclic inheritance: $cls extends itself", parent.pos)
582+
defn.ObjectClass.typeRef
583+
}
584+
else pt
585+
}
579586
}
580587

581588
val selfInfo =

tests/neg/i827.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait A { trait Inner }
2+
trait B { self: A =>
3+
trait Inner extends self.Inner
4+
}
5+
6+
7+
class C extends C

0 commit comments

Comments
 (0)