@@ -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
@@ -1126,14 +1148,10 @@ object desugar {
1126
1148
*
1127
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:
@@ -1264,13 +1282,14 @@ object desugar {
1264
1282
1265
1283
/** Make a function value pat => body.
1266
1284
* If pat is a var pattern id: T then this gives (id: T) => body
1267
- * Otherwise this gives { case pat => body }
1285
+ * Otherwise this gives { case pat => body }, where `pat` is allowed to be
1286
+ * refutable only if `checkMode` is MatchCheck.None.
1268
1287
*/
1269
- def makeLambda (pat : Tree , body : Tree ): Tree = pat match {
1288
+ def makeLambda (pat : Tree , body : Tree , checkMode : MatchCheck ): Tree = pat match {
1270
1289
case IdPattern (named, tpt) =>
1271
1290
Function (derivedValDef(pat, named, tpt, EmptyTree , Modifiers (Param )) :: Nil , body)
1272
1291
case _ =>
1273
- makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil )
1292
+ makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil , checkMode )
1274
1293
}
1275
1294
1276
1295
/** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
@@ -1316,7 +1335,7 @@ object desugar {
1316
1335
val cases = List (
1317
1336
CaseDef (pat, EmptyTree , Literal (Constant (true ))),
1318
1337
CaseDef (Ident (nme.WILDCARD ), EmptyTree , Literal (Constant (false ))))
1319
- Apply (Select (rhs, nme.withFilter), makeCaseLambda(cases))
1338
+ Apply (Select (rhs, nme.withFilter), makeCaseLambda(cases, MatchCheck . None ))
1320
1339
}
1321
1340
1322
1341
/** Is pattern `pat` irrefutable when matched against `rhs`?
@@ -1355,26 +1374,30 @@ object desugar {
1355
1374
Select (rhs, name)
1356
1375
}
1357
1376
1377
+ def checkMode (gen : GenFrom ) =
1378
+ if (gen.filtering) MatchCheck .None // refutable paterns were already eliminated in filter step
1379
+ else MatchCheck .IrrefutableGenFrom
1380
+
1358
1381
enums match {
1359
1382
case (gen : GenFrom ) :: Nil =>
1360
- Apply (rhsSelect(gen, mapName), makeLambda(gen.pat, body))
1383
+ Apply (rhsSelect(gen, mapName), makeLambda(gen.pat, body, checkMode(gen) ))
1361
1384
case (gen : GenFrom ) :: (rest @ (GenFrom (_, _, _) :: _)) =>
1362
1385
val cont = makeFor(mapName, flatMapName, rest, body)
1363
- Apply (rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont))
1364
- case (gen @ GenFrom (pat, rhs, _) ) :: (rest @ GenAlias (_, _) :: _) =>
1386
+ Apply (rhsSelect(gen, flatMapName), makeLambda(gen.pat, cont, checkMode(gen) ))
1387
+ case (gen : GenFrom ) :: (rest @ GenAlias (_, _) :: _) =>
1365
1388
val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
1366
1389
val pats = valeqs map { case GenAlias (pat, _) => pat }
1367
1390
val rhss = valeqs map { case GenAlias (_, rhs) => rhs }
1368
- val (defpat0, id0) = makeIdPat(pat)
1391
+ val (defpat0, id0) = makeIdPat(gen. pat)
1369
1392
val (defpats, ids) = (pats map makeIdPat).unzip
1370
1393
val pdefs = (valeqs, defpats, rhss).zipped.map(makePatDef(_, Modifiers (), _, _))
1371
- val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom (defpat0, rhs , gen.filtering) :: Nil , Block (pdefs, makeTuple(id0 :: ids)))
1372
- val allpats = pat :: pats
1394
+ val rhs1 = makeFor(nme.map, nme.flatMap, GenFrom (defpat0, gen.expr , gen.filtering) :: Nil , Block (pdefs, makeTuple(id0 :: ids)))
1395
+ val allpats = gen. pat :: pats
1373
1396
val vfrom1 = new GenFrom (makeTuple(allpats), rhs1, filtering = false )
1374
1397
makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
1375
1398
case (gen : GenFrom ) :: test :: rest =>
1376
- val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test))
1377
- val genFrom = new GenFrom (gen.pat, filtered, filtering = false )
1399
+ val filtered = Apply (rhsSelect(gen, nme.withFilter), makeLambda(gen.pat, test, MatchCheck . None ))
1400
+ val genFrom = GenFrom (gen.pat, filtered, filtering = false )
1378
1401
makeFor(mapName, flatMapName, genFrom :: rest, body)
1379
1402
case _ =>
1380
1403
EmptyTree // may happen for erroneous input
0 commit comments