@@ -644,6 +644,12 @@ class Objects(using Context @constructorOnly):
644
644
case (ValueSet (values), b : ValueElement ) => ValueSet (values + b)
645
645
case (a : ValueElement , b : ValueElement ) => ValueSet (ListSet (a, b))
646
646
647
+ def remove (b : Value ): Value = (a, b) match
648
+ case (ValueSet (values1), b : ValueElement ) => ValueSet (values1 - b)
649
+ case (ValueSet (values1), ValueSet (values2)) => ValueSet (values1.removedAll(values2))
650
+ case (a : Ref , b : Ref ) if a.equals(b) => Bottom
651
+ case _ => a
652
+
647
653
def widen (height : Int )(using Context ): Value =
648
654
if height == 0 then Cold
649
655
else
@@ -1386,29 +1392,25 @@ class Objects(using Context @constructorOnly):
1386
1392
def getMemberMethod (receiver : Type , name : TermName , tp : Type ): Denotation =
1387
1393
receiver.member(name).suchThat(receiver.memberInfo(_) <:< tp)
1388
1394
1389
- def evalCase (caseDef : CaseDef ): Value =
1390
- evalPattern(scrutinee, caseDef.pat)
1391
- eval(caseDef.guard, thisV, klass)
1392
- eval(caseDef.body, thisV, klass)
1393
-
1394
1395
/** Abstract evaluation of patterns.
1395
1396
*
1396
1397
* It augments the local environment for bound pattern variables. As symbols are globally
1397
1398
* unique, we can put them in a single environment.
1398
1399
*
1399
1400
* Currently, we assume all cases are reachable, thus all patterns are assumed to match.
1400
1401
*/
1401
- def evalPattern (scrutinee : Value , pat : Tree ): Value = log(" match " + scrutinee.show + " against " + pat.show, printer, (_ : Value ).show):
1402
+ def evalPattern (scrutinee : Value , pat : Tree ): ( Type , Value ) = log(" match " + scrutinee.show + " against " + pat.show, printer, (_ : ( Type , Value ))._2 .show):
1402
1403
val trace2 = Trace .trace.add(pat)
1403
1404
pat match
1404
1405
case Alternative (pats) =>
1405
- for pat <- pats do evalPattern(scrutinee, pat)
1406
- scrutinee
1406
+ val (types, values) = pats.map(evalPattern(scrutinee, _)).unzip()
1407
+ val orType = types.fold(defn.NothingType )(OrType (_, _, false ))
1408
+ (orType, values.join)
1407
1409
1408
1410
case bind @ Bind (_, pat) =>
1409
- val value = evalPattern(scrutinee, pat)
1411
+ val (tpe, value) = evalPattern(scrutinee, pat)
1410
1412
initLocal(bind.symbol, value)
1411
- scrutinee
1413
+ (tpe, value)
1412
1414
1413
1415
case UnApply (fun, implicits, pats) =>
1414
1416
given Trace = trace2
@@ -1417,6 +1419,10 @@ class Objects(using Context @constructorOnly):
1417
1419
val funRef = fun1.tpe.asInstanceOf [TermRef ]
1418
1420
val unapplyResTp = funRef.widen.finalResultType
1419
1421
1422
+ val receiverType = fun1 match
1423
+ case ident : Ident => funRef.prefix
1424
+ case select : Select => select.qualifier.tpe
1425
+
1420
1426
val receiver = fun1 match
1421
1427
case ident : Ident =>
1422
1428
evalType(funRef.prefix, thisV, klass)
@@ -1505,17 +1511,18 @@ class Objects(using Context @constructorOnly):
1505
1511
end if
1506
1512
end if
1507
1513
end if
1508
- scrutinee
1514
+ (receiverType, scrutinee.filterType(receiverType))
1509
1515
1510
1516
case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
1511
- scrutinee
1517
+ (defn. ThrowableType , scrutinee)
1512
1518
1513
- case Typed (pat, _) =>
1514
- evalPattern(scrutinee, pat)
1519
+ case Typed (pat, typeTree) =>
1520
+ val (_, value) = evalPattern(scrutinee.filterType(typeTree.tpe), pat)
1521
+ (typeTree.tpe, value)
1515
1522
1516
1523
case tree =>
1517
1524
// For all other trees, the semantics is normal.
1518
- eval(tree, thisV, klass)
1525
+ (defn. ThrowableType , eval(tree, thisV, klass) )
1519
1526
1520
1527
end evalPattern
1521
1528
@@ -1539,12 +1546,12 @@ class Objects(using Context @constructorOnly):
1539
1546
if isWildcardStarArgList(pats) then
1540
1547
if pats.size == 1 then
1541
1548
// call .toSeq
1542
- val toSeqDenot = getMemberMethod( scrutineeType, nme.toSeq, toSeqType(elemType) )
1549
+ val toSeqDenot = scrutineeType.member( nme.toSeq).suchThat(_.info.isParameterless )
1543
1550
val toSeqRes = call(scrutinee, toSeqDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1544
1551
evalPattern(toSeqRes, pats.head)
1545
1552
else
1546
1553
// call .drop
1547
- val dropDenot = getMemberMethod(scrutineeType, nme.drop, dropType (elemType))
1554
+ val dropDenot = getMemberMethod(scrutineeType, nme.drop, applyType (elemType))
1548
1555
val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1549
1556
for pat <- pats.init do evalPattern(applyRes, pat)
1550
1557
evalPattern(dropRes, pats.last)
@@ -1555,8 +1562,21 @@ class Objects(using Context @constructorOnly):
1555
1562
end if
1556
1563
end evalSeqPatterns
1557
1564
1565
+ def canSkipCase (remainingScrutinee : Value , catchValue : Value ) =
1566
+ (remainingScrutinee == Bottom && scrutinee != Bottom ) ||
1567
+ (catchValue == Bottom && remainingScrutinee != Bottom )
1558
1568
1559
- cases.map(evalCase).join
1569
+ var remainingScrutinee = scrutinee
1570
+ val caseResults : mutable.ArrayBuffer [Value ] = mutable.ArrayBuffer ()
1571
+ for caseDef <- cases do
1572
+ val (tpe, value) = evalPattern(remainingScrutinee, caseDef.pat)
1573
+ eval(caseDef.guard, thisV, klass)
1574
+ if ! canSkipCase(remainingScrutinee, value) then
1575
+ caseResults.addOne(eval(caseDef.body, thisV, klass))
1576
+ if catchesAllOf(caseDef, tpe) then
1577
+ remainingScrutinee = remainingScrutinee.remove(value)
1578
+
1579
+ caseResults.join
1560
1580
end patternMatch
1561
1581
1562
1582
/** Handle semantics of leaf nodes
0 commit comments