Skip to content

Commit 4d715ce

Browse files
committed
Allow generic literals in patterns
Wrap generic literals in patterns in blocks, which force expression evaluation. This allows to match (say) a scrutinee of BigInt type against large numeric literals. But it does not work if the scrutinee is of type `Any` because then the expeected type for the pattern is missing. This would be addressed by a feature that's still missing: patterns of the form `<literal> : <type>`. We have to change the syntax of patterns in general for this one.
1 parent 5a3f872 commit 4d715ce

File tree

3 files changed

+29
-4
lines changed

3 files changed

+29
-4
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,9 +347,11 @@ class SpaceEngine(implicit ctx: Context) extends SpaceLogic {
347347
Typ(pat.tpe.stripAnnots, false)
348348
case EmptyTree => // default rethrow clause of try/catch, check tests/patmat/try2.scala
349349
Typ(WildcardType, false)
350+
case Block(Nil, expr) =>
351+
project(expr)
350352
case _ =>
351-
ctx.error(s"unknown pattern: $pat", pat.sourcePos)
352-
Empty
353+
// Pattern is an arbitrary expression; assume a skolem (i.e. an unknown value) of the pattern type
354+
Typ(pat.tpe.narrow, false)
353355
}
354356

355357
private def unapplySeqInfo(resTp: Type, pos: SourcePosition)(implicit ctx: Context): (Int, Type, Type) = {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,9 @@ class Typer extends Namer
550550
case Whole(r) if r != 10 => Literal(Constant(r)) :: Nil
551551
case _ => Nil
552552
}
553-
return typed(untpd.Apply(fromDigits, firstArg :: otherArgs), pt)
553+
var app: untpd.Tree = untpd.Apply(fromDigits, firstArg :: otherArgs)
554+
if (ctx.mode.is(Mode.Pattern)) app = untpd.Block(Nil, app)
555+
return typed(app, pt)
554556
case _ =>
555557
}
556558
}
@@ -765,7 +767,8 @@ class Typer extends Namer
765767
(index(stats), typedStats(stats, ctx.owner))
766768

767769
def typedBlock(tree: untpd.Block, pt: Type)(implicit ctx: Context): Tree = track("typedBlock") {
768-
val (exprCtx, stats1) = typedBlockStats(tree.stats)
770+
val localCtx = ctx.retractMode(Mode.Pattern)
771+
val (exprCtx, stats1) = typedBlockStats(tree.stats) given localCtx
769772
val expr1 = typedExpr(tree.expr, pt.dropIfProto)(exprCtx)
770773
ensureNoLocalRefs(
771774
cpy.Block(tree)(stats1, expr1).withType(expr1.tpe), pt, localSyms(stats1))

tests/run/genericNumLits.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,24 @@ object Test extends App {
2626
catch {
2727
case ex: FromDigits.MalformedNumber => println("malformed")
2828
}
29+
30+
val N = 10
31+
32+
x match {
33+
case 13232202002020202020202 => ()
34+
}
35+
y match {
36+
case 13232202002020202020202 => assert(false)
37+
case -0xaabb12345ACF12345AC => ()
38+
}
39+
z match {
40+
case 132322020020.223 => ()
41+
}
42+
z match {
43+
case 132322020020.223 => ()
44+
}
45+
46+
e match {
47+
case 1234 =>
48+
}
2949
}

0 commit comments

Comments
 (0)