Skip to content

Commit 7d40d5c

Browse files
committed
Fix isStable; fix var track in lazy val
1 parent ef5864e commit 7d40d5c

File tree

14 files changed

+115
-21
lines changed

14 files changed

+115
-21
lines changed

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ class Definitions {
270270
@tu lazy val Any_asInstanceOf: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, _.paramRefs(0), Final)
271271
@tu lazy val Any_typeTest: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.isInstanceOfPM, _ => BooleanType, Final | Synthetic | Artifact)
272272
@tu lazy val Any_typeCast: TermSymbol = enterT1ParameterlessMethod(AnyClass, nme.asInstanceOfPM, _.paramRefs(0), Final | Synthetic | Artifact | StableRealizable)
273-
// generated by pattern matcher, eliminated by erasure
273+
// generated by pattern matcher and exlicit nulls, eliminated by erasure
274274

275275
/** def getClass[A >: this.type](): Class[? <: A] */
276276
@tu lazy val Any_getClass: TermSymbol =
@@ -320,8 +320,7 @@ class Definitions {
320320

321321
/** Methods in Object and Any that do not have a side effect */
322322
@tu lazy val pureMethods: List[TermSymbol] = List(Any_==, Any_!=, Any_equals, Any_hashCode,
323-
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_typeTest, Object_eq, Object_ne,
324-
Compiletime_notNull.asInstanceOf[TermSymbol])
323+
Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_typeTest, Object_eq, Object_ne)
325324

326325
@tu lazy val AnyKindClass: ClassSymbol = {
327326
val cls = ctx.newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyKind, AbstractFinal | Permanent, Nil)

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import SymDenotations._
1717
import Decorators._
1818
import Denotations._
1919
import Periods._
20+
import CheckRealizable._
2021
import util.Stats._
2122
import util.SimpleIdentitySet
2223
import reporting.diagnostic.Message
@@ -163,7 +164,9 @@ object Types {
163164
case tp: RefinedOrRecType => tp.parent.isStable
164165
case tp: ExprType => tp.resultType.isStable
165166
case tp: AnnotatedType => tp.parent.isStable
166-
case tp: AndType => tp.tp1.isStable || tp.tp2.isStable
167+
case tp: AndType =>
168+
tp.tp1.isStable && (realizability(tp.tp2) eq Realizable) ||
169+
tp.tp2.isStable && (realizability(tp.tp1) eq Realizable)
167170
case _ => false
168171
}
169172

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,12 @@ trait Implicits { self: Typer =>
823823
// if (x.asInstanceOf[String|Null] == null) {} // ok
824824
cls1 == defn.NullClass && cls1 == cls2
825825
else if (cls1 == defn.NullClass)
826-
cls1 == cls2 || cls2.derivesFrom(defn.ObjectClass)
827-
else if (cls2 == defn.NullClass)
828-
cls1.derivesFrom(defn.ObjectClass)
826+
cls1 == cls2
827+
else if (!ctx.explicitNulls)
828+
if (cls1 == defn.NullClass)
829+
cls2.derivesFrom(defn.ObjectClass)
830+
else
831+
cls2 == defn.NullClass && cls1.derivesFrom(defn.ObjectClass)
829832
else
830833
false
831834
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ object Nullables with
110110
|| { val sym = ref.symbol
111111
sym.is(Mutable)
112112
&& sym.owner.isTerm
113+
&& !curCtx.owner.is(Flags.Lazy) // not a rhs of lazy ValDef
113114
&& sym.owner.enclosingMethod == curCtx.owner.enclosingMethod
114115
&& sym.span.exists
115116
&& curCtx.compilationUnit != null // could be null under -Ytest-pickler

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

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -352,15 +352,12 @@ class Typer extends Namer
352352
case ref @ OrNull(tpnn) : TermRef
353353
if pt != AssignProto && // Ensure it is not the lhs of Assign
354354
ctx.notNullInfos.impliesNotNull(ref) =>
355-
val tpeA = TypeTree(tpnn)
356-
val tpeB = TypeTree(AndType(ref, tpnn))
357-
//val tpeB = if (ref.symbol.is(Mutable)) tpeA else TypeTree(AndType(ref, tpnn))
358-
val newTree = TypeApply(Select(tree, defn.Any_typeCast.namedType), tpeB :: Nil)
359-
//newTree.symbol.setFlag(Erased)
360-
// val newTree = Apply(
355+
// val tpeA = TypeTree(tpnn)
356+
// val tpeB = TypeTree(AndType(ref, tpnn))
357+
// Apply(
361358
// TypeApply(Ident(defn.Compiletime_notNull.namedType), tpeA :: tpeB :: Nil),
362359
// tree :: Nil)
363-
newTree
360+
tree.select(defn.Any_typeCast).appliedToType(AndType(ref, tpnn))
364361
case _ =>
365362
tree
366363

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class C(val x: Int, val next: C|Null)
2+
3+
def f = {
4+
var xs: C|Null = C(1, C(2, null))
5+
while (xs != null) {
6+
val xsx: Int = xs.x
7+
val xscpy: C = xs
8+
xs = xscpy // Since xscpy is non-nullable, after the assign, xs is still non-nullable
9+
val xscpyx: Int = xscpy.x
10+
xs = xs.next // xs.next is nullable, after the assign, xs becomes nullable
11+
val xsnx: Int = xs.x // error
12+
}
13+
}

tests/explicit-nulls/neg/eq.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ class Foo {
4141
null == false // error
4242
'a' == null // error
4343
null == 'b' // error
44-
}
44+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Test simple var track
2+
3+
def nullable[T](x: T): T|Null = x
4+
5+
def f = {
6+
var x: String|Null = ???
7+
if (x != null) {
8+
val a: String = x
9+
x = ""
10+
val b: String = x
11+
}
12+
13+
assert(x != null)
14+
val a: String = x
15+
x = nullable(x)
16+
val b: String = x // error: x might be null
17+
}
18+
19+
def g = {
20+
var x: String|Null = ???
21+
lazy val y = {
22+
if (x != null) {
23+
x = null
24+
}
25+
26+
}
27+
if (x != null) {
28+
val a: String = x // error: x exists in closure, no longer tackable
29+
}
30+
}
31+
32+
def h = {
33+
var x: String|Null = "???"
34+
lazy val y = {
35+
if (x != null) {
36+
val a: String = x // error: x exists in closure, no longer tackable
37+
}
38+
x
39+
}
40+
}
41+
42+
def i = {
43+
var x: String|Null = "???"
44+
def y = {
45+
if (x != null) {
46+
val a: String = x // error: x exists in closure, no longer tackable
47+
}
48+
x
49+
}
50+
}

tests/explicit-nulls/neg/strip.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ class Foo {
2020

2121
locally {
2222
val x: (Null | B1) & B2 = ???
23-
if (x != null) {
24-
val _: B1 & B2 = x // error: the type of x is not a nullable union, so we cannot remove the Null
25-
}
23+
if (x != null) {} // error: the type of x is not a nullable union, so we cannot remove the Null
2624
}
2725
}

tests/explicit-nulls/pos/flow3.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
1+
// TODO: broken
22
// Test that flow inference can look inside type ascriptions.
33
// This is useful in combination with inlining (because inlined methods have an ascribed return type).
4+
45
class Foo {
56
val x: String|Null = "hello"
67

0 commit comments

Comments
 (0)