Skip to content

Fix remaining initialization warnings in bootstrapping #15682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jul 17, 2022
116 changes: 64 additions & 52 deletions compiler/src/dotty/tools/dotc/transform/init/Errors.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,107 +6,119 @@ package init
import ast.tpd._
import core._
import util.SourcePosition
import util.Property
import Decorators._, printing.SyntaxHighlighting
import Types._, Symbols._, Contexts._

import scala.collection.mutable

object Errors:
private val IsFromPromotion = new Property.Key[Boolean]

sealed trait Error:
def trace: Seq[Tree]
def show(using Context): String

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

def stacktrace(using Context): String =
val preamble: String =
if ctx.property(IsFromPromotion).nonEmpty
then " Promotion trace:\n"
else " Calling trace:\n"
buildStacktrace(trace, preamble)

def issue(using Context): Unit =
report.warning(show, this.pos)
end Error

def buildStacktrace(trace: Seq[Tree], preamble: String)(using Context): String = if trace.isEmpty then "" else preamble + {
var lastLineNum = -1
var lines: mutable.ArrayBuffer[String] = new mutable.ArrayBuffer
trace.foreach { tree =>
val pos = tree.sourcePos
val prefix = "-> "
val line =
if pos.source.exists then
val loc = "[ " + pos.source.file.name + ":" + (pos.line + 1) + " ]"
val code = SyntaxHighlighting.highlight(pos.lineContent.trim.nn)
i"$code\t$loc"
else
tree.show
val positionMarkerLine =
if pos.exists && pos.source.exists then
positionMarker(pos)
else ""

// always use the more precise trace location
if lastLineNum == pos.line then
lines.dropRightInPlace(1)

def stacktrace(preamble: String = " Calling trace:\n")(using Context): String = if trace.isEmpty then "" else preamble + {
var lastLineNum = -1
var lines: mutable.ArrayBuffer[String] = new mutable.ArrayBuffer
trace.foreach { tree =>
val pos = tree.sourcePos
val prefix = "-> "
val line =
if pos.source.exists then
val loc = "[ " + pos.source.file.name + ":" + (pos.line + 1) + " ]"
val code = SyntaxHighlighting.highlight(pos.lineContent.trim.nn)
i"$code\t$loc"
else
tree.show
val positionMarkerLine =
if pos.exists && pos.source.exists then
positionMarker(pos)
else ""

// always use the more precise trace location
if lastLineNum == pos.line then
lines.dropRightInPlace(1)

lines += (prefix + line + "\n" + positionMarkerLine)

lastLineNum = pos.line
}
val sb = new StringBuilder
for line <- lines do sb.append(line)
sb.toString
lines += (prefix + line + "\n" + positionMarkerLine)

lastLineNum = pos.line
}
val sb = new StringBuilder
for line <- lines do sb.append(line)
sb.toString
}

/** Used to underline source positions in the stack trace
* pos.source must exist
*/
private def positionMarker(pos: SourcePosition): String =
val trimmed = pos.lineContent.takeWhile(c => c.isWhitespace).length
val padding = pos.startColumnPadding.substring(trimmed).nn + " "
val carets =
if (pos.startLine == pos.endLine)
"^" * math.max(1, pos.endColumn - pos.startColumn)
else "^"
/** Used to underline source positions in the stack trace
* pos.source must exist
*/
private def positionMarker(pos: SourcePosition): String =
val trimmed = pos.lineContent.takeWhile(c => c.isWhitespace).length
val padding = pos.startColumnPadding.substring(trimmed).nn + " "
val carets =
if (pos.startLine == pos.endLine)
"^" * math.max(1, pos.endColumn - pos.startColumn)
else "^"

s"$padding$carets\n"
s"$padding$carets\n"

override def toString() = this.getClass.getName.nn
end Error
override def toString() = this.getClass.getName.nn

/** Access non-initialized field */
case class AccessNonInit(field: Symbol, trace: Seq[Tree]) extends Error:
def source: Tree = trace.last
def show(using Context): String =
"Access non-initialized " + field.show + "." + stacktrace()
"Access non-initialized " + field.show + "." + stacktrace

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

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

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

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

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

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

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

Expand All @@ -129,5 +141,5 @@ object Errors:
acc + text2
}
val verb = if multiple then " are " else " is "
val adjective = "not fully initialized."
val adjective = "not hot."
subject + verb + adjective
Loading