From aad73c149076f4cc16672bfde1278d1eb27a7ee9 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 22 Jan 2024 15:24:56 +0100 Subject: [PATCH 1/3] Do not propagate `@tailrec` to exported methods Fixes #19505 --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 5 ++++- tests/pos/i19505.scala | 10 ++++++++++ tests/warn/i19505.scala | 8 ++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i19505.scala create mode 100644 tests/warn/i19505.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index e9264366dfc0..70ee6e6e1fe5 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1254,7 +1254,10 @@ class Namer { typer: Typer => newSymbol(cls, forwarderName, mbrFlags, mbrInfo, coord = span) forwarder.info = avoidPrivateLeaks(forwarder) - forwarder.addAnnotations(sym.annotations.filterConserve(_.symbol != defn.BodyAnnot)) + forwarder.addAnnotations(sym.annotations.filterConserve { annot => + annot.symbol != defn.BodyAnnot + && annot.symbol != defn.TailrecAnnot + }) if forwarder.isType then buf += tpd.TypeDef(forwarder.asType).withSpan(span) diff --git a/tests/pos/i19505.scala b/tests/pos/i19505.scala new file mode 100644 index 000000000000..69fb0217c1d7 --- /dev/null +++ b/tests/pos/i19505.scala @@ -0,0 +1,10 @@ +import scala.annotation.tailrec + +object Foo: + @tailrec + def foo(n: Int): Int = + if n == 0 then 0 + else foo(n-1) + +object Bar: + export Foo.foo // def foo here should not have `@tailrec` diff --git a/tests/warn/i19505.scala b/tests/warn/i19505.scala new file mode 100644 index 000000000000..da0f859b24ad --- /dev/null +++ b/tests/warn/i19505.scala @@ -0,0 +1,8 @@ +import scala.annotation.tailrec + +object Foo: + @tailrec + def foo: Int = foo // warn: Infinite recursive call + +object Bar: + export Foo.foo // def foo here should not have `@tailrec` From 29deb053abc711dba54273d4d43e780d44517e18 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 23 Jan 2024 09:01:14 +0100 Subject: [PATCH 2/3] Do not propagate macro annotations to exported methods --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 1 + tests/run-macros/annot-export/Macro_1.scala | 13 +++++++++++++ tests/run-macros/annot-export/Test_2.scala | 10 ++++++++++ 3 files changed, 24 insertions(+) create mode 100644 tests/run-macros/annot-export/Macro_1.scala create mode 100644 tests/run-macros/annot-export/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 70ee6e6e1fe5..9f65f999d5e3 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1257,6 +1257,7 @@ class Namer { typer: Typer => forwarder.addAnnotations(sym.annotations.filterConserve { annot => annot.symbol != defn.BodyAnnot && annot.symbol != defn.TailrecAnnot + && !annot.symbol.derivesFrom(defn.MacroAnnotationClass) }) if forwarder.isType then diff --git a/tests/run-macros/annot-export/Macro_1.scala b/tests/run-macros/annot-export/Macro_1.scala new file mode 100644 index 000000000000..9a8267bfae4b --- /dev/null +++ b/tests/run-macros/annot-export/Macro_1.scala @@ -0,0 +1,13 @@ +import scala.annotation.{experimental, MacroAnnotation} +import scala.quoted._ +import scala.collection.mutable.Map + +@experimental +class returnClassName extends MacroAnnotation { + def transform(using Quotes)(tree: quotes.reflect.Definition): List[quotes.reflect.Definition] = + import quotes.reflect._ + tree match + case DefDef(name, params, tpt, _) => + val rhs = Literal(StringConstant(Symbol.spliceOwner.name.stripSuffix("$"))) + List(DefDef.copy(tree)(name, params, tpt, Some(rhs))) +} diff --git a/tests/run-macros/annot-export/Test_2.scala b/tests/run-macros/annot-export/Test_2.scala new file mode 100644 index 000000000000..abae5716bc5d --- /dev/null +++ b/tests/run-macros/annot-export/Test_2.scala @@ -0,0 +1,10 @@ +object Bar: + @returnClassName + def f(): String = ??? // def f(): String = "Bar" + +object Baz: + export Bar.f // def f(): String = Bar.f(n) + +@main def Test = + assert(Bar.f() == "Bar") + assert(Baz.f() == "Bar") From ef4888b87e38a796b0df3e959a0379481054104d Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 23 Jan 2024 09:14:05 +0100 Subject: [PATCH 3/3] Do not propagate `main` annotations to exported methods --- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 ++ tests/pos/export-main.scala | 5 +++++ 2 files changed, 7 insertions(+) create mode 100644 tests/pos/export-main.scala diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 9f65f999d5e3..819b43fcec2c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1257,7 +1257,9 @@ class Namer { typer: Typer => forwarder.addAnnotations(sym.annotations.filterConserve { annot => annot.symbol != defn.BodyAnnot && annot.symbol != defn.TailrecAnnot + && annot.symbol != defn.MainAnnot && !annot.symbol.derivesFrom(defn.MacroAnnotationClass) + && !annot.symbol.derivesFrom(defn.MainAnnotationClass) }) if forwarder.isType then diff --git a/tests/pos/export-main.scala b/tests/pos/export-main.scala new file mode 100644 index 000000000000..7ce0a23de76f --- /dev/null +++ b/tests/pos/export-main.scala @@ -0,0 +1,5 @@ +object Foo: + @main def baz: Int = 1 + +object Bar: + export Foo.baz // export Foo.baz but not create an new main entry point