@@ -609,6 +609,12 @@ class Objects(using Context @constructorOnly):
609
609
case (ValueSet (values), b : ValueElement ) => ValueSet (values + b)
610
610
case (a : ValueElement , b : ValueElement ) => ValueSet (ListSet (a, b))
611
611
612
+ def remove (b : Value ): Value = (a, b) match
613
+ case (ValueSet (values1), b : ValueElement ) => ValueSet (values1 - b)
614
+ case (ValueSet (values1), ValueSet (values2)) => ValueSet (values1.removedAll(values2))
615
+ case (a : Ref , b : Ref ) if a.equals(b) => Bottom
616
+ case _ => a
617
+
612
618
def widen (height : Int )(using Context ): Value =
613
619
if height == 0 then Cold
614
620
else
@@ -1348,29 +1354,25 @@ class Objects(using Context @constructorOnly):
1348
1354
def getMemberMethod (receiver : Type , name : TermName , tp : Type ): Denotation =
1349
1355
receiver.member(name).suchThat(receiver.memberInfo(_) <:< tp)
1350
1356
1351
- def evalCase (caseDef : CaseDef ): Value =
1352
- evalPattern(scrutinee, caseDef.pat)
1353
- eval(caseDef.guard, thisV, klass)
1354
- eval(caseDef.body, thisV, klass)
1355
-
1356
1357
/** Abstract evaluation of patterns.
1357
1358
*
1358
1359
* It augments the local environment for bound pattern variables. As symbols are globally
1359
1360
* unique, we can put them in a single environment.
1360
1361
*
1361
1362
* Currently, we assume all cases are reachable, thus all patterns are assumed to match.
1362
1363
*/
1363
- def evalPattern (scrutinee : Value , pat : Tree ): Value = log(" match " + scrutinee.show + " against " + pat.show, printer, (_ : Value ).show):
1364
+ def evalPattern (scrutinee : Value , pat : Tree ): ( Type , Value ) = log(" match " + scrutinee.show + " against " + pat.show, printer, (_ : ( Type , Value ))._2 .show):
1364
1365
val trace2 = Trace .trace.add(pat)
1365
1366
pat match
1366
1367
case Alternative (pats) =>
1367
- for pat <- pats do evalPattern(scrutinee, pat)
1368
- scrutinee
1368
+ val (types, values) = pats.map(evalPattern(scrutinee, _)).unzip()
1369
+ val orType = types.fold(defn.NothingType )(OrType (_, _, false ))
1370
+ (orType, values.join)
1369
1371
1370
1372
case bind @ Bind (_, pat) =>
1371
- val value = evalPattern(scrutinee, pat)
1373
+ val (tpe, value) = evalPattern(scrutinee, pat)
1372
1374
initLocal(bind.symbol, value)
1373
- scrutinee
1375
+ (tpe, value)
1374
1376
1375
1377
case UnApply (fun, implicits, pats) =>
1376
1378
given Trace = trace2
@@ -1379,6 +1381,10 @@ class Objects(using Context @constructorOnly):
1379
1381
val funRef = fun1.tpe.asInstanceOf [TermRef ]
1380
1382
val unapplyResTp = funRef.widen.finalResultType
1381
1383
1384
+ val receiverType = fun1 match
1385
+ case ident : Ident => funRef.prefix
1386
+ case select : Select => select.qualifier.tpe
1387
+
1382
1388
val receiver = fun1 match
1383
1389
case ident : Ident =>
1384
1390
evalType(funRef.prefix, thisV, klass)
@@ -1467,17 +1473,18 @@ class Objects(using Context @constructorOnly):
1467
1473
end if
1468
1474
end if
1469
1475
end if
1470
- scrutinee
1476
+ (receiverType, scrutinee.filterType(receiverType))
1471
1477
1472
1478
case Ident (nme.WILDCARD ) | Ident (nme.WILDCARD_STAR ) =>
1473
- scrutinee
1479
+ (defn. ThrowableType , scrutinee)
1474
1480
1475
- case Typed (pat, _) =>
1476
- evalPattern(scrutinee, pat)
1481
+ case Typed (pat, typeTree) =>
1482
+ val (_, value) = evalPattern(scrutinee.filterType(typeTree.tpe), pat)
1483
+ (typeTree.tpe, value)
1477
1484
1478
1485
case tree =>
1479
1486
// For all other trees, the semantics is normal.
1480
- eval(tree, thisV, klass)
1487
+ (defn. ThrowableType , eval(tree, thisV, klass) )
1481
1488
1482
1489
end evalPattern
1483
1490
@@ -1501,12 +1508,12 @@ class Objects(using Context @constructorOnly):
1501
1508
if isWildcardStarArgList(pats) then
1502
1509
if pats.size == 1 then
1503
1510
// call .toSeq
1504
- val toSeqDenot = getMemberMethod( scrutineeType, nme.toSeq, toSeqType(elemType) )
1511
+ val toSeqDenot = scrutineeType.member( nme.toSeq).suchThat(_.info.isParameterless )
1505
1512
val toSeqRes = call(scrutinee, toSeqDenot.symbol, Nil , scrutineeType, superType = NoType , needResolve = true )
1506
1513
evalPattern(toSeqRes, pats.head)
1507
1514
else
1508
1515
// call .drop
1509
- val dropDenot = getMemberMethod(scrutineeType, nme.drop, dropType (elemType))
1516
+ val dropDenot = getMemberMethod(scrutineeType, nme.drop, applyType (elemType))
1510
1517
val dropRes = call(scrutinee, dropDenot.symbol, ArgInfo (Bottom , summon[Trace ], EmptyTree ) :: Nil , scrutineeType, superType = NoType , needResolve = true )
1511
1518
for pat <- pats.init do evalPattern(applyRes, pat)
1512
1519
evalPattern(dropRes, pats.last)
@@ -1517,8 +1524,21 @@ class Objects(using Context @constructorOnly):
1517
1524
end if
1518
1525
end evalSeqPatterns
1519
1526
1527
+ def canSkipCase (remainingScrutinee : Value , catchValue : Value ) =
1528
+ (remainingScrutinee == Bottom && scrutinee != Bottom ) ||
1529
+ (catchValue == Bottom && remainingScrutinee != Bottom )
1520
1530
1521
- cases.map(evalCase).join
1531
+ var remainingScrutinee = scrutinee
1532
+ val caseResults : mutable.ArrayBuffer [Value ] = mutable.ArrayBuffer ()
1533
+ for caseDef <- cases do
1534
+ val (tpe, value) = evalPattern(remainingScrutinee, caseDef.pat)
1535
+ eval(caseDef.guard, thisV, klass)
1536
+ if ! canSkipCase(remainingScrutinee, value) then
1537
+ caseResults.addOne(eval(caseDef.body, thisV, klass))
1538
+ if catchesAllOf(caseDef, tpe) then
1539
+ remainingScrutinee = remainingScrutinee.remove(value)
1540
+
1541
+ caseResults.join
1522
1542
end patternMatch
1523
1543
1524
1544
/** Handle semantics of leaf nodes
0 commit comments