@@ -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
@@ -1126,14 +1148,10 @@ object desugar {
11261148 *
11271149 * (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:
@@ -1264,13 +1282,14 @@ object desugar {
12641282
12651283 /** Make a function value pat => body.
12661284 * 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.
12681287 */
1269- def makeLambda (pat : Tree , body : Tree ): Tree = pat match {
1288+ def makeLambda (pat : Tree , body : Tree , checkMode : MatchCheck ): Tree = pat match {
12701289 case IdPattern (named, tpt) =>
12711290 Function (derivedValDef(pat, named, tpt, EmptyTree , Modifiers (Param )) :: Nil , body)
12721291 case _ =>
1273- makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil )
1292+ makeCaseLambda(CaseDef (pat, EmptyTree , body) :: Nil , checkMode )
12741293 }
12751294
12761295 /** If `pat` is not an Identifier, a Typed(Ident, _), or a Bind, wrap
@@ -1316,7 +1335,7 @@ object desugar {
13161335 val cases = List (
13171336 CaseDef (pat, EmptyTree , Literal (Constant (true ))),
13181337 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 ))
13201339 }
13211340
13221341 /** Is pattern `pat` irrefutable when matched against `rhs`?
@@ -1355,26 +1374,30 @@ object desugar {
13551374 Select (rhs, name)
13561375 }
13571376
1377+ def checkMode (gen : GenFrom ) =
1378+ if (gen.filtering) MatchCheck .None // refutable paterns were already eliminated in filter step
1379+ else MatchCheck .IrrefutableGenFrom
1380+
13581381 enums match {
13591382 case (gen : GenFrom ) :: Nil =>
1360- Apply (rhsSelect(gen, mapName), makeLambda(gen.pat, body))
1383+ Apply (rhsSelect(gen, mapName), makeLambda(gen.pat, body, checkMode(gen) ))
13611384 case (gen : GenFrom ) :: (rest @ (GenFrom (_, _, _) :: _)) =>
13621385 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 (_, _) :: _) =>
13651388 val (valeqs, rest1) = rest.span(_.isInstanceOf [GenAlias ])
13661389 val pats = valeqs map { case GenAlias (pat, _) => pat }
13671390 val rhss = valeqs map { case GenAlias (_, rhs) => rhs }
1368- val (defpat0, id0) = makeIdPat(pat)
1391+ val (defpat0, id0) = makeIdPat(gen. pat)
13691392 val (defpats, ids) = (pats map makeIdPat).unzip
13701393 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
13731396 val vfrom1 = new GenFrom (makeTuple(allpats), rhs1, filtering = false )
13741397 makeFor(mapName, flatMapName, vfrom1 :: rest1, body)
13751398 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 )
13781401 makeFor(mapName, flatMapName, genFrom :: rest, body)
13791402 case _ =>
13801403 EmptyTree // may happen for erroneous input
0 commit comments