Skip to content

Commit

Permalink
Merge pull request #15488 from dotty-staging/fix-15459
Browse files Browse the repository at this point in the history
Fix #15459: Display uninitialized fields in promotion error
  • Loading branch information
olhotak authored Jun 21, 2022
2 parents 9e3953d + 227616c commit 7f1ae28
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 19 deletions.
21 changes: 19 additions & 2 deletions compiler/src/dotty/tools/dotc/transform/init/Semantic.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,19 @@ object Semantic:
}
}

def nonInitFields(): Contextual[List[Symbol]] =
val obj = ref.objekt
ref.klass.baseClasses.flatMap { klass =>
if klass.hasSource then
klass.info.decls.filter { member =>
!member.isOneOf(Flags.Method | Flags.Lazy | Flags.Deferred)
&& !member.isType
&& !obj.hasField(member)
}
else
Nil
}

end extension

extension (thisRef: ThisRef)
Expand All @@ -1032,8 +1045,12 @@ object Semantic:
reporter.report(PromoteError(msg, trace.toVector))

case thisRef: ThisRef =>
if !thisRef.tryPromoteCurrentObject() then
reporter.report(PromoteError(msg, trace.toVector))
val emptyFields = thisRef.nonInitFields()
if emptyFields.isEmpty then
promoted.promoteCurrent(thisRef)
else
val fields = "Non initialized field(s): " + emptyFields.map(_.show).mkString(", ") + "."
reporter.report(PromoteError(msg + "\n" + fields, trace.toVector))

case warm: Warm =>
if !promoted.contains(warm) then
Expand Down
3 changes: 2 additions & 1 deletion tests/init/neg/closureLeak.check
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
| ^^^^^^^^^^^^^^^^^
|
| Promoting the value to fully initialized failed due to the following problem:
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak. Calling trace:
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak.
| Non initialized field(s): value p. Calling trace:
| -> l.foreach(a => a.addX(this)) // error [ closureLeak.scala:11 ]
| ^^^^
19 changes: 10 additions & 9 deletions tests/init/neg/default-this.check
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
-- Error: tests/init/neg/default-this.scala:9:8 ------------------------------------------------------------------------
9 | compare() // error
| ^^^^^^^
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak. Calling trace:
| -> class B extends A { [ default-this.scala:6 ]
| ^
| -> val result = updateThenCompare(5) [ default-this.scala:11 ]
| ^^^^^^^^^^^^^^^^^^^^
| -> def updateThenCompare(c: Int): Boolean = { [ default-this.scala:7 ]
| ^
| -> compare() // error [ default-this.scala:9 ]
| ^^^^^^^
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak.
| Non initialized field(s): value result. Calling trace:
| -> class B extends A { [ default-this.scala:6 ]
| ^
| -> val result = updateThenCompare(5) [ default-this.scala:11 ]
| ^^^^^^^^^^^^^^^^^^^^
| -> def updateThenCompare(c: Int): Boolean = { [ default-this.scala:7 ]
| ^
| -> compare() // error [ default-this.scala:9 ]
| ^^^^^^^
11 changes: 11 additions & 0 deletions tests/init/neg/i15459.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- Error: tests/init/neg/i15459.scala:3:10 -----------------------------------------------------------------------------
3 | println(this) // error
| ^^^^
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak.
| Non initialized field(s): value b. Calling trace:
| -> class Sub extends Sup: [ i15459.scala:5 ]
| ^
| -> class Sup: [ i15459.scala:1 ]
| ^
| -> println(this) // error [ i15459.scala:3 ]
| ^^^^
8 changes: 8 additions & 0 deletions tests/init/neg/i15459.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Sup:
val a = 10
println(this) // error

class Sub extends Sup:
val b = 20

override def toString() = "a = " + a + ", b = " + b
15 changes: 8 additions & 7 deletions tests/init/neg/inlined-method.check
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
-- Error: tests/init/neg/inlined-method.scala:8:45 ---------------------------------------------------------------------
8 | scala.runtime.Scala3RunTime.assertFailed(message) // error
| ^^^^^^^
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak. Calling trace:
| -> class InlineError { [ inlined-method.scala:1 ]
| ^
| -> Assertion.failAssert(this) [ inlined-method.scala:2 ]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| -> scala.runtime.Scala3RunTime.assertFailed(message) // error [ inlined-method.scala:8 ]
| ^^^^^^^
| Cannot prove the argument is fully initialized. Only fully initialized values are safe to leak.
| Non initialized field(s): value v. Calling trace:
| -> class InlineError { [ inlined-method.scala:1 ]
| ^
| -> Assertion.failAssert(this) [ inlined-method.scala:2 ]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| -> scala.runtime.Scala3RunTime.assertFailed(message) // error [ inlined-method.scala:8 ]
| ^^^^^^^
1 change: 1 addition & 0 deletions tests/init/neg/promotion-loop.check
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
|
| Promoting the value to fully initialized failed due to the following problem:
| Cannot prove that the field val outer is fully initialized.
| Non initialized field(s): value n.

0 comments on commit 7f1ae28

Please sign in to comment.