@@ -6,107 +6,119 @@ package init
6
6
import ast .tpd ._
7
7
import core ._
8
8
import util .SourcePosition
9
+ import util .Property
9
10
import Decorators ._ , printing .SyntaxHighlighting
10
11
import Types ._ , Symbols ._ , Contexts ._
11
12
12
13
import scala .collection .mutable
13
14
14
15
object Errors :
16
+ private val IsFromPromotion = new Property .Key [Boolean ]
17
+
15
18
sealed trait Error :
16
19
def trace : Seq [Tree ]
17
20
def show (using Context ): String
18
21
19
22
def pos (using Context ): SourcePosition = trace.last.sourcePos
20
23
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)
30
+
21
31
def issue (using Context ): Unit =
22
32
report.warning(show, this .pos)
33
+ end Error
34
+
35
+ def buildStacktrace (trace : Seq [Tree ], preamble : String )(using Context ): String = if trace.isEmpty then " " else preamble + {
36
+ var lastLineNum = - 1
37
+ var lines : mutable.ArrayBuffer [String ] = new mutable.ArrayBuffer
38
+ trace.foreach { tree =>
39
+ val pos = tree.sourcePos
40
+ val prefix = " -> "
41
+ val line =
42
+ if pos.source.exists then
43
+ val loc = " [ " + pos.source.file.name + " :" + (pos.line + 1 ) + " ]"
44
+ val code = SyntaxHighlighting .highlight(pos.lineContent.trim.nn)
45
+ i " $code\t $loc"
46
+ else
47
+ tree.show
48
+ val positionMarkerLine =
49
+ if pos.exists && pos.source.exists then
50
+ positionMarker(pos)
51
+ else " "
52
+
53
+ // always use the more precise trace location
54
+ if lastLineNum == pos.line then
55
+ lines.dropRightInPlace(1 )
23
56
24
- def stacktrace (preamble : String = " Calling trace:\n " )(using Context ): String = if trace.isEmpty then " " else preamble + {
25
- var lastLineNum = - 1
26
- var lines : mutable.ArrayBuffer [String ] = new mutable.ArrayBuffer
27
- trace.foreach { tree =>
28
- val pos = tree.sourcePos
29
- val prefix = " -> "
30
- val line =
31
- if pos.source.exists then
32
- val loc = " [ " + pos.source.file.name + " :" + (pos.line + 1 ) + " ]"
33
- val code = SyntaxHighlighting .highlight(pos.lineContent.trim.nn)
34
- i " $code\t $loc"
35
- else
36
- tree.show
37
- val positionMarkerLine =
38
- if pos.exists && pos.source.exists then
39
- positionMarker(pos)
40
- else " "
41
-
42
- // always use the more precise trace location
43
- if lastLineNum == pos.line then
44
- lines.dropRightInPlace(1 )
45
-
46
- lines += (prefix + line + " \n " + positionMarkerLine)
47
-
48
- lastLineNum = pos.line
49
- }
50
- val sb = new StringBuilder
51
- for line <- lines do sb.append(line)
52
- sb.toString
57
+ lines += (prefix + line + " \n " + positionMarkerLine)
58
+
59
+ lastLineNum = pos.line
53
60
}
61
+ val sb = new StringBuilder
62
+ for line <- lines do sb.append(line)
63
+ sb.toString
64
+ }
54
65
55
- /** Used to underline source positions in the stack trace
56
- * pos.source must exist
57
- */
58
- private def positionMarker (pos : SourcePosition ): String =
59
- val trimmed = pos.lineContent.takeWhile(c => c.isWhitespace).length
60
- val padding = pos.startColumnPadding.substring(trimmed).nn + " "
61
- val carets =
62
- if (pos.startLine == pos.endLine)
63
- " ^" * math.max(1 , pos.endColumn - pos.startColumn)
64
- else " ^"
66
+ /** Used to underline source positions in the stack trace
67
+ * pos.source must exist
68
+ */
69
+ private def positionMarker (pos : SourcePosition ): String =
70
+ val trimmed = pos.lineContent.takeWhile(c => c.isWhitespace).length
71
+ val padding = pos.startColumnPadding.substring(trimmed).nn + " "
72
+ val carets =
73
+ if (pos.startLine == pos.endLine)
74
+ " ^" * math.max(1 , pos.endColumn - pos.startColumn)
75
+ else " ^"
65
76
66
- s " $padding$carets\n "
77
+ s " $padding$carets\n "
67
78
68
- override def toString () = this .getClass.getName.nn
69
- end Error
79
+ override def toString () = this .getClass.getName.nn
70
80
71
81
/** Access non-initialized field */
72
82
case class AccessNonInit (field : Symbol , trace : Seq [Tree ]) extends Error :
73
83
def source : Tree = trace.last
74
84
def show (using Context ): String =
75
- " Access non-initialized " + field.show + " ." + stacktrace()
85
+ " Access non-initialized " + field.show + " ." + stacktrace
76
86
77
87
override def pos (using Context ): SourcePosition = field.sourcePos
78
88
79
89
/** Promote a value under initialization to fully-initialized */
80
90
case class PromoteError (msg : String , trace : Seq [Tree ]) extends Error :
81
- def show (using Context ): String = msg + stacktrace()
91
+ def show (using Context ): String = msg + stacktrace
82
92
83
93
case class AccessCold (field : Symbol , trace : Seq [Tree ]) extends Error :
84
94
def show (using Context ): String =
85
- " Access field " + field.show + " on a cold object." + stacktrace()
95
+ " Access field " + field.show + " on a cold object." + stacktrace
86
96
87
97
case class CallCold (meth : Symbol , trace : Seq [Tree ]) extends Error :
88
98
def show (using Context ): String =
89
- " Call method " + meth.show + " on a cold object." + stacktrace()
99
+ " Call method " + meth.show + " on a cold object." + stacktrace
90
100
91
101
case class CallUnknown (meth : Symbol , trace : Seq [Tree ]) extends Error :
92
102
def show (using Context ): String =
93
103
val prefix = if meth.is(Flags .Method ) then " Calling the external method " else " Accessing the external field"
94
- prefix + meth.show + " may cause initialization errors." + stacktrace()
104
+ prefix + meth.show + " may cause initialization errors." + stacktrace
95
105
96
106
/** Promote a value under initialization to fully-initialized */
97
107
case class UnsafePromotion (msg : String , trace : Seq [Tree ], error : Error ) extends Error :
98
108
def show (using Context ): String =
99
- msg + stacktrace() + " \n " +
100
- " Promoting the value to fully initialized failed due to the following problem:\n " +
101
- 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
+ }
102
114
103
115
/** Unsafe leaking a non-hot value as constructor arguments
104
116
*
105
117
* Invariant: argsIndices.nonEmpty
106
118
*/
107
119
case class UnsafeLeaking (trace : Seq [Tree ], error : Error , nonHotOuterClass : Symbol , argsIndices : List [Int ]) extends Error :
108
120
def show (using Context ): String =
109
- " Problematic object instantiation: " + argumentInfo() + stacktrace() + " \n " +
121
+ " Problematic object instantiation: " + argumentInfo() + stacktrace + " \n " +
110
122
" It leads to the following error during object initialization:\n " +
111
123
error.show
112
124
@@ -129,5 +141,5 @@ object Errors:
129
141
acc + text2
130
142
}
131
143
val verb = if multiple then " are " else " is "
132
- val adjective = " not fully initialized ."
144
+ val adjective = " not hot ."
133
145
subject + verb + adjective
0 commit comments