Skip to content

Commit df875ee

Browse files
committed
Improve error messages
1 parent 0ae7346 commit df875ee

File tree

10 files changed

+44
-30
lines changed

10 files changed

+44
-30
lines changed

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

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,27 @@ package init
66
import ast.tpd._
77
import core._
88
import util.SourcePosition
9+
import util.Property
910
import Decorators._, printing.SyntaxHighlighting
1011
import Types._, Symbols._, Contexts._
1112

1213
import scala.collection.mutable
1314

1415
object Errors:
16+
private val IsFromPromotion = new Property.Key[Boolean]
17+
1518
sealed trait Error:
1619
def trace: Seq[Tree]
1720
def show(using Context): String
1821

1922
def pos(using Context): SourcePosition = trace.last.sourcePos
2023

21-
def stacktrace(preamble: String = " Calling trace:\n")(using Context): String = buildStacktrace(trace, preamble)
24+
def stacktrace(using Context): String =
25+
val preamble: String =
26+
if ctx.property(IsFromPromotion).nonEmpty
27+
then " Promotion trace:\n"
28+
else " Calling trace:\n"
29+
buildStacktrace(trace, preamble)
2230

2331
def issue(using Context): Unit =
2432
report.warning(show, this.pos)
@@ -74,41 +82,43 @@ object Errors:
7482
case class AccessNonInit(field: Symbol, trace: Seq[Tree]) extends Error:
7583
def source: Tree = trace.last
7684
def show(using Context): String =
77-
"Access non-initialized " + field.show + "." + stacktrace()
85+
"Access non-initialized " + field.show + "." + stacktrace
7886

7987
override def pos(using Context): SourcePosition = field.sourcePos
8088

8189
/** Promote a value under initialization to fully-initialized */
8290
case class PromoteError(msg: String, trace: Seq[Tree]) extends Error:
83-
def show(using Context): String = msg + stacktrace()
91+
def show(using Context): String = msg + stacktrace
8492

8593
case class AccessCold(field: Symbol, trace: Seq[Tree]) extends Error:
8694
def show(using Context): String =
87-
"Access field " + field.show + " on a cold object." + stacktrace()
95+
"Access field " + field.show + " on a cold object." + stacktrace
8896

8997
case class CallCold(meth: Symbol, trace: Seq[Tree]) extends Error:
9098
def show(using Context): String =
91-
"Call method " + meth.show + " on a cold object." + stacktrace()
99+
"Call method " + meth.show + " on a cold object." + stacktrace
92100

93101
case class CallUnknown(meth: Symbol, trace: Seq[Tree]) extends Error:
94102
def show(using Context): String =
95103
val prefix = if meth.is(Flags.Method) then "Calling the external method " else "Accessing the external field"
96-
prefix + meth.show + " may cause initialization errors." + stacktrace()
104+
prefix + meth.show + " may cause initialization errors." + stacktrace
97105

98106
/** Promote a value under initialization to fully-initialized */
99107
case class UnsafePromotion(msg: String, trace: Seq[Tree], error: Error) extends Error:
100108
def show(using Context): String =
101-
msg + stacktrace() + "\n" +
102-
"Promoting the value to hot failed due to the following problem:\n" +
103-
error.show
109+
msg + stacktrace + "\n" +
110+
"Promoting the value to hot failed due to the following problem:\n" + {
111+
val ctx2 = ctx.withProperty(IsFromPromotion, Some(true))
112+
error.show(using ctx2)
113+
}
104114

