Skip to content

Commit 3e25a19

Browse files
committed
Modify logic type tests logic to strip the | Null's from testType and add a forceStrip argument to .stripNull that makes it strip | Null's even when explicit-nulls is not enabled
1 parent 464d605 commit 3e25a19

File tree

4 files changed

+12
-18
lines changed

4 files changed

+12
-18
lines changed

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ import Types.*
88
object NullOpsDecorator:
99

1010
extension (self: Type)
11-
/** Syntactically strips the nullability from this type.
11+
/** If explicit-nulls is enabled, syntactically strips the nullability from this type.
12+
* If explicit-nulls is not enabled, removes all Null in unions.
1213
* If the type is `T1 | ... | Tn`, and `Ti` references to `Null`,
1314
* then return `T1 | ... | Ti-1 | Ti+1 | ... | Tn`.
1415
* If this type isn't (syntactically) nullable, then returns the type unchanged.
15-
* The type will not be changed if explicit-nulls is not enabled.
16+
* The type will not be changed if explicit-nulls is not enabled and forceStrip is false.
1617
*/
17-
def stripNull(stripFlexibleTypes: Boolean = true)(using Context): Type = {
18+
def stripNull(stripFlexibleTypes: Boolean = true, forceStrip: Boolean = false)(using Context): Type = {
1819
def strip(tp: Type): Type =
1920
val tpWiden = tp.widenDealias
2021
val tpStripped = tpWiden match {
@@ -42,7 +43,7 @@ object NullOpsDecorator:
4243
}
4344
if tpStripped ne tpWiden then tpStripped else tp
4445

45-
if ctx.explicitNulls then strip(self) else self
46+
if ctx.explicitNulls || forceStrip then strip(self) else self
4647
}
4748

4849
/** Is self (after widening and dealiasing) a type of the form `T | Null`? */

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import reporting.*
1616
import config.Printers.{ transforms => debug }
1717

1818
import patmat.Typ
19+
import dotty.tools.dotc.core.NullOpsDecorator.stripNull
1920
import dotty.tools.dotc.util.SrcPos
2021

2122
/** This transform normalizes type tests and type casts,
@@ -323,19 +324,15 @@ object TypeTestsCasts {
323324
* The transform happens before erasure of `testType`, thus cannot be merged
324325
* with `transformIsInstanceOf`, which depends on erased type of `testType`.
325326
*/
326-
def transformTypeTest(expr: Tree, testType: Type, flagUnrelated: Boolean): Tree = testType.dealias match {
327+
def transformTypeTest(expr: Tree, testType: Type, flagUnrelated: Boolean): Tree = testType.dealias.stripNull(false, true) match {
327328
case tref: TermRef if tref.symbol == defn.EmptyTupleModule =>
328329
ref(defn.RuntimeTuples_isInstanceOfEmptyTuple).appliedTo(expr)
329330
case _: SingletonType =>
330331
expr.isInstance(testType).withSpan(tree.span)
331-
case OrType(tp1, tp2) =>
332+
case t @ OrType(tp1, tp2) =>
332333
evalOnce(expr) { e =>
333-
lazy val tp1Tree = transformTypeTest(e, tp1, flagUnrelated = false)
334-
lazy val tp2Tree = transformTypeTest(e, tp2, flagUnrelated = false)
335-
336-
if (tp1.isNothingType || (tp1.isNullType && !tp2.isNotNull)) tp2Tree
337-
else if (tp2.isNothingType || (tp2.isNullType && !tp1.isNotNull)) tp1Tree
338-
else tp1Tree.or(tp2Tree)
334+
transformTypeTest(e, tp1, flagUnrelated = false)
335+
.or(transformTypeTest(e, tp2, flagUnrelated = false))
339336
}
340337
case AndType(tp1, tp2) =>
341338
evalOnce(expr) { e =>

tests/neg/i23243.check

Lines changed: 0 additions & 4 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
object Extractor:
22
def unapply(s: String|Null): Boolean = true
3-
3+
44
class A
55

66
def main =
77
("foo": (A|String)) match
8-
case Extractor() => println("foo matched") // error
8+
case Extractor() => println("foo matched")
99
case _ => println("foo didn't match")

0 commit comments

Comments
 (0)