Skip to content

Commit 215aa72

Browse files
committed
More consistant results in pickling
1 parent c37175b commit 215aa72

File tree

9 files changed

+142
-23
lines changed

9 files changed

+142
-23
lines changed

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2141,7 +2141,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
21412141
* @note We do not admit singleton types in or-types as lubs.
21422142
*/
21432143
def lub(tp1: Type, tp2: Type, canConstrain: Boolean = false, isSoft: Boolean = true): Type = /*>|>*/ trace(s"lub(${tp1.show}, ${tp2.show}, canConstrain=$canConstrain, isSoft=$isSoft)", subtyping, show = true) /*<|<*/ {
2144-
if (tp1 eq tp2) tp1
2144+
if tp1 eq tp2 then tp1
21452145
else if !tp1.exists || (tp2 eq WildcardType) then tp1
21462146
else if !tp2.exists || (tp1 eq WildcardType) then tp2
21472147
else if tp1.isAny && !tp2.isLambdaSub || tp1.isAnyKind || isBottom(tp2) then tp1
@@ -2157,16 +2157,19 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
21572157
if (hi1 & hi2).isEmpty then return orType(tp1, tp2)
21582158
case none =>
21592159
case none =>
2160+
2161+
// Simplifying the super type is important to avoid
2162+
// inconsistant result in union type.
21602163
val t1 = mergeIfSuper(tp1, tp2, canConstrain)
2161-
if (t1.exists) return t1
2164+
if t1.exists then return t1.simplified
21622165

21632166
val t2 = mergeIfSuper(tp2, tp1, canConstrain)
2164-
if (t2.exists) return t2
2167+
if t2.exists then return t2.simplified
21652168

2166-
def widen(tp: Type) = if (widenInUnions) tp.widen else tp.widenIfUnstable
2169+
def widen(tp: Type) = if widenInUnions then tp.widen else tp.widenIfUnstable
21672170
val tp1w = widen(tp1)
21682171
val tp2w = widen(tp2)
2169-
if ((tp1 ne tp1w) || (tp2 ne tp2w)) lub(tp1w, tp2w, canConstrain = canConstrain, isSoft = isSoft)
2172+
if (tp1 ne tp1w) || (tp2 ne tp2w) then lub(tp1w, tp2w, canConstrain = canConstrain, isSoft = isSoft)
21702173
else orType(tp1w, tp2w, isSoft = isSoft) // no need to check subtypes again
21712174
}
21722175
mergedLub(tp1.stripLazyRef, tp2.stripLazyRef)

compiler/src/dotty/tools/dotc/core/tasty/TreeUnpickler.scala

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,10 +1194,6 @@ class TreeUnpickler(reader: TastyReader,
11941194
res.withAttachment(SuppressedApplyToNone, ())
11951195
else res
11961196

1197-
def simplifyLub(tree: Tree): Tree =
1198-
tree.overwriteType(tree.tpe.simplified)
1199-
tree
1200-
12011197
def readLengthTerm(): Tree = {
12021198
val end = readEnd()
12031199
val result =
@@ -1247,25 +1243,23 @@ class TreeUnpickler(reader: TastyReader,
12471243
val tpt = ifBefore(end)(readTpt(), EmptyTree)
12481244
Closure(Nil, meth, tpt)
12491245
case MATCH =>
1250-
simplifyLub(
1251-
if (nextByte == IMPLICIT) {
1252-
readByte()
1253-
InlineMatch(EmptyTree, readCases(end))
1254-
}
1255-
else if (nextByte == INLINE) {
1256-
readByte()
1257-
InlineMatch(readTerm(), readCases(end))
1258-
}
1259-
else Match(readTerm(), readCases(end)))
1246+
if (nextByte == IMPLICIT) {
1247+
readByte()
1248+
InlineMatch(EmptyTree, readCases(end))
1249+
}
1250+
else if (nextByte == INLINE) {
1251+
readByte()
1252+
InlineMatch(readTerm(), readCases(end))
1253+
}
1254+
else Match(readTerm(), readCases(end))
12601255
case RETURN =>
12611256
val from = readSymRef()
12621257
val expr = ifBefore(end)(readTerm(), EmptyTree)
12631258
Return(expr, Ident(from.termRef))
12641259
case WHILE =>
12651260
WhileDo(readTerm(), readTerm())
12661261
case TRY =>
1267-
simplifyLub(
1268-
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree)))
1262+
Try(readTerm(), readCases(end), ifBefore(end)(readTerm(), EmptyTree))
12691263
case SELECTouter =>
12701264
val levels = readNat()
12711265
readTerm().outerSelect(levels, SkolemType(readType()))

compiler/src/dotty/tools/dotc/typer/Nullables.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ object Nullables:
2828
ctx.explicitNulls && !ctx.mode.is(Mode.SafeNulls)
2929

3030
private def needNullifyHi(lo: Type, hi: Type)(using Context): Boolean =
31-
ctx.explicitNulls
31+
ctx.mode.is(Mode.SafeNulls)
3232
&& lo.isExactlyNull // only nullify hi if lo is exactly Null type
3333
&& hi.isValueType
3434
// We cannot check if hi is nullable, because it can cause cyclic reference.

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,9 @@ class CompilationTests {
248248
compileFilesInDir("tests/explicit-nulls/pos", explicitNullsOptions),
249249
compileFilesInDir("tests/explicit-nulls/pos-separate", explicitNullsOptions),
250250
compileFilesInDir("tests/explicit-nulls/pos-patmat", explicitNullsOptions and "-Xfatal-warnings"),
251+
compileFilesInDir("tests/explicit-nulls/pos-pickling", explicitNullsOptions and "-Ytest-pickler" and "-Xprint-types"),
251252
compileFilesInDir("tests/explicit-nulls/unsafe-common", explicitNullsOptions and "-language:unsafeNulls"),
252253
compileFile("tests/explicit-nulls/pos-special/i14682.scala", explicitNullsOptions and "-Ysafe-init"),
253-
compileFile("tests/explicit-nulls/pos-special/i14947.scala", explicitNullsOptions and "-Ytest-pickler" and "-Xprint-types"),
254254
)
255255
}.checkCompile()
256256