105115
/** Unsafe leaking a non-hot value as constructor arguments
106116
*
107117
* Invariant: argsIndices.nonEmpty
108118
*/
109119
case class UnsafeLeaking(trace: Seq[Tree], error: Error, nonHotOuterClass: Symbol, argsIndices: List[Int]) extends Error:
110120
def show(using Context): String =
111-
"Problematic object instantiation: " + argumentInfo() + stacktrace() + "\n" +
121+
"Problematic object instantiation: " + argumentInfo() + stacktrace + "\n" +
112122
"It leads to the following error during object initialization:\n" +
113123
error.show
114124

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ object Semantic:
11001100
eval(body, thisV, klass)
11011101
}
11021102
given Trace = Trace.empty.add(body)
1103-
res.promote("The function return value is not hot. Found = " + res.show + ". ")
1103+
res.promote("The function return value is not hot. Found = " + res.show + ".")
11041104
}
11051105
if errors.nonEmpty then
11061106
reporter.report(UnsafePromotion(msg, trace.toVector, errors.head))
@@ -1131,7 +1131,7 @@ object Semantic:
11311131
val classRef = warm.klass.appliedRef
11321132
val hasInnerClass = classRef.memberClasses.filter(_.symbol.hasSource).nonEmpty
11331133
if hasInnerClass then
1134-
return PromoteError(msg + "Promotion cancelled as the value contains inner classes. ", trace.toVector) :: Nil
1134+
return PromoteError(msg + "Promotion cancelled as the value contains inner classes.", trace.toVector) :: Nil
11351135

11361136
val obj = warm.objekt
11371137

@@ -1161,12 +1161,12 @@ object Semantic:
11611161
val args = member.info.paramInfoss.flatten.map(_ => ArgInfo(Hot, Trace.empty))
11621162
val res = warm.call(member, args, receiver = warm.klass.typeRef, superType = NoType)
11631163
withTrace(trace.add(member.defTree)) {
1164-
res.promote("Cannot prove that the return value of " + member.show + " is hot. Found = " + res.show + ". ")
1164+
res.promote("Cannot prove that the return value of " + member.show + " is hot. Found = " + res.show + ".")
11651165
}
11661166
else
11671167
val res = warm.select(member, receiver = warm.klass.typeRef)
11681168
withTrace(trace.add(member.defTree)) {
1169-
res.promote("Cannot prove that the field " + member.show + " is hot. Found = " + res.show + ". ")
1169+
res.promote("Cannot prove that the field " + member.show + " is hot. Found = " + res.show + ".")
11701170
}
11711171
end for
11721172

@@ -1281,7 +1281,7 @@ object Semantic:
12811281
/** Utility definition used for better error-reporting of argument errors */
12821282
case class ArgInfo(value: Value, trace: Trace):
12831283
def promote: Contextual[Unit] = withTrace(trace) {
1284-
value.promote("Cannot prove the method argument is hot. Only hot values are safe to leak.\nFound = " + value.show + ". ")
1284+
value.promote("Cannot prove the method argument is hot. Only hot values are safe to leak.\nFound = " + value.show + ".")
12851285
}
12861286

