@@ -6,107 +6,119 @@ package init
66import ast .tpd ._
77import core ._
88import util .SourcePosition
9+ import util .Property
910import Decorators ._ , printing .SyntaxHighlighting
1011import Types ._ , Symbols ._ , Contexts ._
1112
1213import scala .collection .mutable
1314
1415object 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
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+
2131 def issue (using Context ): Unit =
2232 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 )
2356
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
5360 }
61+ val sb = new StringBuilder
62+ for line <- lines do sb.append(line)
63+ sb.toString
64+ }
5465
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 " ^"
6576
66- s " $padding$carets\n "
77+ s " $padding$carets\n "
6778
68- override def toString () = this .getClass.getName.nn
69- end Error
79+ override def toString () = this .getClass.getName.nn
7080
7181 /** Access non-initialized field */
7282 case class AccessNonInit (field : Symbol , trace : Seq [Tree ]) extends Error :
7383 def source : Tree = trace.last
7484 def show (using Context ): String =
75- " Access non-initialized " + field.show + " ." + stacktrace()
85+ " Access non-initialized " + field.show + " ." + stacktrace
7686
7787 override def pos (using Context ): SourcePosition = field.sourcePos
7888
7989 /** Promote a value under initialization to fully-initialized */
8090 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
8292
8393 case class AccessCold (field : Symbol , trace : Seq [Tree ]) extends Error :
8494 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
8696
8797 case class CallCold (meth : Symbol , trace : Seq [Tree ]) extends Error :
8898 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
90100
91101 case class CallUnknown (meth : Symbol , trace : Seq [Tree ]) extends Error :
92102 def show (using Context ): String =
93103 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
95105
96106 /** Promote a value under initialization to fully-initialized */
97107 case class UnsafePromotion (msg : String , trace : Seq [Tree ], error : Error ) extends Error :
98108 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+ }
102114
103115 /** Unsafe leaking a non-hot value as constructor arguments
104116 *
105117 * Invariant: argsIndices.nonEmpty
106118 */
107119 case class UnsafeLeaking (trace : Seq [Tree ], error : Error , nonHotOuterClass : Symbol , argsIndices : List [Int ]) extends Error :
108120 def show (using Context ): String =
109- " Problematic object instantiation: " + argumentInfo() + stacktrace() + " \n " +
121+ " Problematic object instantiation: " + argumentInfo() + stacktrace + " \n " +
110122 " It leads to the following error during object initialization:\n " +
111123 error.show
112124
@@ -129,5 +141,5 @@ object Errors:
129141 acc + text2
130142 }
131143 val verb = if multiple then " are " else " is "
132- val adjective = " not fully initialized ."
144+ val adjective = " not hot ."
133145 subject + verb + adjective
0 commit comments