tests/pos/i15097.scala renamed to tests/explicit-nulls/pos-pickling/i15097.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class C:
1010
if ??? then g else ""
1111

1212
def f3 =
13+
import scala.language.unsafeNulls
1314
(??? : Boolean) match
1415
case true => g
1516
case _ => ""
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import scala.language.unsafeNulls
2+
3+
def a(): String | Null = ???
4+
val b: String | Null = ???
5+
6+
val i: Int = ???
7+
8+
def f1 = i match {
9+
case 0 => b
10+
case _ => a()
11+
}
12+
13+
def f2 = i match {
14+
case 0 => a()
15+
case _ => b
16+
}
17+
18+
def f3 = i match {
19+
case 0 => a()
20+
case _ => "".trim
21+
}
22+
23+
def f4 = i match {
24+
case 0 => b
25+
case _ => "".trim
26+
}
27+
28+
def g1 = i match {
29+
case 0 => a()
30+
case 1 => ""
31+
case _ => null
32+
}
33+
34+
def g2 = i match {
35+
case 0 => ""
36+
case 1 => null
37+
case _ => b
38+
}
39+
40+
def g3 = i match {
41+
case 0 => null
42+
case 1 => b
43+
case _ => ""
44+
}
45+
46+
def h1(i: Int) = i match
47+
case 0 => 0
48+
case 1 => true
49+
case 2 => i.toString
50+
case _ => null
51+
52+
// This test still fails.
53+
// Even without explicit nulls, the type of Match
54+
// is (0, true, "2"), which is wrong.
55+
// def h2(i: Int) = i match
56+
// case 0 => 0
57+
// case 1 => true
58+
// case 2 => "2"
59+
// case _ => null
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import scala.language.unsafeNulls
2+
3+
def associatedFile: String | Null = ???
4+
5+
def source: String = {
6+
val f = associatedFile
7+
if (f != null) f else associatedFile
8+
}
9+
10+
def defines(raw: String): List[String] = {
11+
val ds: List[(Int, Int)] = ???
12+
ds map { case (start, end) => raw.substring(start, end) }
13+
}
14+
15+
abstract class DeconstructorCommon[T >: Null <: AnyRef] {
16+
var field: T = null
17+
def get: this.type = this
18+
def isEmpty: Boolean = field eq null
19+
def isDefined = !isEmpty
20+
def unapply(s: T): this.type ={
21+
field = s
22+
this
23+
}
24+
}
25+
26+
def genBCode =
27+
val bsmArgs: Array[Object | Null] | Null = null
28+
val implMethod = bsmArgs(3).asInstanceOf[Integer].toInt
29+
implMethod
30+
31+
val arrayApply = "a".split(" ")(2)
32+
33+
val globdir: String = if (??? : Boolean) then associatedFile.replaceAll("[\\\\/][^\\\\/]*$", "") else ""
34+
35+
def newInstOfC(c: Class[?]) = c.getConstructor().newInstance()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scala.language.unsafeNulls
2+
3+
4+
def s: String | Null = ???
5+
6+
def tryString = try s catch {
7+
case _: NullPointerException => null
8+
case _ => ""
9+
}
10+
11+
def tryString2 = try s catch {
12+
case _: NullPointerException => ""
13+
case _ => s
14+
}
15+
16+
def loadClass(classLoader: ClassLoader, name: String): Class[?] =
17+
try classLoader.loadClass(name)
18+
catch {
19+
case _ =>
20+
throw new Exception()
21+
}
22+
23+
def loadClass2(classLoader: ClassLoader, name: String): Class[?] =
24+
try classLoader.loadClass(name)
25+
catch {
26+
case _ => null
27+
}

0 commit comments

Comments
 (0)