@@ -32,8 +32,19 @@ object desugar {
32
32
*/
33
33
val DerivingCompanion : Property .Key [SourcePosition ] = new Property .Key
34
34
35
- /** An attachment for match expressions generated from a PatDef */
36
- val PatDefMatch : Property .Key [Unit ] = new Property .Key
35
+ /** An attachment for match expressions generated from a PatDef or GenFrom.
36
+ * Value of key == one of IrrefutablePatDef, IrrefutableGenFrom
37
+ */
38
+ val CheckIrrefutable : Property .Key [MatchCheck ] = new Property .StickyKey
39
+
40
+ /** What static check should be applied to a Match (none, irrefutable, exhaustive) */
41
+ class MatchCheck (val n : Int ) extends AnyVal
42
+ object MatchCheck {
43
+ val None = new MatchCheck (0 )
44
+ val Exhaustive = new MatchCheck (1 )
45
+ val IrrefutablePatDef = new MatchCheck (2 )
46
+ val IrrefutableGenFrom = new MatchCheck (3 )
47
+ }
37
48
38
49
/** Info of a variable in a pattern: The named tree and its type */
39
50
private type VarInfo = (NameTree , Tree )
@@ -925,6 +936,22 @@ object desugar {
925
936
}
926
937
}
927
938
939
+ /** The selector of a match, which depends of the given `checkMode`.
940
+ * @param sel the original selector
941
+ * @return if `checkMode` is
942
+ * - None : sel @unchecked
943
+ * - Exhaustive : sel
944
+ * - IrrefutablePatDef,
945
+ * IrrefutableGenFrom: sel @unchecked with attachment `CheckIrrefutable -> checkMode`
946
+ */
947
+ def makeSelector (sel : Tree , checkMode : MatchCheck )(implicit ctx : Context ): Tree =
948
+ if (checkMode == MatchCheck .Exhaustive ) sel
949
+ else {
950
+ val sel1 = Annotated (sel, New (ref(defn.UncheckedAnnotType )))
951
+ if (checkMode != MatchCheck .None ) sel1.pushAttachment(CheckIrrefutable , checkMode)
952
+ sel1
953
+ }
954
+
928
955
/** If `pat` is a variable pattern,
929
956
*
930
957
* val/var/lazy val p = e
@@ -959,11 +986,6 @@ object desugar {
959
986
// - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
960
987
val tupleOptimizable = forallResults(rhs, isMatchingTuple)
961
988
962
- def rhsUnchecked = {
963
- val rhs1 = makeAnnotated(" scala.unchecked" , rhs)
964
- rhs1.pushAttachment(PatDefMatch , ())
965
- rhs1
966
- }
967
989
val vars =
968
990
if (tupleOptimizable) // include `_`
969
991
pat match {
@@ -976,7 +998,7 @@ object desugar {
976
998
val caseDef = CaseDef (pat, EmptyTree , makeTuple(ids))
977
999
val matchExpr =
978
1000
if (tupleOptimizable) rhs
979
- else Match (rhsUnchecked , caseDef :: Nil )
1001
+ else Match (makeSelector(rhs, MatchCheck . IrrefutablePatDef ) , caseDef :: Nil )
980
1002
vars match {
981
1003
case Nil =>
982
1004
matchExpr
@@ -1125,14 +1147,10 @@ object desugar {
1125
1147
*
1126
1148
* (x$1, ..., x$n) => (x$0, ..., x${n-1} @unchecked?) match { cases }
1127
1149
*/
1128
- def makeCaseLambda (cases : List [CaseDef ], nparams : Int = 1 , unchecked : Boolean = true )(implicit ctx : Context ): Function = {
1150
+ def makeCaseLambda (cases : List [CaseDef ], checkMode : MatchCheck , nparams : Int = 1 )(implicit ctx : Context ): Function = {
1129
1151
val params = (1 to nparams).toList.map(makeSyntheticParameter(_))
1130
1152
val selector = makeTuple(params.map(p => Ident (p.name)))
1131
-
1132
- if (unchecked)
1133
- Function (params, Match (Annotated (selector, New (ref(defn.UncheckedAnnotType ))), cases))
1134
- else
1135
- Function (params, Match (selector, cases))
1153
+ Function (params, Match (makeSelector(selector, checkMode), cases))
1136
1154
}
1137
1155
1138
1156
/** Map n-ary function `(p1, ..., pn) => body` where n != 1 to unary function as follows:
@@ -1262,13 +1280,14 @@ object desugar {
1262
1280
1263
1281
/** Make a function value pat => body.
1264
1282
* If pat is a var pattern id: T then this gives (id: T) => body
1265
- * Otherwise this gives { case pat => body }
1283
+ * Otherwise this gives { case pat => body }, where `pat` is allowed to be
1284
+ * refutable only if `checkMode` is MatchCheck.None.
1266
1285
*/
1267
- def makeLambda (pat : Tree , body : Tree ): Tree = pat match {
1286
+ def makeLambda (pat : Tree , body : Tree , checkMode : MatchCheck ): Tree = pat match {
1268
1287
case IdPattern (named, tpt) =>
1269
1288
Function (derivedValDef(pat, named, tpt, EmptyTree , Modifiers (Param )) :: Nil , body)
1270
1289
case _ =>
1271
- makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil )
1290
+ makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil , checkMode )
1272
1291
}
1273
1292
1274
1293
/** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
@@ -1314,7 +1333,7 @@ object desugar {
1314
1333
val cases = List (
1315
1334
CaseDef (pat, EmptyTree , Literal (Constant (true ))),
1316
1335
CaseDef (Ident (nme.WILDCARD ), EmptyTree , Literal (Constant (false ))))
1317
- Apply (Select (rhs, nme.withFilter), makeCaseLambda(cases))
1336
+ Apply (Select (rhs, nme.withFilter), makeCaseLambda(cases, MatchCheck . None ))
1318
1337
}
1319
1338
1320
1339
/** Is pattern `pat` irrefutable when matched against `rhs`?
@@ -1353,26 +1372,30 @@ object desugar {
1353
1372
Select (rhs, name)
1354
1373
}
1355
1374
1375
+ def checkMode (gen : GenFrom ) =
1376
+ if (gen.filtering) MatchCheck .None // refutable paterns were already eliminated in filter step
1377
+ else MatchCheck .IrrefutableGenFrom
1378
+
1356
1379
enums match {
1357
1380
case (gen : GenFrom ) :: Nil =>
1358
- Apply (rhsSelect(gen, mapName), makeLambda(gen.pat, body))
1381
+ Apply (rhsSelect(gen, mapName), makeLambda(gen.pat, body, checkMode(gen) ))
1359
1382
case (gen : GenFrom ) :: (rest @ (GenFrom (_, _, _) :: _)) =>
1360
1383
val cont = makeFor(mapName, flatMapName, rest, body)
1361
- Apply (rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont))
1362
- case (gen @ GenFrom (pat, rhs, _) ) :: (rest @ GenAlias (_, _) :: _) =>
1384
+ Apply (rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont, checkMode(gen) ))
1385
+ case (gen : GenFrom ) :: (rest @ GenAlias (_, _) :: _) =>
1363
1386
val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
1364
1387
val pats = valeqs map { case GenAlias (pat, _) => pat }
1365
1388
val rhss = valeqs map { case GenAlias (_, rhs) => rhs }
1366
- val (defpat0, id0) = makeIdPat(pat)
1389
+ val (defpat0, id0) = makeIdPat(gen. pat)
1367
1390
val (defpats, ids) = (pats map makeIdPat).unzip
1368
1391
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers (), _, _))
1369
- val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom (defpat0, rhs , gen.filtering) :: Nil , Block (pdefs, makeTuple(id0 :: ids)))
1370
- val allpats = pat :: pats
1392
+ val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom (defpat0, gen.expr , gen.filtering) :: Nil , Block (pdefs, makeTuple(id0 :: ids)))
1393
+ val allpats = gen. pat :: pats
1371
1394
val vfrom1 = new GenFrom (makeTuple(allpats), rhs1, filtering = false )
1372
1395
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
1373
1396
case (gen : GenFrom ) :: test :: rest =>
1374
- val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test))
1375
- val genFrom = new GenFrom (gen.pat, filtered, filtering = false )
1397
+ val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test, MatchCheck . None ))
1398
+ val genFrom = GenFrom (gen.pat, filtered, filtering = false )
1376
1399
makeFor(mapName, flatMapName, genFrom :: rest, body)
1377
1400
case _ =>
1378
1401
EmptyTree // may happen for erroneous input
0 commit comments