Skip to content
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

Global Initialization checker: Widen values in assignment #21512

Merged
merged 2 commits into from
Sep 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions compiler/src/dotty/tools/dotc/transform/init/Objects.scala
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ class Objects(using Context @constructorOnly):

/**
* Handle new expression `new p.C(args)`.
* The actual instance might be cached without running the constructor.
* The actual instance might be cached without running the constructor.
* See tests/init-global/pos/cache-constructor.scala
*
* @param outer The value for `p`.
Expand Down Expand Up @@ -1226,11 +1226,12 @@ class Objects(using Context @constructorOnly):
extendTrace(id) { evalType(prefix, thisV, klass) }

val value = eval(rhs, thisV, klass)
val widened = widenEscapedValue(value, rhs)

if isLocal then
writeLocal(thisV, lhs.symbol, value)
writeLocal(thisV, lhs.symbol, widened)
else
withTrace(trace2) { assign(receiver, lhs.symbol, value, rhs.tpe) }
withTrace(trace2) { assign(receiver, lhs.symbol, widened, rhs.tpe) }

case closureDef(ddef) =>
Fun(ddef, thisV, klass, summon[Env.Data])
Expand Down Expand Up @@ -1568,6 +1569,36 @@ class Objects(using Context @constructorOnly):
throw new Exception("unexpected type: " + tp + ", Trace:\n" + Trace.show)
}

/** Widen the escaped value (a method argument or rhs of an assignment)
*
* The default widening is 1 for most values, 2 for function values.
* User-specified widening annotations are repected.
*/
def widenEscapedValue(value: Value, annotatedTree: Tree): Contextual[Value] =
def parseAnnotation: Option[Int] =
annotatedTree.tpe.getAnnotation(defn.InitWidenAnnot).flatMap: annot =>
annot.argument(0).get match
case arg @ Literal(c: Constants.Constant) =>
val height = c.intValue
if height < 0 then
report.warning("The argument should be positive", arg)
None
else
Some(height)
case arg =>
report.warning("The argument should be a constant integer value", arg)
None
end parseAnnotation

parseAnnotation match
case Some(i) =>
value.widen(i)

case None =>
if value.isInstanceOf[Fun]
then value.widen(2)
else value.widen(1)

/** Evaluate arguments of methods and constructors */
def evalArgs(args: List[Arg], thisV: ThisValue, klass: ClassSymbol): Contextual[List[ArgInfo]] =
val argInfos = new mutable.ArrayBuffer[ArgInfo]
Expand All @@ -1578,23 +1609,7 @@ class Objects(using Context @constructorOnly):
else
eval(arg.tree, thisV, klass)

val widened =
arg.tree.tpe.getAnnotation(defn.InitWidenAnnot) match
case Some(annot) =>
annot.argument(0).get match
case arg @ Literal(c: Constants.Constant) =>
val height = c.intValue
if height < 0 then
report.warning("The argument should be positive", arg)
res.widen(1)
else
res.widen(c.intValue)
case arg =>
report.warning("The argument should be a constant integer value", arg)
res.widen(1)
case _ =>
if res.isInstanceOf[Fun] then res.widen(2) else res.widen(1)

val widened = widenEscapedValue(res, arg.tree)
argInfos += ArgInfo(widened, trace.add(arg.tree), arg.tree)
}
argInfos.toList
Expand Down
Loading