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