12871287
/** Evaluate an expression with the given value for `this` in a given class `klass`

tests/init/neg/closureLeak.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
11 | l.foreach(a => a.addX(this)) // error
33
| ^^^^^^^^^^^^^^^^^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = Fun { this = ThisRef[class Outer], owner = class Outer }. Calling trace:
5+
| Found = Fun { this = ThisRef[class Outer], owner = class Outer }. Calling trace:
66
| -> class Outer { [ closureLeak.scala:1 ]
77
| ^
88
| -> l.foreach(a => a.addX(this)) // error [ closureLeak.scala:11 ]
99
| ^^^^^^^^^^^^^^^^^
1010
|
1111
| Promoting the value to hot failed due to the following problem:
1212
| Cannot prove the method argument is hot. Only hot values are safe to leak.
13-
| Found = ThisRef[class Outer].
14-
| Non initialized field(s): value p. Calling trace:
13+
| Found = ThisRef[class Outer].
14+
| Non initialized field(s): value p. Promotion trace:
1515
| -> l.foreach(a => a.addX(this)) // error [ closureLeak.scala:11 ]
1616
| ^^^^

tests/init/neg/default-this.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
9 | compare() // error
33
| ^^^^^^^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = ThisRef[class B].
5+
| Found = ThisRef[class B].
66
| Non initialized field(s): value result. Calling trace:
77
| -> class B extends A { [ default-this.scala:6 ]
88
| ^

tests/init/neg/i15459.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
3 | println(this) // error
33
| ^^^^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = ThisRef[class Sub].
5+
| Found = ThisRef[class Sub].
66
| Non initialized field(s): value b. Calling trace:
77
| -> class Sub extends Sup: [ i15459.scala:5 ]
88
| ^

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@
1212
| ^^^^^^^^^^^^^^^
1313
|
1414
| Promoting the value to hot failed due to the following problem:
15-
| Cannot prove that the field value a is hot. Found = Cold.
15+
| Cannot prove that the field value a is hot. Found = Cold. Promotion trace:
16+
| -> class B(a: A) { [ inherit-non-hot.scala:10 ]
17+
| ^^^^

tests/init/neg/inlined-method.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
8 | scala.runtime.Scala3RunTime.assertFailed(message) // error
33
| ^^^^^^^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = ThisRef[class InlineError].
5+
| Found = ThisRef[class InlineError].
66
| Non initialized field(s): value v. Calling trace:
77
| -> class InlineError { [ inlined-method.scala:1 ]
88
| ^

tests/init/neg/inner-first.check

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
3 | println(this) // error
33
| ^^^^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = ThisRef[class B].
5+
| Found = ThisRef[class B].
66
| Non initialized field(s): value n. Calling trace:
77
| -> class B: [ inner-first.scala:2 ]
88
| ^

tests/init/neg/promotion-loop.check

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
16 | println(b) // error
33
| ^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = Warm[class B] { outer = ThisRef[class Test] }. Calling trace:
5+
| Found = Warm[class B] { outer = ThisRef[class Test] }. Calling trace:
66
| -> class Test { test => [ promotion-loop.scala:1 ]
77
| ^
88
| -> println(b) // error [ promotion-loop.scala:16 ]
99
| ^
1010
|
1111
| Promoting the value to hot failed due to the following problem:
12-
| Cannot prove that the field value outer is hot. Found = ThisRef[class Test].
13-
| Non initialized field(s): value n.
12+
| Cannot prove that the field value outer is hot. Found = ThisRef[class Test].
13+
| Non initialized field(s): value n. Promotion trace:
14+
| -> val outer = test [ promotion-loop.scala:12 ]
15+
| ^^^^^^^^^^^^^^^^

tests/init/neg/t3273.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@
22
4 | val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error
33
| ^^^^^^^^^^^^^^^
44
| Cannot prove the method argument is hot. Only hot values are safe to leak.
5-
| Found = Fun { this = ThisRef[object Test], owner = object Test }. Calling trace:
5+
| Found = Fun { this = ThisRef[object Test], owner = object Test }. Calling trace:
66
| -> object Test { [ t3273.scala:3 ]
77
| ^
88
| -> val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error [ t3273.scala:4 ]
99
| ^^^^^^^^^^^^^^^
1010
|
1111
| Promoting the value to hot failed due to the following problem:
12-
| Access non-initialized value num1. Calling trace:
12+
| Access non-initialized value num1. Promotion trace:
1313
| -> val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error [ t3273.scala:4 ]
1414
| ^^^^
1515
-- Error: tests/init/neg/t3273.scala:5:61 ------------------------------------------------------------------------------
1616
5 | val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error
1717
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1818
| Cannot prove the method argument is hot. Only hot values are safe to leak.
19-
| Found = Fun { this = ThisRef[object Test], owner = object Test }. Calling trace:
19+
| Found = Fun { this = ThisRef[object Test], owner = object Test }. Calling trace:
2020
| -> object Test { [ t3273.scala:3 ]
2121
| ^
2222
| -> val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error [ t3273.scala:5 ]
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2424
|
2525
| Promoting the value to hot failed due to the following problem:
26-
| Access non-initialized value num2. Calling trace:
26+
| Access non-initialized value num2. Promotion trace:
2727
| -> val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error [ t3273.scala:5 ]
2828
| ^^^^

0 commit comments

Comments
 (0)