Skip to content

Commit b9e576a

Browse files
committed
Check that inferred parent classes are feasible.
1 parent 340ca06 commit b9e576a

File tree

4 files changed

+39
-9
lines changed

4 files changed

+39
-9
lines changed

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ object Inferencing {
468468
case p :: _ if p.classSymbol.isRealClass => parents
469469
case _ =>
470470
val pcls = (defn.ObjectClass /: parents)(improve)
471+
typr.println(i"ensure first is class $parents%, % --> ${parents map (_ baseTypeWithArgs pcls)}%, %")
471472
val ptype = ctx.typeComparer.glb(
472473
defn.ObjectType :: (parents map (_ baseTypeWithArgs pcls)))
473474
ptype :: parents
@@ -479,9 +480,22 @@ object Inferencing {
479480
case p :: ps if p.tpe.classSymbol.isRealClass => parents
480481
case _ =>
481482
// add synthetic class type
482-
val parentTypes = ensureFirstIsClass(parents.tpes)
483-
assert(parentTypes.length > parents.length)
484-
(TypeTree(parentTypes.head) withPos pos) :: parents
483+
val first :: _ = ensureFirstIsClass(parents.tpes)
484+
TypeTree(checkFeasible(first, pos, i"\n in inferred parent $first")).withPos(pos) :: parents
485+
}
486+
487+
/** Check that any top-level type arguments in this type are feasible, i.e. that
488+
* their lower bound conforms to their upper cound. If a type argument is
489+
* infeasible, issue and error and continue with upper bound.
490+
*/
491+
def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp match {
492+
case tp: RefinedType =>
493+
tp.derivedRefinedType(tp.parent, tp.refinedName, checkFeasible(tp.refinedInfo, pos, where))
494+
case tp @ TypeBounds(lo, hi) if !(lo <:< hi) =>
495+
ctx.error(i"no type exists between low bound $lo and high bound $hi$where", pos)
496+
tp.derivedTypeAlias(hi)
497+
case _ =>
498+
tp
485499
}
486500

487501
/** Check that class does not define */

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class tests extends CompilerTest {
4747
@Test def neg_typers() = compileFile(negDir, "typers", xerrors = 10)
4848
@Test def neg_privates() = compileFile(negDir, "privates", xerrors = 2)
4949
@Test def neg_rootImports = compileFile(negDir, "rootImplicits", xerrors = 2)
50-
@Test def neg_templateParents() = compileFile(posDir, "templateParents", xerrors = 2)
50+
@Test def neg_templateParents() = compileFile(negDir, "templateParents", xerrors = 3)
5151

5252
@Test def dotc = compileDir(dotcDir + "tools/dotc")
5353
@Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast")

tests/neg/templateParents.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ object templateParentsNeg {
77
new C("b") with C2 // error: C2 is not a trait
88

99
}
10+
object templateParentsNeg1 {
11+
class C[T]
12+
trait D extends C[String]
13+
trait E extends C[Int]
14+
15+
val x = new D with E // error no type fits between inferred bounds
16+
}

tests/pos/templateParents.scala

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
object templateParents {
22

3-
// traits do not call a constructor
4-
class C[+T](x: T)
3+
// traits do not call a constructor
4+
class C[+T](x: T)
55
trait D extends C[String]
66
trait E extends C[Int]
77
new C("abc") with D
8+
9+
}
810

9-
//val x = new D with E
11+
object templateParents1 {
12+
// tests inference of synthesized class type
13+
class C[+T]
14+
trait D extends C[String]
15+
trait E extends C[Int]
16+
17+
val x = new D with E
18+
19+
val y: C[Int & String] = x
20+
}
1021

11-
//val y: C = x
12-
}

0 commit comments

Comments
 (0)