Skip to content

Commit deb85b7

Browse files
committed
Add special case to init checker to always allow certain methods
Closes #14275 - Treats mehtods `ne`, `eq`, `isInstanceOf`, and `asInstanceOf` as safe to call, regardless of initialization Review by @liufengyun
1 parent dbf0067 commit deb85b7

File tree

5 files changed

+56
-0
lines changed

5 files changed

+56
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,8 +596,16 @@ object Semantic {
596596
&& meth.owner.is(Flags.Module)
597597
&& meth.owner.companionClass.is(Flags.Case)
598598

599+
def isAlwaysSafe(meth: Symbol) =
600+
(meth eq defn.Object_eq)
601+
|| (meth eq defn.Object_ne)
602+
|| (meth eq defn.Any_isInstanceOf)
603+
604+
599605
// fast track if the current object is already initialized
600606
if promoted.isCurrentObjectPromoted then Result(Hot, Nil)
607+
else if isAlwaysSafe(meth) then Result(Hot, Nil)
608+
else if meth eq defn.Any_asInstanceOf then Result(value, Nil)
601609
else value match {
602610
case Hot =>
603611
if isSyntheticApply(meth) then
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- Error: tests/init/neg/as-instance-of-cold-field-access.scala:3:44 ---------------------------------------------------
2+
3 | if (o.asInstanceOf[MyAsInstanceOfClass].oRef ne null) o // error
3+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4+
|Access field MyAsInstanceOfClass.this.o.asInstanceOf[MyAsInstanceOfClass].oRef on a value with an unknown initialization status. Calling trace:
5+
| -> else new MyAsInstanceOfClass(this) [ as-instance-of-cold-field-access.scala:4 ]
6+
| -> final class MyAsInstanceOfClass(o: MyAsInstanceOfClass) { [ as-instance-of-cold-field-access.scala:1 ]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
final class MyAsInstanceOfClass(o: MyAsInstanceOfClass) {
2+
val other: MyAsInstanceOfClass = {
3+
if (o.asInstanceOf[MyAsInstanceOfClass].oRef ne null) o // error
4+
else new MyAsInstanceOfClass(this)
5+
}
6+
val oRef = o
7+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
final class MyNeClass(o: MyNeClass) {
2+
val other: MyNeClass = {
3+
if (o ne null) o // o is cold, but ne is always valid
4+
else new MyNeClass(this)
5+
}
6+
}
7+
8+
final class MyEqClass(o: MyEqClass) {
9+
val other: MyEqClass = {
10+
if (o eq null) new MyEqClass(this) // o is cold, but eq is always valid
11+
else o
12+
}
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
final class MyIsInstanceOfClass(o: MyIsInstanceOfClass) {
2+
val other: MyIsInstanceOfClass = {
3+
if (!o.isInstanceOf[Object]) new MyIsInstanceOfClass(this) // o is cold, but isInstanceOf is always valid
4+
else o
5+
}
6+
}
7+
8+
final class MyAsInstanceOfClass(o: MyAsInstanceOfClass) {
9+
val other: MyAsInstanceOfClass = {
10+
if (o.asInstanceOf[Object] ne null) o // o is cold, but ne and AsInstanceOf is always valid
11+
else new MyAsInstanceOfClass(this)
12+
}
13+
}
14+
15+
final class MyAsInstanceOfFieldClass(o: MyAsInstanceOfFieldClass) {
16+
val oRef = o
17+
val other: MyAsInstanceOfFieldClass = {
18+
if (this.asInstanceOf[MyAsInstanceOfFieldClass].oRef ne null) oRef // o is cold, but ne and AsInstanceOf is always valid
19+
else new MyAsInstanceOfFieldClass(this)
20+
}
21+
}
22+

0 commit comments

Comments
 (0)