From 42fa9b24a13786277a84bf9f971d41d2636e0d04 Mon Sep 17 00:00:00 2001 From: Abel Nieto Date: Fri, 27 Jul 2018 16:15:57 +0200 Subject: [PATCH] Fix #4815: Illegal modifier on local def During parsing, disallow the use of "final" in local definitions. e.g. def foo = { final def bar = 42 // error: final in local def is disallowed final var x = 42 // error final type X = Int // error } --- .../dotty/tools/dotc/parsing/Parsers.scala | 7 ++++- .../dotty/tools/languageserver/Memory.scala | 4 +-- tests/neg/t4815.scala | 26 +++++++++++++++++++ tests/run/tasty-eval/quoted_2.scala | 3 ++- 4 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 tests/neg/t4815.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index a340d9160150..f3035d718e39 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2545,7 +2545,12 @@ object Parsers { def localDef(start: Int, implicitMods: Modifiers = EmptyModifiers): Tree = { var mods = defAnnotsMods(localModifierTokens) for (imod <- implicitMods.mods) mods = addMod(mods, imod) - defOrDcl(start, mods) + if (mods.is(Final)) { + // A final modifier means the local definition is "class-like". + tmplDef(start, mods) + } else { + defOrDcl(start, mods) + } } /** BlockStatSeq ::= { BlockStat semi } [ResultExpr] diff --git a/language-server/src/dotty/tools/languageserver/Memory.scala b/language-server/src/dotty/tools/languageserver/Memory.scala index 7193df0732ea..a2869614e276 100644 --- a/language-server/src/dotty/tools/languageserver/Memory.scala +++ b/language-server/src/dotty/tools/languageserver/Memory.scala @@ -37,11 +37,11 @@ object Memory { } def stats(): String = { - final val M = 2 << 20 + val M = 2 << 20 val runtime = Runtime.getRuntime def total = runtime.totalMemory / M def maximal = runtime.maxMemory / M def free = runtime.freeMemory / M s"total used memory: $total MB, free: $free MB, maximal available = $maximal MB" } -} \ No newline at end of file +} diff --git a/tests/neg/t4815.scala b/tests/neg/t4815.scala new file mode 100644 index 000000000000..f447e896674c --- /dev/null +++ b/tests/neg/t4815.scala @@ -0,0 +1,26 @@ +class Test { + def foo = { + final def bar = 1 // error: local def may not be final + final val v = 42 // error: local val may not be final + final var v2 = 100 // error: local var may not be final + final type T = Int // error: local type def may not be final + } + + { + final def foo(x: Int) = x // error: local def may not be final + } + + final def foo2(x: Int) = x // ok: final allowed in class field + + object Foo { + final def foo(x: Int) = x // ok, but redundant + } + + abstract class Bar { + def foo: Int + } + + val x = new Bar { + override final def foo = 42 // ok: def is a field + } +} diff --git a/tests/run/tasty-eval/quoted_2.scala b/tests/run/tasty-eval/quoted_2.scala index 208bcca87708..ac3adbcc9bcd 100644 --- a/tests/run/tasty-eval/quoted_2.scala +++ b/tests/run/tasty-eval/quoted_2.scala @@ -2,10 +2,11 @@ import Macros._ object Test { + final val y = 5 + def main(args: Array[String]): Unit = { println(foo(1)) // "Some(1)" println(foo(1 + 7)) // "Some(8)" - final val y = 5 println(foo(y)) // "Some(5)" println(foo(y + 1)) val x = 4