Skip to content

Commit de2c072

Browse files
committed
Make sure inner classes are checked first
This will produce better diagnosis messages. This is because Dotty only show the first error detected for the same line to end users. If we check inner classes first, the scope of the error is restricted to the inner class whenever possible (instead of involving the outer class).
1 parent 2c87994 commit de2c072

File tree

6 files changed

+49
-43
lines changed

6 files changed

+49
-43
lines changed

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,10 +1143,10 @@ object Semantic:
11431143
case class Task(value: ThisRef)
11441144

11451145
class WorkList private[Semantic]():
1146-
private var pendingTasks: List[Task] = Nil
1146+
private val pendingTasks: mutable.ArrayBuffer[Task] = new mutable.ArrayBuffer
11471147

11481148
def addTask(task: Task): Unit =
1149-
if !pendingTasks.contains(task) then pendingTasks = task :: pendingTasks
1149+
if !pendingTasks.contains(task) then pendingTasks += task
11501150

11511151
/** Process the worklist until done */
11521152
final def work()(using Cache, Context): Unit =

tests/init/neg/cycle-structure.check

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
-- Error: tests/init/neg/cycle-structure.scala:9:13 --------------------------------------------------------------------
2-
9 | val x = A(this) // error
1+
-- Error: tests/init/neg/cycle-structure.scala:3:13 --------------------------------------------------------------------
2+
3 | val x = B(this) // error
33
| ^^^^^^^
44
| Problematic object instantiation: arg 1 is not fully initialized. Calling trace:
5-
| -> case class B(a: A) { [ cycle-structure.scala:7 ]
5+
| -> case class A(b: B) { [ cycle-structure.scala:1 ]
66
| ^
7-
| -> val x = A(this) // error [ cycle-structure.scala:9 ]
7+
| -> val x = B(this) // error [ cycle-structure.scala:3 ]
88
| ^^^^^^^
99
|
1010
| It leads to the following error during object initialization:
1111
| Access field on a value with an unknown initialization status. Calling trace:
12-
| -> case class A(b: B) { [ cycle-structure.scala:1 ]
12+
| -> case class B(a: A) { [ cycle-structure.scala:7 ]
1313
| ^
14-
| -> val x1 = b.x [ cycle-structure.scala:2 ]
14+
| -> val x1 = a.x [ cycle-structure.scala:8 ]
1515
| ^^^
16-
-- Error: tests/init/neg/cycle-structure.scala:3:13 --------------------------------------------------------------------
17-
3 | val x = B(this) // error
16+
-- Error: tests/init/neg/cycle-structure.scala:9:13 --------------------------------------------------------------------
17+
9 | val x = A(this) // error
1818
| ^^^^^^^
1919
| Problematic object instantiation: arg 1 is not fully initialized. Calling trace:
20-
| -> case class A(b: B) { [ cycle-structure.scala:1 ]
20+
| -> case class B(a: A) { [ cycle-structure.scala:7 ]
2121
| ^
22-
| -> val x = B(this) // error [ cycle-structure.scala:3 ]
22+
| -> val x = A(this) // error [ cycle-structure.scala:9 ]
2323
| ^^^^^^^
2424
|
2525
| It leads to the following error during object initialization:
2626
| Access field on a value with an unknown initialization status. Calling trace:
27-
| -> case class B(a: A) { [ cycle-structure.scala:7 ]
27+
| -> case class A(b: B) { [ cycle-structure.scala:1 ]
2828
| ^
29-
| -> val x1 = a.x [ cycle-structure.scala:8 ]
29+
| -> val x1 = b.x [ cycle-structure.scala:2 ]
3030
| ^^^

tests/init/neg/inherit-non-hot.check

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
6 | if b == null then b = new B(this) // error
33
| ^^^^^^^^^^^
44
| The RHS of reassignment must be fully initialized. Calling trace:
5-
| -> object Foo { [ inherit-non-hot.scala:2 ]
6-
| ^
7-
| -> val c = new C [ inherit-non-hot.scala:19 ]
8-
| ^^^^^
95
| -> class C extends A { [ inherit-non-hot.scala:15 ]
106
| ^
117
| -> val bAgain = toB.getBAgain [ inherit-non-hot.scala:16 ]

tests/init/neg/inner-first.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- Error: tests/init/neg/inner-first.scala:3:12 ------------------------------------------------------------------------
2+
3 | println(this) // error
3+
| ^^^^
4+
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak.
5+
| Non initialized field(s): value n. Calling trace:
6+
| -> class B: [ inner-first.scala:2 ]
7+
| ^
8+
| -> println(this) // error [ inner-first.scala:3 ]
9+
| ^^^^

tests/init/neg/inner-first.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class A:
2+
class B:
3+
println(this) // error
4+
val n = 10
5+
def foo() = println(m)
6+
new B
7+
val m = 20

tests/init/neg/secondary-ctor4.check

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,26 @@
11
-- Error: tests/init/neg/secondary-ctor4.scala:54:14 -------------------------------------------------------------------
22
54 | val c = new C(b, 5) // error
33
| ^^^^^^^^^^^
4-
| Problematic object instantiation: the outer M.this and arg 1 are not fully initialized. Calling trace:
5-
| -> class N(d: D) extends M(d) { [ secondary-ctor4.scala:59 ]
6-
| ^
7-
| -> def this(d: D) = { [ secondary-ctor4.scala:7 ]
8-
| ^
9-
| -> new A(new B(new D)) // error [ secondary-ctor4.scala:42 ]
10-
| ^^^^^
11-
| -> class D { [ secondary-ctor4.scala:52 ]
12-
| ^
13-
| -> val c = new C(b, 5) // error [ secondary-ctor4.scala:54 ]
14-
| ^^^^^^^^^^^
4+
| Problematic object instantiation: arg 1 is not fully initialized. Calling trace:
5+
| -> class D { [ secondary-ctor4.scala:52 ]
6+
| ^
7+
| -> val c = new C(b, 5) // error [ secondary-ctor4.scala:54 ]
8+
| ^^^^^^^^^^^
159
|
16-
| It leads to the following error during object initialization:
17-
| Access field on a value with an unknown initialization status. Calling trace:
18-
| -> def this(b: B, x: Int) = this(b) [ secondary-ctor4.scala:49 ]
19-
| ^^^^^^^
20-
| -> class C(b: B) extends A(b) with T { [ secondary-ctor4.scala:48 ]
21-
| ^
22-
| -> def this(b: B) = { [ secondary-ctor4.scala:17 ]
23-
| ^
24-
| -> Inner().foo() [ secondary-ctor4.scala:26 ]
25-
| ^^^^^^^
26-
| -> class Inner() { [ secondary-ctor4.scala:21 ]
27-
| ^
28-
| -> println(b.n) [ secondary-ctor4.scala:23 ]
29-
| ^^^
10+
| It leads to the following error during object initialization:
11+
| Access field on a value with an unknown initialization status. Calling trace:
12+
| -> def this(b: B, x: Int) = this(b) [ secondary-ctor4.scala:49 ]
13+
| ^^^^^^^
14+
| -> class C(b: B) extends A(b) with T { [ secondary-ctor4.scala:48 ]
15+
| ^
16+
| -> def this(b: B) = { [ secondary-ctor4.scala:17 ]
17+
| ^
18+
| -> Inner().foo() [ secondary-ctor4.scala:26 ]
19+
| ^^^^^^^
20+
| -> class Inner() { [ secondary-ctor4.scala:21 ]
21+
| ^
22+
| -> println(b.n) [ secondary-ctor4.scala:23 ]
23+
| ^^^
3024
-- Error: tests/init/neg/secondary-ctor4.scala:42:4 --------------------------------------------------------------------
3125
42 | new A(new B(new D)) // error
3226
| ^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)