From c13e7affdb05aa9fee498f9c01cd733365799aad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 15 Jul 2017 14:16:19 +0200 Subject: [PATCH 1/3] Fix #2712 and #2421: Check inapplicable modifiers Check modifiers `lazy` and `inline` for inapplicability --- compiler/src/dotty/tools/dotc/typer/Checking.scala | 8 +++++++- compiler/src/dotty/tools/dotc/typer/Namer.scala | 4 ++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index c402f4aafccf..915ae74a8044 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -315,7 +315,10 @@ object Checking { fail(AbstractMemberMayNotHaveModifier(sym, flag)) def checkNoConflict(flag1: FlagSet, flag2: FlagSet) = if (sym.is(allOf(flag1, flag2))) - fail(i"illegal combination of modifiers: $flag1 and $flag2 for: $sym") + fail(i"illegal combination of modifiers: `$flag1` and `$flag2` for: $sym") + def checkApplicable(flag: FlagSet, ok: Boolean) = + if (!ok && !sym.is(Synthetic)) + fail(i"modifier `$flag` is not allowed for this definition") if (sym.is(ImplicitCommon)) { if (sym.owner.is(Package)) @@ -345,6 +348,9 @@ object Checking { checkNoConflict(Final, Sealed) checkNoConflict(Private, Protected) checkNoConflict(Abstract, Override) + checkNoConflict(Lazy, Inline) + if (sym.is(Inline)) checkApplicable(Inline, sym.is(Method, butNot = Mutable)) + if (sym.is(Lazy)) checkApplicable(Lazy, !sym.is(Method | Mutable)) if (sym.isType && !sym.is(Deferred)) for (cls <- sym.allOverriddenSymbols.filter(_.isClass)) { fail(CannotHaveSameNameAs(sym, cls, CannotHaveSameNameAs.CannotBeOverridden)) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 74cfffbcd6a1..5038007b4ec0 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -243,6 +243,10 @@ class Namer { typer: Typer => def privateWithinClass(mods: Modifiers) = enclosingClassNamed(mods.privateWithin, mods.pos) + /** Check that flags are OK for symbol. This is done early to avoid + * catastrophic failure when we create a TermSymbol with TypeFlags, or vice versa. + * A more complete check is done in checkWellformed. + */ def checkFlags(flags: FlagSet) = if (flags.isEmpty) flags else { From d8c574a028aca8e4d6d9652ac3ebe7dce8be866c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 15 Jul 2017 16:44:46 +0200 Subject: [PATCH 2/3] Fix admissibility criterion for Inline --- compiler/src/dotty/tools/dotc/typer/Checking.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 915ae74a8044..7cb144adb025 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -349,7 +349,7 @@ object Checking { checkNoConflict(Private, Protected) checkNoConflict(Abstract, Override) checkNoConflict(Lazy, Inline) - if (sym.is(Inline)) checkApplicable(Inline, sym.is(Method, butNot = Mutable)) + if (sym.is(Inline)) checkApplicable(Inline, sym.isTerm && !sym.is(Mutable | Module)) if (sym.is(Lazy)) checkApplicable(Lazy, !sym.is(Method | Mutable)) if (sym.isType && !sym.is(Deferred)) for (cls <- sym.allOverriddenSymbols.filter(_.isClass)) { From 8213e9624e4ea4beacaad5c014aa428f83cb2cc1 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 15 Jul 2017 17:11:27 +0200 Subject: [PATCH 3/3] Add tests back --- tests/neg/i2421.scala | 10 ++++++++++ tests/neg/i2712.scala | 12 ++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 tests/neg/i2421.scala create mode 100644 tests/neg/i2712.scala diff --git a/tests/neg/i2421.scala b/tests/neg/i2421.scala new file mode 100644 index 000000000000..c09da6a8a3f2 --- /dev/null +++ b/tests/neg/i2421.scala @@ -0,0 +1,10 @@ +inline object Foo // error: modifier(s) `inline' incompatible with type definition +inline class Bar // error: modifier(s) `inline' incompatible with type definition +inline abstract class Baz // error: modifier(s) `inline' incompatible with type definition +inline trait Qux // error: modifier(s) `inline' incompatible with type definition + +object Quux { + inline type T // error: modifier(s) `inline' incompatible with type definition + inline var x: Int = 42 // error: modifier(s) `inline' incompatible with var definition + inline lazy val y: Int = 43 // error: modifier(s) `inline' incompatible with lazy val definition +} diff --git a/tests/neg/i2712.scala b/tests/neg/i2712.scala new file mode 100644 index 000000000000..59fb0a1ebf14 --- /dev/null +++ b/tests/neg/i2712.scala @@ -0,0 +1,12 @@ +object Foo { + lazy var x: Int = 42 // error: modifier(s) `lazy' incompatible with var definition + lazy def y: Int = 42 // error: modifier(s) `lazy' incompatible with def definition +} + +lazy class Bar // error: modifier(s) `lazy' incompatible with type definition +lazy abstract class Baz // error: modifier(s) `lazy abstract' incompatible with type definition +lazy trait Qux // error: modifier(s) `lazy' not allowed for trait + +object Quux { + lazy type T // error: modifier(s) `lazy' incompatible with type definition +}