diff options
-rw-r--r-- | src/dotty/tools/dotc/typer/Checking.scala | 14 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 3 | ||||
-rw-r--r-- | test/dotc/tests.scala | 1 | ||||
-rw-r--r-- | tests/neg/traitParamsTyper.scala | 16 |
4 files changed, 29 insertions, 5 deletions
diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index 3ef6d059a..9047b8cb3 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -20,6 +20,7 @@ import annotation.unchecked import util.Positions._ import util.{Stats, SimpleMap} import util.common._ +import transform.SymUtils._ import Decorators._ import Uniques._ import ErrorReporting.{err, errorType, DiagnosticString} @@ -328,9 +329,15 @@ trait Checking { } } - def checkInstantiatable(cls: ClassSymbol, pos: Position): Unit = { - ??? // to be done in later phase: check that class `cls` is legal in a new. - } + def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = + if (!ctx.isAfterTyper) { + val called = call.tpe.classSymbol + if (caller is Trait) + ctx.error(i"$caller may not call constructor of $called", call.pos) + else if (called.is(Trait) && !caller.mixins.contains(called)) + ctx.error(i"""$called is already implemented by super${caller.superClass}, + |its constructor cannot be called again""".stripMargin, call.pos) + } } trait NoChecking extends Checking { @@ -343,4 +350,5 @@ trait NoChecking extends Checking { override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = () override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = () + override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = () } diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 5f03d19e7..2bdd0d197 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -911,8 +911,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit if (tree.isType) typedType(tree)(superCtx) else { val result = typedExpr(tree)(superCtx) - if ((cls is Trait) && result.tpe.classSymbol.isRealClass && !ctx.isAfterTyper) - ctx.error(s"trait may not call constructor of ${result.tpe.classSymbol}", tree.pos) + checkParentCall(result, cls) result } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 0a6127580..ec5e34574 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -138,6 +138,7 @@ class tests extends CompilerTest { @Test def neg_instantiateAbstract = compileFile(negDir, "instantiateAbstract", xerrors = 8) @Test def neg_selfInheritance = compileFile(negDir, "selfInheritance", xerrors = 5) @Test def neg_shadowedImplicits = compileFile(negDir, "arrayclone-new", xerrors = 2) + @Test def neg_traitParamsTyper = compileFile(negDir, "traitParamsTyper", xerrors = 5) @Test def run_all = runFiles(runDir) diff --git a/tests/neg/traitParamsTyper.scala b/tests/neg/traitParamsTyper.scala new file mode 100644 index 000000000..f87ba3691 --- /dev/null +++ b/tests/neg/traitParamsTyper.scala @@ -0,0 +1,16 @@ +trait T(x: Int) { + def f = x +} + +class C(x: Int) extends T() // error + +trait U extends C with T + +trait V extends C(1) with T(2) // two errors + +trait W extends T(3) // error + + +class E extends T(0) +class F extends E with T(1) // error + |