From 5fd2028931874291b3cf1b7efef4fed7119d9316 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 31 Jan 2016 16:37:10 +0100 Subject: Enforce rule that laziness is preserved when overriding. --- src/dotty/tools/backend/jvm/DottyBackendInterface.scala | 2 +- src/dotty/tools/dotc/core/Contexts.scala | 2 +- src/dotty/tools/dotc/typer/RefChecks.scala | 12 +++++++----- test/dotc/tests.scala | 4 ++-- tests/neg/overrides.scala | 8 +++++++- tests/pos-scala2/pos-special/i871.scala | 4 ++++ tests/run/t429.scala | 2 +- 7 files changed, 23 insertions(+), 11 deletions(-) create mode 100644 tests/pos-scala2/pos-special/i871.scala diff --git a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala index f70143888..b6adba85a 100644 --- a/src/dotty/tools/backend/jvm/DottyBackendInterface.scala +++ b/src/dotty/tools/backend/jvm/DottyBackendInterface.scala @@ -131,7 +131,7 @@ class DottyBackendInterface()(implicit ctx: Context) extends BackendInterface{ val hashMethodSym: Symbol = NoSymbol // used to dispatch ## on primitives to ScalaRuntime.hash. Should be implemented by a miniphase val externalEqualsNumNum: Symbol = defn.BoxesRunTimeModule.requiredMethod(nme.equalsNumNum) - lazy val externalEqualsNumChar: Symbol = ??? // ctx.requiredMethod(BoxesRunTimeTypeRef, nme.equalsNumChar) // this method is private + val externalEqualsNumChar: Symbol = NoSymbol // ctx.requiredMethod(BoxesRunTimeTypeRef, nme.equalsNumChar) // this method is private val externalEqualsNumObject: Symbol = defn.BoxesRunTimeModule.requiredMethod(nme.equalsNumObject) val externalEquals: Symbol = defn.BoxesRunTimeClass.info.decl(nme.equals_).suchThat(toDenot(_).info.firstParamTypes.size == 2).symbol val MaxFunctionArity: Int = Definitions.MaxFunctionArity diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 9ccb03b89..c1132ce4b 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -493,7 +493,7 @@ object Contexts { } @sharable object NoContext extends Context { - lazy val base = unsupported("base") + val base = null override val implicits: ContextualImplicits = new ContextualImplicits(Nil, null)(this) } diff --git a/src/dotty/tools/dotc/typer/RefChecks.scala b/src/dotty/tools/dotc/typer/RefChecks.scala index 7ccb3d103..067694bfd 100644 --- a/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/src/dotty/tools/dotc/typer/RefChecks.scala @@ -211,7 +211,7 @@ object RefChecks { if (!(hasErrors && member.is(Synthetic) && member.is(Module))) { // suppress errors relating toi synthetic companion objects if other override // errors (e.g. relating to the companion class) have already been reported. - if (member.owner == clazz) ctx.error(fullmsg+", member = $member", member.pos) + if (member.owner == clazz) ctx.error(fullmsg, member.pos) else mixinOverrideErrors += new MixinOverrideError(member, fullmsg) hasErrors = true } @@ -330,10 +330,12 @@ object RefChecks { "(this rule is designed to prevent ``accidental overrides'')") } else if (other.isStable && !member.isStable) { // (1.4) overrideError("needs to be a stable, immutable value") - } else if (member.is(Lazy) && !other.isRealMethod && !other.is(Deferred | Lazy)) { - overrideError("cannot override a concrete non-lazy value") - } else if (other.is(Lazy, butNot = Deferred) && !other.isRealMethod && !member.is(Lazy)) { - overrideError("must be declared lazy to override a concrete lazy value") + } else if (member.is(ModuleVal) && !other.isRealMethod && !other.is(Deferred | Lazy)) { + overrideError("may not override a concrete non-lazy value") + } else if (member.is(Lazy, butNot = Module) && !other.isRealMethod && !other.is(Lazy)) { + overrideError("may not override a non-lazy value") + } else if (other.is(Lazy) && !other.isRealMethod && !member.is(Lazy)) { + overrideError("must be declared lazy to override a lazy value") } else if (other.is(Deferred) && member.is(Macro) && member.extendedOverriddenSymbols.forall(_.is(Deferred))) { // (1.9) overrideError("cannot be used here - term macros cannot override abstract methods") } else if (other.is(Macro) && !member.is(Macro)) { // (1.10) diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index 3414f1977..1c62ed96d 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -122,10 +122,10 @@ class tests extends CompilerTest { @Test def neg_autoTupling2 = compileFile(negDir, "autoTuplingTest", xerrors = 3) @Test def neg_companions = compileFile(negDir, "companions", xerrors = 1) @Test def neg_over = compileFile(negDir, "over", xerrors = 3) - @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 12) + @Test def neg_overrides = compileFile(negDir, "overrides", xerrors = 14) @Test def neg_overrideClass = compileFile(negDir, "overrideClass", List("-language:Scala2"), xerrors = 1) @Test def neg_i39 = compileFile(negDir, "i39", xerrors = 2) - @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 6) + @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 5) @Test def neg_zoo = compileFile(negDir, "zoo", xerrors = 12) val negTailcallDir = negDir + "tailcall/" diff --git a/tests/neg/overrides.scala b/tests/neg/overrides.scala index fe14f91ef..81a93a7a2 100644 --- a/tests/neg/overrides.scala +++ b/tests/neg/overrides.scala @@ -3,10 +3,16 @@ class Foo { type B >: Int <: Int def get: A = 42 } -class Bar extends Foo { +trait T { + lazy val x: Int + val y: Int +} +class Bar extends Foo with T { override type A = Any // error type B >: String <: Any // error override def get: A = "bar" + val x = 2 // error + lazy val y = 3 // error } object Test { def main(args: Array[String]): Unit = { diff --git a/tests/pos-scala2/pos-special/i871.scala b/tests/pos-scala2/pos-special/i871.scala new file mode 100644 index 000000000..2e5f100d8 --- /dev/null +++ b/tests/pos-scala2/pos-special/i871.scala @@ -0,0 +1,4 @@ +trait Message { + def first(x: Int) + def second +} diff --git a/tests/run/t429.scala b/tests/run/t429.scala index e62a6b307..eeed4b080 100644 --- a/tests/run/t429.scala +++ b/tests/run/t429.scala @@ -1,7 +1,7 @@ object Test { abstract class A { Console.print("A"); - val x: Int; + lazy val x: Int; val y: Int = {Console.print("y"); x + 1} } class B extends A { -- cgit v1.2.3