Skip to content

Commit 763b05c

Browse files
committed
add extractor for Null ops; remove useless imports; reduce side effects
1 parent d59a792 commit 763b05c

File tree

7 files changed

+61
-38
lines changed

7 files changed

+61
-38
lines changed

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

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ object NullOpsDecorator {
4545
if (rrhs.isNullType) llhs
4646
else if (llhs.isNullType) rrhs
4747
else tp.derivedOrType(llhs, rrhs)
48+
case tp @ AndType(tp1, tp2) =>
49+
tp.derivedAndType(strip(tp1), strip(tp2))
4850
case _ =>
4951
if (tp.isNullType) {
5052
if (tp.isJavaNullType) hasJavaNull = true
@@ -77,17 +79,6 @@ object NullOpsDecorator {
7779
}
7880
}
7981

80-
/** Is this type guaranteed not to have `null` as a value? */
81-
final def isNotNull(implicit ctx: Context): Boolean = self match {
82-
case tp: ConstantType => tp.value.value != null
83-
case tp: ClassInfo => !tp.cls.isNullableClass && tp.cls != defn.NothingClass
84-
case tp: TypeBounds => tp.lo.isNotNull
85-
case tp: TypeProxy => tp.underlying.isNotNull
86-
case AndType(tp1, tp2) => tp1.isNotNull || tp2.isNotNull
87-
case OrType(tp1, tp2) => tp1.isNotNull && tp2.isNotNull
88-
case _ => false
89-
}
90-
9182
def maybeNullable(implicit ctx: Context): Type =
9283
if (ctx.explicitNulls) OrType(self, defn.NullType) else self
9384

@@ -120,18 +111,17 @@ object NullOpsDecorator {
120111
*/
121112
def stripAllJavaNull(implicit ctx: Context): Type = {
122113
assert(ctx.explicitNulls)
123-
var diff = false
124114
object RemoveNulls extends TypeMap {
125115
override def apply(tp: Type): Type =
126116
tp.normNullableUnion match {
127117
case OrType(lhs, rhs) if rhs.isJavaNullType =>
128-
diff = true
129118
mapOver(lhs)
130119
case _ => mapOver(tp)
131120
}
132121
}
133-
val rem = RemoveNulls(self.widenDealias)
134-
if (diff) rem else self
122+
val self1 = self.widenDealias
123+
val rem = RemoveNulls(self1)
124+
if (rem ne self1) rem else self
135125
}
136126

137127
/** Injects this type into a union with `JavaNull`. */

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,8 @@ trait Symbols { this: Context =>
386386
/** Get a List of ClassSymbols which are either defined in current compilation
387387
* run or present on classpath.
388388
*/
389-
def getClassesIfDefined(pathes: List[PreName]): List[ClassSymbol] =
390-
pathes.foldLeft(List.empty){ case (acc, path) => getClassIfDefined(path) match {
389+
def getClassesIfDefined(paths: List[PreName]): List[ClassSymbol] =
390+
paths.foldLeft(List.empty){ case (acc, path) => getClassIfDefined(path) match {
391391
case cls: ClassSymbol => cls :: acc
392392
case _ => acc
393393
}}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,12 +1610,18 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
16101610
// The next two definitions handle the special case mentioned above, where
16111611
// the Java argument has type 'Any', and the Scala argument has type 'Object' or
16121612
// 'Object|Null', depending on whether explicit nulls are enabled.
1613-
lazy val formal2IsObject =
1614-
if (ctx.explicitNulls) formal2.isNullableUnion && formal2.stripNull(ctx).isRef(ObjectClass)
1615-
else formal2.isRef(ObjectClass)
1616-
lazy val formal1IsObject =
1617-
if (ctx.explicitNulls) formal1.isNullableUnion && formal1.stripNull(ctx).isRef(ObjectClass)
1613+
def formal1IsObject =
1614+
if (ctx.explicitNulls) formal1 match {
1615+
case OrNull(formal1b) => formal1b.isRef(ObjectClass)
1616+
case _ => false
1617+
}
16181618
else formal1.isRef(ObjectClass)
1619+
def formal2IsObject =
1620+
if (ctx.explicitNulls) formal2 match {
1621+
case OrNull(formal2b) => formal2b.isRef(ObjectClass)
1622+
case _ => false
1623+
}
1624+
else formal2.isRef(ObjectClass)
16191625
(isSameTypeWhenFrozen(formal1, formal2a)
16201626
|| tp1.isJavaMethod && formal2IsObject && (formal1 isRef AnyClass)
16211627
|| tp2.isJavaMethod && formal1IsObject && (formal2 isRef AnyClass)) &&

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

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,17 @@ object Types {
273273
loop(this)
274274
}
275275

276+
/** Is this type guaranteed not to have `null` as a value? */
277+
final def isNotNull(implicit ctx: Context): Boolean = this match {
278+
case tp: ConstantType => tp.value.value != null
279+
case tp: ClassInfo => !tp.cls.isNullableClass && tp.cls != defn.NothingClass
280+
case tp: TypeBounds => tp.lo.isNotNull
281+
case tp: TypeProxy => tp.underlying.isNotNull
282+
case AndType(tp1, tp2) => tp1.isNotNull || tp2.isNotNull
283+
case OrType(tp1, tp2) => tp1.isNotNull && tp2.isNotNull
284+
case _ => false
285+
}
286+
276287
/** Is this type produced as a repair for an error? */
277288
final def isError(implicit ctx: Context): Boolean = stripTypeVar.isInstanceOf[ErrorType]
278289

@@ -588,19 +599,19 @@ object Types {
588599
case AndType(l, r) =>
589600
goAnd(l, r)
590601
case tp: OrType =>
591-
if (ctx.explicitNulls && tp.isJavaNullableUnion) {
592-
// Selecting `name` from a type `T|JavaNull` is like selecting `name` from `T`.
593-
// This can throw at runtime, but we trade soundness for usability.
594-
// We need to strip `JavaNull` from both the type and the prefix so that
595-
// `pre <: tp` continues to hold.
596-
tp.stripJavaNull.findMember(name, pre.stripJavaNull, required, excluded)
597-
}
598-
else {
599-
// we need to keep the invariant that `pre <: tp`. Branch `union-types-narrow-prefix`
600-
// achieved that by narrowing `pre` to each alternative, but it led to merge errors in
601-
// lots of places. The present strategy is instead of widen `tp` using `join` to be a
602-
// supertype of `pre`.
603-
go(tp.join)
602+
tp match {
603+
case OrJavaNull(tp1) =>
604+
// Selecting `name` from a type `T|JavaNull` is like selecting `name` from `T`.
605+
// This can throw at runtime, but we trade soundness for usability.
606+
// We need to strip `JavaNull` from both the type and the prefix so that
607+
// `pre <: tp` continues to hold.
608+
tp1.findMember(name, pre.stripJavaNull, required, excluded)
609+
case _ =>
610+
// we need to keep the invariant that `pre <: tp`. Branch `union-types-narrow-prefix`
611+
// achieved that by narrowing `pre` to each alternative, but it led to merge errors in
612+
// lots of places. The present strategy is instead of widen `tp` using `join` to be a
613+
// supertype of `pre`.
614+
go(tp.join)
604615
}
605616
case tp: JavaArrayType =>
606617
defn.ObjectType.findMember(name, pre, required, excluded)
@@ -2924,6 +2935,25 @@ object Types {
29242935
else apply(tp1, tp2)
29252936
}
29262937

2938+
object OrNull {
2939+
def apply(tp: Type)(given Context) =
2940+
OrType(tp, defn.NullType)
2941+
def unapply(tp: Type)(given Context): Option[Type] =
2942+
val tp1 = tp.stripNull
2943+
if tp1 ne tp then Some(tp1) else None
2944+
}
2945+
2946+
object OrJavaNull {
2947+
def apply(tp: Type)(given Context) =
2948+
OrType(tp, defn.JavaNullAliasType)
2949+
def unapply(tp: Type)(given ctx: Context): Option[Type] =
2950+
if (ctx.explicitNulls) {
2951+
val tp1 = tp.stripJavaNull
2952+
if tp1 ne tp then Some(tp1) else None
2953+
}
2954+
else None
2955+
}
2956+
29272957
// ----- ExprType and LambdaTypes -----------------------------------
29282958

29292959
// Note: method types are cached whereas poly types are not. The reason

compiler/src/dotty/tools/dotc/transform/LazyVals.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import dotty.tools.dotc.core.Types._
1616
import dotty.tools.dotc.core.{Names, StdNames}
1717
import dotty.tools.dotc.transform.MegaPhase.MiniPhase
1818
import dotty.tools.dotc.transform.SymUtils._
19-
import dotty.tools.dotc.core.NullOpsDecorator._
2019
import scala.collection.mutable
2120

2221
class LazyVals extends MiniPhase with IdentityDenotTransformer {

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import config.Printers.patmatch
1717
import reporting.diagnostic.messages._
1818
import dotty.tools.dotc.ast._
1919
import util.Property._
20-
import NullOpsDecorator._
2120

2221
/** The pattern matching transform.
2322
* After this phase, the only Match nodes remaining in the code are simple switches

compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import util.Spans._
1414
import reporting.diagnostic.messages.TypeTestAlwaysSucceeds
1515
import reporting.trace
1616
import config.Printers.{ transforms => debug }
17-
import NullOpsDecorator._
1817

1918
/** This transform normalizes type tests and type casts,
2019
* also replacing type tests with singleton argument type with reference equality check

0 commit comments

Comments
 (0)