Skip to content

Commit b4de0d8

Browse files
committed
Adapt superclass inference to new scheme
It could now be that a superclass type is an AndType of two class types. This case needs to be rejected and healed. Test case is templateParents.scala, which crashed without the fix in this commit.
1 parent 8a52da5 commit b4de0d8

File tree

4 files changed

+17
-17
lines changed

4 files changed

+17
-17
lines changed

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -580,12 +580,15 @@ trait Checking {
580580
case _ =>
581581
}
582582

583-
/** Check that any top-level type arguments in this type are feasible, i.e. that
584-
* their lower bound conforms to their upper bound. If a type argument is
585-
* infeasible, issue and error and continue with upper bound.
583+
/** Check that `tp` is a class type and that any top-level type arguments in this type
584+
* are feasible, i.e. that their lower bound conforms to their upper bound. If a type
585+
* argument is infeasible, issue and error and continue with upper bound.
586586
*/
587-
def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type =
587+
def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type =
588588
tp match {
589+
case tp @ AndType(tp1, tp2) =>
590+
ctx.error(s"conflicting type arguments$where", pos)
591+
tp1
589592
case tp @ AppliedType(tycon, args) =>
590593
def checkArg(arg: Type) = arg match {
591594
case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
@@ -595,7 +598,7 @@ trait Checking {
595598
}
596599
tp.derivedAppliedType(tycon, args.mapConserve(checkArg))
597600
case tp: RefinedType => // @!!!
598-
tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
601+
tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasibleParent(tp.refinedInfo, pos, where))
599602
case tp: RecType => // @!!!
600603
tp.rebind(tp.parent)
601604
case tp @ TypeBounds(lo, hi) if !(lo <:< hi) => // @!!!
@@ -745,7 +748,7 @@ trait NoChecking extends Checking {
745748
override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = ()
746749
override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp
747750
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
748-
override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
751+
override def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
749752
override def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context) = ()
750753
override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = ()
751754
override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = ()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ class Namer { typer: Typer =>
913913
indexAndAnnotate(rest)(inClassContext(selfInfo))
914914
symbolOfTree(constr).ensureCompleted()
915915

916-
val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)))
916+
val parentTypes = ensureFirstIsClass(parents.map(checkedParentType(_)), cls.pos)
917917
val parentRefs = ctx.normalizeToClassRefs(parentTypes, cls, decls)
918918
typr.println(i"completing $denot, parents = $parents%, %, parentTypes = $parentTypes%, %, parentRefs = $parentRefs%, %")
919919

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

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13941394

13951395
completeAnnotations(cdef, cls)
13961396
val constr1 = typed(constr).asInstanceOf[DefDef]
1397-
val parentsWithClass = ensureFirstIsClass(parents mapconserve typedParent, cdef.namePos)
1397+
val parentsWithClass = ensureFirstTreeIsClass(parents mapconserve typedParent, cdef.namePos)
13981398
val parents1 = ensureConstrCall(cls, parentsWithClass)(superCtx)
13991399
val self1 = typed(self)(ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible
14001400
if (self1.tpt.tpe.isError || classExistsOnSelf(cls.unforcedDecls, self1)) {
@@ -1452,7 +1452,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
14521452
* - has C as its class symbol, and
14531453
* - for all parents P_i: If P_i derives from C then P_i <:< CT.
14541454
*/
1455-
def ensureFirstIsClass(parents: List[Type])(implicit ctx: Context): List[Type] = {
1455+
def ensureFirstIsClass(parents: List[Type], pos: Position)(implicit ctx: Context): List[Type] = {
14561456
def realClassParent(cls: Symbol): ClassSymbol =
14571457
if (!cls.isClass) defn.ObjectClass
14581458
else if (!(cls is Trait)) cls.asClass
@@ -1469,19 +1469,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
14691469
case _ =>
14701470
val pcls = (defn.ObjectClass /: parents)(improve)
14711471
typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %")
1472-
val ptype = ctx.typeComparer.glb(
1472+
val first = ctx.typeComparer.glb(
14731473
defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls)))
1474-
ptype :: parents
1474+
checkFeasibleParent(first, pos, em" in inferred superclass $first") :: parents
14751475
}
14761476
}
14771477

14781478
/** Ensure that first parent tree refers to a real class. */
1479-
def ensureFirstIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match {
1479+
def ensureFirstTreeIsClass(parents: List[Tree], pos: Position)(implicit ctx: Context): List[Tree] = parents match {
14801480
case p :: ps if p.tpe.classSymbol.isRealClass => parents
1481-
case _ =>
1482-
// add synthetic class type
1483-
val first :: _ = ensureFirstIsClass(parents.tpes)
1484-
TypeTree(checkFeasible(first, pos, em"\n in inferred parent $first")).withPos(pos) :: parents
1481+
case _ => TypeTree(ensureFirstIsClass(parents.tpes, pos).head).withPos(pos) :: parents
14851482
}
14861483

14871484
/** If this is a real class, make sure its first parent is a

tests/neg/templateParents.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ object templateParentsNeg1 {
1212
trait D extends C[String]
1313
trait E extends C[Int]
1414

15-
val x = new D with E // error no type fits between inferred bounds
15+
val x = new D with E // error: conflicting type arguments inferred type
1616
}

0 commit comments

Comments
 (0)