@@ -33,8 +33,19 @@ object desugar {
33
33
*/
34
34
val DerivingCompanion : Property .Key [SourcePosition ] = new Property .Key
35
35
36
- /** An attachment for match expressions generated from a PatDef */
37
- val PatDefMatch : Property .Key [Unit ] = new Property .Key
36
+ /** An attachment for match expressions generated from a PatDef or GenFrom.
37
+ * Value of key == one of IrrefutablePatDef, IrrefutableGenFrom
38
+ */
39
+ val CheckIrrefutable : Property .Key [MatchCheck ] = new Property .StickyKey
40
+
41
+ /** What static check should be applied to a Match (none, irrefutable, exhaustive) */
42
+ class MatchCheck (val n : Int ) extends AnyVal
43
+ object MatchCheck {
44
+ val None = new MatchCheck (0 )
45
+ val Exhaustive = new MatchCheck (1 )
46
+ val IrrefutablePatDef = new MatchCheck (2 )
47
+ val IrrefutableGenFrom = new MatchCheck (3 )
48
+ }
38
49
39
50
/** Info of a variable in a pattern: The named tree and its type */
40
51
private type VarInfo = (NameTree , Tree )
@@ -926,6 +937,22 @@ object desugar {
926
937
}
927
938
}
928
939
940
+ /** The selector of a match, which depends of the given `checkMode`.
941
+ * @param sel the original selector
942
+ * @return if `checkMode` is
943
+ * - None : sel @unchecked
944
+ * - Exhaustive : sel
945
+ * - IrrefutablePatDef,
946
+ * IrrefutableGenFrom: sel @unchecked with attachment `CheckIrrefutable -> checkMode`
947
+ */
948
+ def makeSelector (sel : Tree , checkMode : MatchCheck )(implicit ctx : Context ): Tree =
949
+ if (checkMode == MatchCheck .Exhaustive ) sel
950
+ else {
951
+ val sel1 = Annotated (sel, New (ref(defn.UncheckedAnnotType )))
952
+ if (checkMode != MatchCheck .None ) sel1.pushAttachment(CheckIrrefutable , checkMode)
953
+ sel1
954
+ }
955
+
929
956
/** If `pat` is a variable pattern,
930
957
*
931
958
* val/var/lazy val p = e
@@ -960,11 +987,6 @@ object desugar {
960
987
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
961
988
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
962
989
963
- def rhsUnchecked = {
964
- val rhs1 = makeAnnotated(" scala.unchecked" , rhs)
965
- rhs1.pushAttachment(PatDefMatch , ())
966
- rhs1
967
- }
968
990
val vars =
969
991
if (tupleOptimizable) // include `_`
970
992
pat match {
@@ -977,7 +999,7 @@ object desugar {
977
999
val caseDef = CaseDef (pat, EmptyTree , makeTuple(ids))
978
1000
val matchExpr =
979
1001
if (tupleOptimizable) rhs
980
- else Match (rhsUnchecked , caseDef :: Nil )
1002
+ else Match (makeSelector(rhs, MatchCheck . IrrefutablePatDef ) , caseDef :: Nil )
981
1003
vars match {
982
1004
case Nil =>
983
1005
matchExpr
@@ -1120,20 +1142,16 @@ object desugar {
1120
1142
*
1121
1143
* { cases }
1122
1144
* ==>
1123
- * x$1 => (x$1 @unchecked) match { cases }
1145
+ * x$1 => (x$1 @unchecked? ) match { cases }
1124
1146
*
1125
1147
* If `nparams` != 1, expand instead to
1126
1148
*
1127
- * (x$1, ..., x$n) => (x$0, ..., x${n-1} @unchecked) match { cases }
1149
+ * (x$1, ..., x$n) => (x$0, ..., x${n-1} @unchecked? ) match { cases }
1128
1150
*/
1129
- def makeCaseLambda (cases : List [CaseDef ], nparams : Int = 1 , unchecked : Boolean = true )(implicit ctx : Context ): Function = {
1151
+ def makeCaseLambda (cases : List [CaseDef ], checkMode : MatchCheck , nparams : Int = 1 )(implicit ctx : Context ): Function = {
1130
1152
val params = (1 to nparams).toList.map(makeSyntheticParameter(_))
1131
1153
val selector = makeTuple(params.map(p => Ident (p.name)))
1132
-
1133
- if (unchecked)
1134
- Function (params, Match (Annotated (selector, New (ref(defn.UncheckedAnnotType ))), cases))
1135
- else
1136
- Function (params, Match (selector, cases))
1154
+ Function (params, Match (makeSelector(selector, checkMode), cases))
1137
1155
}
1138
1156
1139
1157
/** Map n-ary function `(p1, ..., pn) => body` where n != 1 to unary function as follows:
@@ -1262,15 +1280,19 @@ object desugar {
1262
1280
*/
1263
1281
def makeFor (mapName : TermName , flatMapName : TermName , enums : List [Tree ], body : Tree ): Tree = trace(i " make for ${ForYield (enums, body)}" , show = true ) {
1264
1282
1265
- /** Make a function value pat => body.
1266
- * If pat is a var pattern id: T then this gives (id: T) => body
1267
- * Otherwise this gives { case pat => body }
1283
+ /** Let `pat` be `gen`'s pattern. Make a function value `pat => body`.
1284
+ * If `pat` is a var pattern `id: T` then this gives `(id: T) => body`.
1285
+ * Otherwise this gives `{ case pat => body }`, where `pat` is checked to be
1286
+ * irrefutable if `gen`'s checkMode is GenCheckMode.Check.
1268
1287
*/
1269
- def makeLambda (pat : Tree , body : Tree ): Tree = pat match {
1270
- case IdPattern (named, tpt) =>
1271
- Function (derivedValDef(pat, named, tpt, EmptyTree , Modifiers (Param )) :: Nil , body)
1288
+ def makeLambda (gen : GenFrom , body : Tree ): Tree = gen. pat match {
1289
+ case IdPattern (named, tpt) if gen.checkMode != GenCheckMode . FilterAlways =>
1290
+ Function (derivedValDef(gen. pat, named, tpt, EmptyTree , Modifiers (Param )) :: Nil , body)
1272
1291
case _ =>
1273
- makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil )
1292
+ val matchCheckMode =
1293
+ if (gen.checkMode == GenCheckMode .Check ) MatchCheck .IrrefutableGenFrom
1294
+ else MatchCheck .None
1295
+ makeCaseLambda(CaseDef (gen.pat, EmptyTree , body) :: Nil , matchCheckMode)
1274
1296
}
1275
1297
1276
1298
/** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
@@ -1316,7 +1338,7 @@ object desugar {
1316
1338
val cases = List (
1317
1339
CaseDef (pat, EmptyTree , Literal (Constant (true ))),
1318
1340
CaseDef (Ident (nme.WILDCARD ), EmptyTree , Literal (Constant (false ))))
1319
- Apply (Select (rhs, nme.withFilter), makeCaseLambda(cases))
1341
+ Apply (Select (rhs, nme.withFilter), makeCaseLambda(cases, MatchCheck . None ))
1320
1342
}
1321
1343
1322
1344
/** Is pattern `pat` irrefutable when matched against `rhs`?
@@ -1342,41 +1364,47 @@ object desugar {
1342
1364
}
1343
1365
}
1344
1366
1345
- def isIrrefutableGenFrom (gen : GenFrom ): Boolean =
1346
- gen.isInstanceOf [IrrefutableGenFrom ] ||
1347
- IdPattern .unapply(gen.pat).isDefined ||
1348
- isIrrefutable(gen.pat, gen.expr)
1367
+ def needsNoFilter (gen : GenFrom ): Boolean =
1368
+ if (gen.checkMode == GenCheckMode .FilterAlways ) // pattern was prefixed by `case`
1369
+ false
1370
+ else (
1371
+ gen.checkMode != GenCheckMode .FilterNow ||
1372
+ IdPattern .unapply(gen.pat).isDefined ||
1373
+ isIrrefutable(gen.pat, gen.expr)
1374
+ )
1349
1375
1350
1376
/** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when
1351
1377
* matched against `rhs`.
1352
1378
*/
1353
1379
def rhsSelect (gen : GenFrom , name : TermName ) = {
1354
- val rhs = if (isIrrefutableGenFrom (gen)) gen.expr else makePatFilter(gen.expr, gen.pat)
1380
+ val rhs = if (needsNoFilter (gen)) gen.expr else makePatFilter(gen.expr, gen.pat)
1355
1381
Select (rhs, name)
1356
1382
}
1357
1383
1384
+ def checkMode (gen : GenFrom ) =
1385
+ if (gen.checkMode == GenCheckMode .Check ) MatchCheck .IrrefutableGenFrom
1386
+ else MatchCheck .None // refutable paterns were already eliminated in filter step
1387
+
1358
1388
enums match {
1359
1389
case (gen : GenFrom ) :: Nil =>
1360
- Apply (rhsSelect(gen, mapName), makeLambda(gen.pat , body))
1361
- case (gen : GenFrom ) :: (rest @ (GenFrom (_, _) :: _)) =>
1390
+ Apply (rhsSelect(gen, mapName), makeLambda(gen, body))
1391
+ case (gen : GenFrom ) :: (rest @ (GenFrom (_, _, _ ) :: _)) =>
1362
1392
val cont = makeFor(mapName, flatMapName, rest, body)
1363
- Apply (rhsSelect(gen, flatMapName), makeLambda(gen.pat , cont))
1364
- case (GenFrom (pat, rhs) ) :: (rest @ GenAlias (_, _) :: _) =>
1393
+ Apply (rhsSelect(gen, flatMapName), makeLambda(gen, cont))
1394
+ case (gen : GenFrom ) :: (rest @ GenAlias (_, _) :: _) =>
1365
1395
val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
1366
1396
val pats = valeqs map { case GenAlias (pat, _) => pat }
1367
1397
val rhss = valeqs map { case GenAlias (_, rhs) => rhs }
1368
- val (defpat0, id0) = makeIdPat(pat)
1398
+ val (defpat0, id0) = makeIdPat(gen. pat)
1369
1399
val (defpats, ids) = (pats map makeIdPat).unzip
1370
1400
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers (), _, _))
1371
- val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom (defpat0, rhs ) :: Nil , Block (pdefs, makeTuple(id0 :: ids)))
1372
- val allpats = pat :: pats
1373
- val vfrom1 = new IrrefutableGenFrom (makeTuple(allpats), rhs1)
1401
+ val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom (defpat0, gen.expr, gen.checkMode ) :: Nil , Block (pdefs, makeTuple(id0 :: ids)))
1402
+ val allpats = gen. pat :: pats
1403
+ val vfrom1 = new GenFrom (makeTuple(allpats), rhs1, GenCheckMode . Ignore )
1374
1404
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
1375
1405
case (gen : GenFrom ) :: test :: rest =>
1376
- val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test))
1377
- val genFrom =
1378
- if (isIrrefutableGenFrom(gen)) new IrrefutableGenFrom (gen.pat, filtered)
1379
- else GenFrom (gen.pat, filtered)
1406
+ val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen, test))
1407
+ val genFrom = GenFrom (gen.pat, filtered, GenCheckMode .Ignore )
1380
1408
makeFor(mapName, flatMapName, genFrom :: rest, body)
1381
1409
case _ =>
1382
1410
EmptyTree // may happen for erroneous input
@@ -1571,7 +1599,4 @@ object desugar {
1571
1599
collect(tree)
1572
1600
buf.toList
1573
1601
}
1574
-
1575
- private class IrrefutableGenFrom (pat : Tree , expr : Tree )(implicit @ constructorOnly src : SourceFile )
1576
- extends GenFrom (pat, expr)
1577
1602
}
0 commit comments