@@ -33,8 +33,19 @@ object desugar {
3333 */
3434 val DerivingCompanion : Property .Key [SourcePosition ] = new Property .Key
3535
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+ }
3849
3950 /** Info of a variable in a pattern: The named tree and its type */
4051 private type VarInfo = (NameTree , Tree )
@@ -926,6 +937,22 @@ object desugar {
926937 }
927938 }
928939
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+
929956 /** If `pat` is a variable pattern,
930957 *
931958 * val/var/lazy val p = e
@@ -960,11 +987,6 @@ object desugar {
960987 // - `pat` is a tuple of N variables or wildcard patterns like `(x1, x2, ..., xN)`
961988 val tupleOptimizable = forallResults(rhs, isMatchingTuple)
962989
963- def rhsUnchecked = {
964- val rhs1 = makeAnnotated(" scala.unchecked" , rhs)
965- rhs1.pushAttachment(PatDefMatch , ())
966- rhs1
967- }
968990 val vars =
969991 if (tupleOptimizable) // include `_`
970992 pat match {
@@ -977,7 +999,7 @@ object desugar {
977999 val caseDef = CaseDef (pat, EmptyTree , makeTuple(ids))
9781000 val matchExpr =
9791001 if (tupleOptimizable) rhs
980- else Match (rhsUnchecked , caseDef :: Nil )
1002+ else Match (makeSelector(rhs, MatchCheck . IrrefutablePatDef ) , caseDef :: Nil )
9811003 vars match {
9821004 case Nil =>
9831005 matchExpr
@@ -1120,20 +1142,16 @@ object desugar {
11201142 *
11211143 * { cases }
11221144 * ==>
1123- * x$1 => (x$1 @unchecked) match { cases }
1145+ * x$1 => (x$1 @unchecked? ) match { cases }
11241146 *
11251147 * If `nparams` != 1, expand instead to
11261148 *
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 }
11281150 */
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 = {
11301152 val params = (1 to nparams).toList.map(makeSyntheticParameter(_))
11311153 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))
11371155 }
11381156
11391157 /** Map n-ary function `(p1, ..., pn) => body` where n != 1 to unary function as follows:
@@ -1262,15 +1280,19 @@ object desugar {
12621280 */
12631281 def makeFor (mapName : TermName , flatMapName : TermName , enums : List [Tree ], body : Tree ): Tree = trace(i " make for ${ForYield (enums, body)}" , show = true ) {
12641282
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.
12681287 */
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)
12721291 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)
12741296 }
12751297
12761298 /** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
@@ -1316,7 +1338,7 @@ object desugar {
13161338 val cases = List (
13171339 CaseDef (pat, EmptyTree , Literal (Constant (true ))),
13181340 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 ))
13201342 }
13211343
13221344 /** Is pattern `pat` irrefutable when matched against `rhs`?
@@ -1342,41 +1364,47 @@ object desugar {
13421364 }
13431365 }
13441366
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+ )
13491375
13501376 /** rhs.name with a pattern filter on rhs unless `pat` is irrefutable when
13511377 * matched against `rhs`.
13521378 */
13531379 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)
13551381 Select (rhs, name)
13561382 }
13571383
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+
13581388 enums match {
13591389 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 (_, _, _ ) :: _)) =>
13621392 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 (_, _) :: _) =>
13651395 val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
13661396 val pats = valeqs map { case GenAlias (pat, _) => pat }
13671397 val rhss = valeqs map { case GenAlias (_, rhs) => rhs }
1368- val (defpat0, id0) = makeIdPat(pat)
1398+ val (defpat0, id0) = makeIdPat(gen. pat)
13691399 val (defpats, ids) = (pats map makeIdPat).unzip
13701400 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 )
13741404 makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
13751405 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 )
13801408 makeFor(mapName, flatMapName, genFrom :: rest, body)
13811409 case _ =>
13821410 EmptyTree // may happen for erroneous input
@@ -1571,7 +1599,4 @@ object desugar {
15711599 collect(tree)
15721600 buf.toList
15731601 }
1574-
1575- private class IrrefutableGenFrom (pat : Tree , expr : Tree )(implicit @ constructorOnly src : SourceFile )
1576- extends GenFrom (pat, expr)
15771602}
0 commit comments