Skip to content

Commit ec094fe

Browse files
authored
Global Initialization checker: Widen values in assignment (#21512)
Global Initialization checker: Widen values in assignment
2 parents 0e17117 + 76498dc commit ec094fe

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

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

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ class Objects(using Context @constructorOnly):
913913

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

12311231
val value = eval(rhs, thisV, klass)
1232+
val widened = widenEscapedValue(value, rhs)
12321233

12331234
if isLocal then
1234-
writeLocal(thisV, lhs.symbol, value)
1235+
writeLocal(thisV, lhs.symbol, widened)
12351236
else
1236-
withTrace(trace2) { assign(receiver, lhs.symbol, value, rhs.tpe) }
1237+
withTrace(trace2) { assign(receiver, lhs.symbol, widened, rhs.tpe) }
12371238

12381239
case closureDef(ddef) =>
12391240
Fun(ddef, thisV, klass, summon[Env.Data])
@@ -1571,6 +1572,36 @@ class Objects(using Context @constructorOnly):
15711572
throw new Exception("unexpected type: " + tp + ", Trace:\n" + Trace.show)
15721573
}
15731574

1575+
/** Widen the escaped value (a method argument or rhs of an assignment)
1576+
*
1577+
* The default widening is 1 for most values, 2 for function values.
1578+
* User-specified widening annotations are repected.
1579+
*/
1580+
def widenEscapedValue(value: Value, annotatedTree: Tree): Contextual[Value] =
1581+
def parseAnnotation: Option[Int] =
1582+
annotatedTree.tpe.getAnnotation(defn.InitWidenAnnot).flatMap: annot =>
1583+
annot.argument(0).get match
1584+
case arg @ Literal(c: Constants.Constant) =>
1585+
val height = c.intValue
1586+
if height < 0 then
1587+
report.warning("The argument should be positive", arg)
1588+
None
1589+
else
1590+
Some(height)
1591+
case arg =>
1592+
report.warning("The argument should be a constant integer value", arg)
1593+
None
1594+
end parseAnnotation
1595+
1596+
parseAnnotation match
1597+
case Some(i) =>
1598+
value.widen(i)
1599+
1600+
case None =>
1601+
if value.isInstanceOf[Fun]
1602+
then value.widen(2)
1603+
else value.widen(1)
1604+
15741605
/** Evaluate arguments of methods and constructors */
15751606
def evalArgs(args: List[Arg], thisV: ThisValue, klass: ClassSymbol): Contextual[List[ArgInfo]] =
15761607
val argInfos = new mutable.ArrayBuffer[ArgInfo]
@@ -1581,23 +1612,7 @@ class Objects(using Context @constructorOnly):
15811612
else
15821613
eval(arg.tree, thisV, klass)
15831614

1584-
val widened =
1585-
arg.tree.tpe.getAnnotation(defn.InitWidenAnnot) match
1586-
case Some(annot) =>
1587-
annot.argument(0).get match
1588-
case arg @ Literal(c: Constants.Constant) =>
1589-
val height = c.intValue
1590-
if height < 0 then
1591-
report.warning("The argument should be positive", arg)
1592-
res.widen(1)
1593-
else
1594-
res.widen(c.intValue)
1595-
case arg =>
1596-
report.warning("The argument should be a constant integer value", arg)
1597-
res.widen(1)
1598-
case _ =>
1599-
if res.isInstanceOf[Fun] then res.widen(2) else res.widen(1)
1600-
1615+
val widened = widenEscapedValue(res, arg.tree)
16011616
argInfos += ArgInfo(widened, trace.add(arg.tree), arg.tree)
16021617
}
16031618
argInfos.toList

0 commit comments

Comments
 (0)