From 89672bf0baf07a8055fbefae535d41beda97caaa Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 23 Apr 2020 19:29:57 +0200 Subject: [PATCH 1/4] =?UTF-8?q?Only=20allow=20sound=20inline=20parameters?= =?UTF-8?q?=20in=C2=A0overrides?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inline overrides can only use inline parameters if the overriden parameter is inline. --- .../dotty/tools/dotc/config/Printers.scala | 2 +- .../src/dotty/tools/dotc/typer/Checking.scala | 15 +++++++- tests/neg/inline-parameter-override.scala | 35 +++++++++++++++++++ tests/run/inline-override-num.scala | 2 +- tests/run/typeclass-derivation2b.scala | 4 +-- 5 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 tests/neg/inline-parameter-override.scala diff --git a/compiler/src/dotty/tools/dotc/config/Printers.scala b/compiler/src/dotty/tools/dotc/config/Printers.scala index e54d9ac2d695..1b5d71d9e702 100644 --- a/compiler/src/dotty/tools/dotc/config/Printers.scala +++ b/compiler/src/dotty/tools/dotc/config/Printers.scala @@ -7,7 +7,7 @@ object Printers { } object noPrinter extends Printer { - inline override def println(inline msg: => String): Unit = () + inline override def println(msg: => String): Unit = () } val default = new Printer diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 77ab4829baa4..ce585f2052fb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -451,7 +451,8 @@ object Checking { || sym.is(TermParam) && !sym.owner.isInlineMethod )) fail(ParamsNoInline(sym.owner)) - + if sym.isInlineMethod && !sym.is(Deferred) && sym.allOverriddenSymbols.nonEmpty then + checkInlineOverrideParameters(sym) if (sym.isOneOf(GivenOrImplicit)) { if (sym.owner.is(Package)) fail(TopLevelCantBeImplicit(sym)) @@ -646,6 +647,18 @@ object Checking { val enumCls = enumCase.owner.linkedClass if !cls.info.parents.exists(_.typeSymbol == enumCls) then ctx.error(i"enum case does not extend its enum $enumCls", enumCase.sourcePos) + + /** Check the inline override methods only use inline parameteres if they override an inline parameter. */ + def checkInlineOverrideParameters(sym: Symbol)(using Context): Unit = + val params = sym.paramSymss.flatten + if params.exists(_.is(Inline)) then + for + sym2 <- sym.allOverriddenSymbols + (p1, p2) <- params.lazyZip(sym2.paramSymss.flatten) + if p1.is(Inline) && !p2.is(Inline) + do + ctx.error("Cannot override non-inline parameter with and inline parameter", p1.sourcePos) + } trait Checking { diff --git a/tests/neg/inline-parameter-override.scala b/tests/neg/inline-parameter-override.scala new file mode 100644 index 000000000000..021f7bf156ba --- /dev/null +++ b/tests/neg/inline-parameter-override.scala @@ -0,0 +1,35 @@ + + +abstract class Logger { + def log1(msg: String): Unit + inline def log2(msg: String): Unit + inline def log3(inline msg: String): Unit +} + +class Logger1 extends Logger { + inline def log1(msg: String): Unit = () + inline def log2(msg: String): Unit = () + inline def log3(msg: String): Unit = () +} + +class Logger2 extends Logger { + inline def log1(inline msg: String): Unit = () // error: Cannot override non-inline parameter with and inline parameter + inline def log2(inline msg: String): Unit = () // error: Cannot override non-inline parameter with and inline parameter + inline def log3(inline msg: String): Unit = () +} + +trait A { + inline def f(inline a: Int): Int +} + +trait B { + def f(a: Int): Int +} + +class C extends A, B { + inline def f(inline a: Int): Int = 3 // error: Cannot override non-inline parameter with and inline parameter +} + +class D extends B, A { + inline def f(inline a: Int): Int = 3 // error: Cannot override non-inline parameter with and inline parameter +} \ No newline at end of file diff --git a/tests/run/inline-override-num.scala b/tests/run/inline-override-num.scala index de2053acdb99..2a5acf1c2553 100644 --- a/tests/run/inline-override-num.scala +++ b/tests/run/inline-override-num.scala @@ -4,7 +4,7 @@ trait Num[T] { object Num { class IntNum extends Num[Int] { - inline def plus(inline x: Int, inline y: Int): Int = x + y + inline def plus(x: Int, y: Int): Int = x + y } given IntNum diff --git a/tests/run/typeclass-derivation2b.scala b/tests/run/typeclass-derivation2b.scala index 3ea06ed4a751..ed3d9eb1d864 100644 --- a/tests/run/typeclass-derivation2b.scala +++ b/tests/run/typeclass-derivation2b.scala @@ -26,7 +26,7 @@ object TypeLevel { abstract class GenericSum[S] extends Generic[S] { def ordinal(x: S): Int - inline def alternative(n: Int): GenericProduct[_ <: S] + inline def alternative(inline n: Int): GenericProduct[_ <: S] } abstract class GenericProduct[P] extends Generic[P] { @@ -49,7 +49,7 @@ object Lst { case x: Cons[_] => 0 case Nil => 1 } - inline override def alternative(inline n: Int) <: GenericProduct[_ <: Lst[T]] = + inline def alternative(inline n: Int) <: GenericProduct[_ <: Lst[T]] = inline n match { case 0 => Cons.GenericCons[T] case 1 => Nil.GenericNil From 9b78ef9be94a394cc04b876f947b7e8715c23dd6 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 24 Apr 2020 15:16:09 +0200 Subject: [PATCH 2/4] Update compiler/src/dotty/tools/dotc/typer/Checking.scala Co-Authored-By: Jamie Thompson --- 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 ce585f2052fb..3fcd73e7e909 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -657,7 +657,7 @@ object Checking { (p1, p2) <- params.lazyZip(sym2.paramSymss.flatten) if p1.is(Inline) && !p2.is(Inline) do - ctx.error("Cannot override non-inline parameter with and inline parameter", p1.sourcePos) + ctx.error("Cannot override non-inline parameter with an inline parameter", p1.sourcePos) } From b5a968e60dfe7bd4643c5539e67261c916c2344e Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 24 Apr 2020 17:52:41 +0200 Subject: [PATCH 3/4] Apply suggestions from code review Co-Authored-By: Guillaume Martres --- compiler/src/dotty/tools/dotc/typer/Checking.scala | 2 +- tests/neg/inline-parameter-override.scala | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 3fcd73e7e909..2cc1683bef7c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -648,7 +648,7 @@ object Checking { if !cls.info.parents.exists(_.typeSymbol == enumCls) then ctx.error(i"enum case does not extend its enum $enumCls", enumCase.sourcePos) - /** Check the inline override methods only use inline parameteres if they override an inline parameter. */ + /** Check the inline override methods only use inline parameters if they override an inline parameter. */ def checkInlineOverrideParameters(sym: Symbol)(using Context): Unit = val params = sym.paramSymss.flatten if params.exists(_.is(Inline)) then diff --git a/tests/neg/inline-parameter-override.scala b/tests/neg/inline-parameter-override.scala index 021f7bf156ba..567d7982a2d9 100644 --- a/tests/neg/inline-parameter-override.scala +++ b/tests/neg/inline-parameter-override.scala @@ -13,8 +13,8 @@ class Logger1 extends Logger { } class Logger2 extends Logger { - inline def log1(inline msg: String): Unit = () // error: Cannot override non-inline parameter with and inline parameter - inline def log2(inline msg: String): Unit = () // error: Cannot override non-inline parameter with and inline parameter + inline def log1(inline msg: String): Unit = () // error: Cannot override non-inline parameter with an inline parameter + inline def log2(inline msg: String): Unit = () // error: Cannot override non-inline parameter with an inline parameter inline def log3(inline msg: String): Unit = () } @@ -32,4 +32,4 @@ class C extends A, B { class D extends B, A { inline def f(inline a: Int): Int = 3 // error: Cannot override non-inline parameter with and inline parameter -} \ No newline at end of file +} From e9c1e7e297515d32f428e88eca793a10f7ce9f8d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Fri, 24 Apr 2020 18:08:18 +0200 Subject: [PATCH 4/4] Disallow non-inline parametter to override inline parameter --- .../src/dotty/tools/dotc/typer/Checking.scala | 18 ++++++++++-------- tests/neg/inline-parameter-override.scala | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 2cc1683bef7c..2a543f0e0595 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -650,14 +650,16 @@ object Checking { /** Check the inline override methods only use inline parameters if they override an inline parameter. */ def checkInlineOverrideParameters(sym: Symbol)(using Context): Unit = - val params = sym.paramSymss.flatten - if params.exists(_.is(Inline)) then - for - sym2 <- sym.allOverriddenSymbols - (p1, p2) <- params.lazyZip(sym2.paramSymss.flatten) - if p1.is(Inline) && !p2.is(Inline) - do - ctx.error("Cannot override non-inline parameter with an inline parameter", p1.sourcePos) + lazy val params = sym.paramSymss.flatten + for + sym2 <- sym.allOverriddenSymbols + (p1, p2) <- sym.paramSymss.flatten.lazyZip(sym2.paramSymss.flatten) + if p1.is(Inline) != p2.is(Inline) + do + ctx.error( + if p2.is(Inline) then "Cannot override inline parameter with a non-inline parameter" + else "Cannot override non-inline parameter with an inline parameter", + p1.sourcePos) } diff --git a/tests/neg/inline-parameter-override.scala b/tests/neg/inline-parameter-override.scala index 567d7982a2d9..f0ee642f7963 100644 --- a/tests/neg/inline-parameter-override.scala +++ b/tests/neg/inline-parameter-override.scala @@ -9,7 +9,7 @@ abstract class Logger { class Logger1 extends Logger { inline def log1(msg: String): Unit = () inline def log2(msg: String): Unit = () - inline def log3(msg: String): Unit = () + inline def log3(msg: String): Unit = () // error: Cannot override inline parameter with a non-inline parameter } class Logger2 extends Logger {