Skip to content

Commit 1b70511

Browse files
authored
Merge pull request #14550 from dwijnand/patmat-unreachable-int-long
2 parents 25f4eec + 9ff512b commit 1b70511

File tree

5 files changed

+26
-60
lines changed

5 files changed

+26
-60
lines changed

compiler/src/dotty/tools/dotc/transform/patmat/Space.scala

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package patmat
44

55
import core._
66
import Types._
7+
import TypeUtils._
78
import Contexts._
89
import Flags._
910
import ast._
@@ -333,9 +334,12 @@ class SpaceEngine(using Context) extends SpaceLogic {
333334
// Since projections of types don't include null, intersection with null is empty.
334335
Empty
335336
else
336-
val res = TypeComparer.provablyDisjoint(tp1, tp2)
337-
if res then Empty
338-
else Typ(AndType(tp1, tp2), decomposed = true)
337+
val intersection = Typ(AndType(tp1, tp2), decomposed = false)
338+
// unrelated numeric value classes can equal each other, so let's not consider type space intersection empty
339+
if tp1.classSymbol.isNumericValueClass && tp2.classSymbol.isNumericValueClass then intersection
340+
else if isPrimToBox(tp1, tp2) || isPrimToBox(tp2, tp1) then intersection
341+
else if TypeComparer.provablyDisjoint(tp1, tp2) then Empty
342+
else intersection
339343
}
340344

341345
/** Return the space that represents the pattern `pat` */
@@ -407,7 +411,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
407411
case tp => Typ(tp, decomposed = true)
408412
}
409413

410-
private def unapplySeqInfo(resTp: Type, pos: SrcPos)(using Context): (Int, Type, Type) = {
414+
private def unapplySeqInfo(resTp: Type, pos: SrcPos): (Int, Type, Type) = {
411415
var resultTp = resTp
412416
var elemTp = unapplySeqTypeElemTp(resultTp)
413417
var arity = productArity(resultTp, pos)
@@ -500,35 +504,8 @@ class SpaceEngine(using Context) extends SpaceLogic {
500504
}
501505
}
502506

503-
/** Numeric literals, while being constant values of unrelated types (e.g. Char and Int),
504-
* when used in a case may end up matching at runtime, because their equals may returns true.
505-
* Because these are universally available, general purpose types, it would be good to avoid
506-
* returning false positive warnings, such as in `(c: Char) match { case 67 => ... }` emitting a
507-
* reachability warning on the case. So the type `ConstantType(Constant(67, IntTag))` is
508-
* converted to `ConstantType(Constant(67, CharTag))`. #12805 */
509-
def convertConstantType(tp: Type, pt: Type): Type = tp match
510-
case tp @ ConstantType(const) =>
511-
val converted = const.convertTo(pt)
512-
if converted == null then tp else ConstantType(converted)
513-
case _ => tp
514-
515-
def isPrimToBox(tp: Type, pt: Type) =
516-
tp.classSymbol.isPrimitiveValueClass && (defn.boxedType(tp).classSymbol eq pt.classSymbol)
517-
518-
/** Adapt types by performing primitive value unboxing or boxing, or numeric constant conversion. #12805
519-
*
520-
* This makes these isSubType cases work like this:
521-
* {{{
522-
* 1 <:< Integer => (<skolem> : Integer) <:< Integer = true
523-
* ONE <:< Int => (<skolem> : Int) <:< Int = true
524-
* Integer <:< (1: Int) => (<skolem> : Int) <:< (1: Int) = false
525-
* }}}
526-
*/
527-
def adaptType(tp1: Type, tp2: Type): Type = trace(i"adaptType($tp1, $tp2)", show = true) {
528-
if isPrimToBox(tp1, tp2) then defn.boxedType(tp1).narrow
529-
else if isPrimToBox(tp2, tp1) then defn.unboxedType(tp1).narrow
530-
else convertConstantType(tp1, tp2)
531-
}
507+
def isPrimToBox(tp: Type, pt: Type): Boolean =
508+
tp.isPrimitiveValueType && (defn.boxedType(tp).classSymbol eq pt.classSymbol)
532509

533510
private val isSubspaceCache = mutable.HashMap.empty[(Space, Space, Context), Boolean]
534511

@@ -539,7 +516,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
539516
def isSubType(tp1: Type, tp2: Type): Boolean = trace(i"$tp1 <:< $tp2", debug, show = true) {
540517
if tp1 == constantNullType && !ctx.mode.is(Mode.SafeNulls)
541518
then tp2 == constantNullType
542-
else adaptType(tp1, tp2) <:< tp2
519+
else tp1 <:< tp2
543520
}
544521

545522
def isSameUnapply(tp1: TermRef, tp2: TermRef): Boolean =
@@ -872,7 +849,7 @@ class SpaceEngine(using Context) extends SpaceLogic {
872849
/** Return the underlying type of non-module, non-constant, non-enum case singleton types.
873850
* Also widen ExprType to its result type, and rewrap any annotation wrappers.
874851
* For example, with `val opt = None`, widen `opt.type` to `None.type`. */
875-
def toUnderlying(tp: Type)(using Context): Type = trace(i"toUnderlying($tp)", show = true)(tp match {
852+
def toUnderlying(tp: Type): Type = trace(i"toUnderlying($tp)", show = true)(tp match {
876853
case _: ConstantType => tp
877854
case tp: TermRef if tp.symbol.is(Module) => tp
878855
case tp: TermRef if tp.symbol.isAllOf(EnumCase) => tp

compiler/test/dotty/tools/dotc/transform/SpaceEngineTest.scala

Lines changed: 0 additions & 25 deletions
This file was deleted.

tests/patmat/i14407.dupe.check

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
6: Match case Unreachable

tests/patmat/i14407.dupe.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// scalac: -Werror
2+
@main def Test =
3+
val it: Int = 42
4+
42L match
5+
case `it` => println("pass")
6+
case `it` => println("dupe") // error
7+
case _ => println("fail")

tests/patmat/i14407.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// scalac: -Werror
2+
@main def Test =
3+
val it: Int = 42
4+
42L match
5+
case `it` => println("pass")
6+
case _ => println("fail")

0 commit comments

Comments
 (0)