Skip to content

Commit 9ef218b

Browse files
committed
Don't chain promotion
1 parent 0181ef9 commit 9ef218b

File tree

9 files changed

+55
-50
lines changed

9 files changed

+55
-50
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ object Errors {
8585
report.warning(show + stacktrace, field.srcPos)
8686
}
8787

88-
/** Promote `this` under initialization to fully-initialized */
88+
/** Promote a value under initialization to fully-initialized */
8989
case class PromoteError(msg: String, source: Tree, trace: Seq[Tree]) extends Error {
90-
def show(using Context): String = "Cannot prove that the value is fully initialized. " + msg + "."
90+
def show(using Context): String = msg
9191
}
9292

9393
case class AccessCold(field: Symbol, source: Tree, trace: Seq[Tree]) extends Error {
@@ -114,8 +114,8 @@ object Errors {
114114

115115
def show(using Context): String = {
116116
var index = 0
117-
"Cannot prove that the value is fully initialized. " + msg + ".\n" + stacktrace +
118-
"\nThe unsafe promotion may cause the following problem:\n" +
117+
msg + "\n" + stacktrace + "\n" +
118+
"Promoting the value to fully initialized failed due to the following problem:\n" +
119119
errors.head.show + errors.head.stacktrace
120120
}
121121
}

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

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -918,20 +918,21 @@ object Semantic {
918918

919919
case warm: Warm =>
920920
if promoted.contains(warm) then Nil
921-
else {
921+
else
922922
promoted.add(warm)
923923
val errors = warm.tryPromote(msg, source)
924924
if errors.nonEmpty then promoted.remove(warm)
925925
errors
926-
}
927926

928927
case fun @ Fun(body, thisV, klass, env) =>
929928
if promoted.contains(fun) then Nil
930929
else
931930
val res = withEnv(env) { eval(body, thisV, klass) }
932-
val errors2 = res.value.promote(msg, source)
933-
if (res.errors.nonEmpty || errors2.nonEmpty)
934-
UnsafePromotion(msg, source, trace.toVector, res.errors ++ errors2) :: Nil
931+
val errors =
932+
if res.value == Hot then res.errors
933+
else res.errors :+ PromoteError("The function return value is not fully initialized.", source, trace.toVector)
934+
if (res.errors.nonEmpty || res.value != Hot)
935+
UnsafePromotion(msg, source, trace.toVector, errors) :: Nil
935936
else
936937
promoted.add(fun)
937938
Nil
@@ -966,20 +967,24 @@ object Semantic {
966967

967968
val buffer = new mutable.ArrayBuffer[Error]
968969

970+
def checkHot(res: Result, msg: String, source: Tree): Errors =
971+
if res.value == Hot || promoted.contains(res.value) then res.errors
972+
else res.errors :+ PromoteError(msg, source, trace.toVector)
973+
969974
warm.klass.baseClasses.exists { klass =>
970975
klass.hasSource && klass.info.decls.exists { member =>
971976
if !member.isType && !member.isConstructor && member.hasSource && !member.is(Flags.Deferred) then
972-
if member.is(Flags.Method) then
977+
if member.is(Flags.Method, butNot = Flags.Accessor) then
973978
val trace2 = trace.add(source)
974979
locally {
975980
given Trace = trace2
976981
val args = member.info.paramInfoss.flatten.map(_ => ArgInfo(Hot, EmptyTree))
977982
val res = warm.call(member, args, receiver = NoType, superType = NoType, source = member.defTree)
978-
buffer ++= res.ensureHot(msg, source).errors
983+
buffer ++= checkHot(res, "Cannot prove that the return value of " + member + " is fully initialized.", source)
979984
}
980985
else
981986
val res = warm.select(member, source)
982-
buffer ++= res.ensureHot(msg, source).errors
987+
buffer ++= checkHot(res, "Cannot prove that the field " + member + " is fully initialized.", source)
983988
buffer.nonEmpty
984989
}
985990
}
@@ -1076,7 +1081,7 @@ object Semantic {
10761081

10771082
/** Utility definition used for better error-reporting of argument errors */
10781083
case class ArgInfo(value: Value, source: Tree) {
1079-
def promote: Contextual[List[Error]] = value.promote("Only initialized values may be used as arguments", source)
1084+
def promote: Contextual[List[Error]] = value.promote("Cannot prove the argument is fully initialized.", source)
10801085
}
10811086

10821087
/** Evaluate an expression with the given value for `this` in a given class `klass`
@@ -1206,9 +1211,9 @@ object Semantic {
12061211
lhs match
12071212
case Select(qual, _) =>
12081213
val res = eval(qual, thisV, klass)
1209-
eval(rhs, thisV, klass).ensureHot("May only assign fully initialized value", rhs) ++ res.errors
1214+
eval(rhs, thisV, klass).ensureHot("May only assign fully initialized value.", rhs) ++ res.errors
12101215
case id: Ident =>
1211-
eval(rhs, thisV, klass).ensureHot("May only assign fully initialized value", rhs)
1216+
eval(rhs, thisV, klass).ensureHot("May only assign fully initialized value.", rhs)
12121217

12131218
case closureDef(ddef) =>
12141219
val value = Fun(ddef.rhs, thisV, klass, env)
@@ -1233,14 +1238,14 @@ object Semantic {
12331238
else eval(arg, thisV, klass)
12341239

12351240
case Match(selector, cases) =>
1236-
val res1 = eval(selector, thisV, klass).ensureHot("The value to be matched needs to be fully initialized", selector)
1241+
val res1 = eval(selector, thisV, klass).ensureHot("The value to be matched needs to be fully initialized.", selector)
12371242
val ress = eval(cases.map(_.body), thisV, klass)
12381243
val value = ress.map(_.value).join
12391244
val errors = res1.errors ++ ress.flatMap(_.errors)
12401245
Result(value, errors)
12411246

12421247
case Return(expr, from) =>
1243-
eval(expr, thisV, klass).ensureHot("return expression may only be initialized value", expr)
1248+
eval(expr, thisV, klass).ensureHot("return expression may only be initialized value.", expr)
12441249

12451250
case WhileDo(cond, body) =>
12461251
val ress = eval(cond :: body :: Nil, thisV, klass)

tests/init/neg/closureLeak.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- Error: tests/init/neg/closureLeak.scala:11:14 -----------------------------------------------------------------------
22
11 | l.foreach(a => a.addX(this)) // error
33
| ^^^^^^^^^^^^^^^^^
4-
| Cannot prove that the value is fully initialized. Only initialized values may be used as arguments.
4+
| Cannot prove the argument is fully initialized.
55
|
6-
| The unsafe promotion may cause the following problem:
7-
| Cannot prove that the value is fully initialized. Only initialized values may be used as arguments.
6+
| Promoting the value to fully initialized failed due to the following problem:
7+
| Cannot prove the argument is fully initialized.

tests/init/neg/default-this.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- Error: tests/init/neg/default-this.scala:9:8 ------------------------------------------------------------------------
22
9 | compare() // error
33
| ^^^^^^^
4-
|Cannot prove that the value is fully initialized. Only initialized values may be used as arguments. Calling trace:
5-
|-> val result = updateThenCompare(5) [ default-this.scala:11 ]
6-
| ^^^^^^^^^^^^^^^^^^^^
4+
| Cannot prove the argument is fully initialized. Calling trace:
5+
| -> val result = updateThenCompare(5) [ default-this.scala:11 ]
6+
| ^^^^^^^^^^^^^^^^^^^^

tests/init/neg/inherit-non-hot.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- Error: tests/init/neg/inherit-non-hot.scala:6:34 --------------------------------------------------------------------
22
6 | if b == null then b = new B(this) // error
33
| ^^^^^^^^^^^
4-
| Cannot prove that the value is fully initialized. May only assign fully initialized value.
4+
| May only assign fully initialized value.
55
| Calling trace:
66
| -> val c = new C [ inherit-non-hot.scala:19 ]
77
| ^^^^^
@@ -10,7 +10,7 @@
1010
| -> val bAgain = toB.getBAgain [ inherit-non-hot.scala:16 ]
1111
| ^^^
1212
|
13-
| The unsafe promotion may cause the following problem:
13+
| Promoting the value to fully initialized failed due to the following problem:
1414
| Call method Foo.B.this.aCopy.toB on a value with an unknown initialization. Calling trace:
1515
| -> val c = new C [ inherit-non-hot.scala:19 ]
1616
| ^^^^^

tests/init/neg/inlined-method.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- Error: tests/init/neg/inlined-method.scala:8:45 ---------------------------------------------------------------------
22
8 | scala.runtime.Scala3RunTime.assertFailed(message) // error
33
| ^^^^^^^
4-
|Cannot prove that the value is fully initialized. Only initialized values may be used as arguments. Calling trace:
5-
|-> Assertion.failAssert(this) [ inlined-method.scala:2 ]
6-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
| Cannot prove the argument is fully initialized. Calling trace:
5+
| -> Assertion.failAssert(this) [ inlined-method.scala:2 ]
6+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/init/neg/local-warm4.check

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
-- Error: tests/init/neg/local-warm4.scala:18:20 -----------------------------------------------------------------------
22
18 | a = newA // error
33
| ^^^^
4-
| Cannot prove that the value is fully initialized. May only assign fully initialized value. Calling trace:
5-
| -> val a = new A(5) [ local-warm4.scala:26 ]
6-
| ^^^^^^^^
7-
| -> class A(x: Int) extends Foo(x) { [ local-warm4.scala:6 ]
8-
| ^
9-
| -> val b = new B(y) [ local-warm4.scala:10 ]
10-
| ^^^^^^^^
11-
| -> class B(x: Int) extends A(x) { [ local-warm4.scala:13 ]
12-
| ^
13-
| -> class A(x: Int) extends Foo(x) { [ local-warm4.scala:6 ]
14-
| ^
15-
| -> increment() [ local-warm4.scala:9 ]
16-
| ^^^^^^^^^^^
17-
| -> updateA() [ local-warm4.scala:21 ]
18-
| ^^^^^^^^^
4+
| May only assign fully initialized value. Calling trace:
5+
| -> val a = new A(5) [ local-warm4.scala:26 ]
6+
| ^^^^^^^^
7+
| -> class A(x: Int) extends Foo(x) { [ local-warm4.scala:6 ]
8+
| ^
9+
| -> val b = new B(y) [ local-warm4.scala:10 ]
10+
| ^^^^^^^^
11+
| -> class B(x: Int) extends A(x) { [ local-warm4.scala:13 ]
12+
| ^
13+
| -> class A(x: Int) extends Foo(x) { [ local-warm4.scala:6 ]
14+
| ^
15+
| -> increment() [ local-warm4.scala:9 ]
16+
| ^^^^^^^^^^^
17+
| -> updateA() [ local-warm4.scala:21 ]
18+
| ^^^^^^^^^

tests/init/neg/promotion-loop.check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- Error: tests/init/neg/promotion-loop.scala:16:10 --------------------------------------------------------------------
22
16 | println(b) // error
33
| ^
4-
| Cannot prove that the value is fully initialized. Only initialized values may be used as arguments.
4+
| Cannot prove the argument is fully initialized.
55
|
6-
| The unsafe promotion may cause the following problem:
7-
| Cannot prove that the value is fully initialized. Only initialized values may be used as arguments.
6+
| Promoting the value to fully initialized failed due to the following problem:
7+
| Cannot prove that the field val outer is fully initialized.

tests/init/neg/t3273.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
-- Error: tests/init/neg/t3273.scala:4:42 ------------------------------------------------------------------------------
22
4 | val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error
33
| ^^^^^^^^^^^^^^^
4-
| Cannot prove that the value is fully initialized. Only initialized values may be used as arguments.
4+
| Cannot prove the argument is fully initialized.
55
|
6-
| The unsafe promotion may cause the following problem:
6+
| Promoting the value to fully initialized failed due to the following problem:
77
| Access non-initialized value num1. Calling trace:
88
| -> val num1: LazyList[Int] = 1 #:: num1.map(_ + 1) // error [ t3273.scala:4 ]
99
| ^^^^
1010
-- Error: tests/init/neg/t3273.scala:5:61 ------------------------------------------------------------------------------
1111
5 | val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13-
| Cannot prove that the value is fully initialized. Only initialized values may be used as arguments.
13+
| Cannot prove the argument is fully initialized.
1414
|
15-
| The unsafe promotion may cause the following problem:
15+
| Promoting the value to fully initialized failed due to the following problem:
1616
| Access non-initialized value num2. Calling trace:
1717
| -> val num2: LazyList[Int] = 1 #:: num2.iterator.map(_ + 1).to(LazyList) // error [ t3273.scala:5 ]
1818
| ^^^^

0 commit comments

Comments
 (0)