Skip to content

Commit 3ccf9b3

Browse files
committed
include constructor in unroll clash, loosen final check for objects
1 parent 73bb8af commit 3ccf9b3

File tree

5 files changed

+42
-9
lines changed

5 files changed

+42
-9
lines changed

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
137137
if method.is(Deferred) then
138138
report.error("Unrolled method must be final and concrete", method.srcPos)
139139
res = false
140-
if !method.isConstructor && !method.is(Final) then
140+
if !(method.isConstructor || method.is(Final) || method.owner.is(ModuleClass)) then
141141
report.error("Unrolled method must be final", method.srcPos)
142142
res = false
143143
res

compiler/src/dotty/tools/dotc/transform/UnrollDefinitions.scala

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import dotty.tools.unreachable
2525

2626
/**Implementation of SIP-61.
2727
* Runs when `@unroll` annotations are found in a compilation unit, installing new definitions
28+
*
29+
* Note that it only generates `Invisible` methods, so no interactions with Zinc/SemanticDB
2830
*/
2931
class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer {
3032
self =>
@@ -63,17 +65,18 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer {
6365

6466
def computeIndices(annotated: Symbol)(using Context): ComputedIndicies =
6567
unrolledDefs.getOrElseUpdate(annotated, {
66-
annotated
68+
val indices = annotated
6769
.paramSymss
6870
.zipWithIndex
69-
.flatMap { (paramClause, paramClauseIndex) =>
71+
.flatMap: (paramClause, paramClauseIndex) =>
7072
val annotationIndices = findUnrollAnnotations(paramClause)
7173
if (annotationIndices.isEmpty) None
72-
else
73-
require(annotated.is(Final, butNot = Deferred) || annotated.isConstructor,
74-
i"${annotated} is not final&concrete, or a constructor")
75-
Some((paramClauseIndex, annotationIndices))
76-
}
74+
else Some((paramClauseIndex, annotationIndices))
75+
if indices.nonEmpty then
76+
// pre-validation should have occurred in posttyper
77+
assert(annotated.is(Final, butNot = Deferred) || annotated.isConstructor || annotated.owner.is(ModuleClass),
78+
i"$annotated is not final&concrete, or a constructor")
79+
indices
7780
})
7881
end computeIndices
7982

@@ -320,7 +323,7 @@ class UnrollDefinitions extends MacroTransform, IdentityDenotTransformer {
320323
decl.matches(other) && !staticNonStaticPair
321324

322325
if allGenerated.nonEmpty then
323-
val byName = otherDecls.groupMap(_.symbol.name.toString)(_.symbol)
326+
val byName = (tmpl.constr :: otherDecls).groupMap(_.symbol.name.toString)(_.symbol)
324327
for
325328
(src, _, dcls) <- allGenerated
326329
dcl <- dcls

tests/neg/unroll-clash.check

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@
44
| Unrolled method foo clashes with existing declaration.
55
| Please remove the clashing definition, or the @unroll annotation.
66
| Unrolled from final def foo(x: Int, y: Int): Int in class Foo at line 6
7+
-- Error: tests/neg/unroll-clash.scala:13:20 ---------------------------------------------------------------------------
8+
13 |class UnrolledClass2(s: String) { // error
9+
| ^
10+
| Unrolled constructor UnrolledClass2 clashes with existing declaration.
11+
| Please remove the clashing definition, or the @unroll annotation.
12+
| Unrolled from def <init>(s: String, y: Boolean): UnrolledClass2 in class UnrolledClass2 at line 15

tests/neg/unroll-clash.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,10 @@ class Foo {
99
-1
1010
}
1111
}
12+
13+
class UnrolledClass2(s: String) { // error
14+
15+
def this(s: String, @unroll y: Boolean = true) = this(s + y)
16+
17+
override def toString = s"UnrolledClass2($s)"
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//> using options -experimental
2+
3+
import scala.annotation.unroll
4+
5+
object UnrolledObj {
6+
// final is not needed because objects can't be extended
7+
def foo(s: String, @unroll y: Boolean = true): String = s + y
8+
}
9+
10+
// final inferred for constructor
11+
class UnrolledClass(s: String, @unroll y: Boolean = true):
12+
override def toString = s"UnrolledClass($s,$y)"
13+
14+
15+
@main def Test: Unit =
16+
assert(UnrolledObj.foo("foo") == "footrue")
17+
assert(new UnrolledClass("foo").toString == "UnrolledClass(foo,true)")

0 commit comments

Comments
 (0)