@@ -1568,17 +1568,81 @@ class CheckCaptures extends Recheck, SymTransformer:
1568
1568
* to narrow to the read-only set, since that set can be propagated
1569
1569
* by the type variable instantiation.
1570
1570
*/
1571
- private def improveReadOnly (actual : Type , expected : Type )(using Context ): Type = actual match
1572
- case actual @ CapturingType (parent, refs)
1573
- if parent.derivesFrom(defn.Caps_Mutable )
1574
- && expected.isValueType
1575
- && ! expected.derivesFromMutable
1576
- && ! expected.isSingleton
1577
- && ! expected.isBoxedCapturing =>
1578
- actual.derivedCapturingType(parent, refs.readOnly)
1579
- .showing(i " improv ro $actual vs $expected = $result" , capt)
1571
+ private def improveReadOnly (actual : Type , expected : Type )(using Context ): Type = reporting.trace(i " improv ro $actual vs $expected" ):
1572
+ actual.dealiasKeepAnnots match
1573
+ case actual @ CapturingType (parent, refs) =>
1574
+ val parent1 = improveReadOnly(parent, expected)
1575
+ val refs1 =
1576
+ if parent1.derivesFrom(defn.Caps_Mutable )
1577
+ && expected.isValueType
1578
+ && (! expected.derivesFromMutable || expected.captureSet.isAlwaysReadOnly)
1579
+ && ! expected.isSingleton
1580
+ && actual.isBoxedCapturing == expected.isBoxedCapturing
1581
+ then refs.readOnly
1582
+ else refs
1583
+ actual.derivedCapturingType(parent1, refs1)
1584
+ case actual @ FunctionOrMethod (aargs, ares) =>
1585
+ expected.dealias.stripCapturing match
1586
+ case FunctionOrMethod (eargs, eres) =>
1587
+ actual.derivedFunctionOrMethod(aargs, improveReadOnly(ares, eres))
1588
+ case _ =>
1589
+ actual
1590
+ case actual @ AppliedType (atycon, aargs) =>
1591
+ def improveArgs (aargs : List [Type ], eargs : List [Type ], formals : List [ParamInfo ]): List [Type ] =
1592
+ aargs match
1593
+ case aargs @ (aarg :: aargs1) =>
1594
+ val aarg1 =
1595
+ if formals.head.paramVariance.is(Covariant )
1596
+ then improveReadOnly(aarg, eargs.head)
1597
+ else aarg
1598
+ aargs.derivedCons(aarg1, improveArgs(aargs1, eargs.tail, formals.tail))
1599
+ case Nil =>
1600
+ aargs
1601
+ val expected1 = expected.dealias.stripCapturing
1602
+ val esym = expected1.typeSymbol
1603
+ expected1 match
1604
+ case AppliedType (etycon, eargs) =>
1605
+ if atycon.typeSymbol == esym then
1606
+ actual.derivedAppliedType(atycon,
1607
+ improveArgs(aargs, eargs, etycon.typeParams))
1608
+ else if esym.isClass then
1609
+ // This case is tricky: Try to lift actual to the base type with class `esym`,
1610
+ // improve the resulting arguments, and figure out if anything can be
1611
+ // deduced from that for the original arguments.
1612
+ actual.baseType(esym) match
1613
+ case base @ AppliedType (_, bargs) =>
1614
+ // If any of the base type arguments can be improved, check
1615
+ // whether they are the same as an original argument, and in this
1616
+ // case improve the original argument.
1617
+ val iargs = improveArgs(bargs, eargs, etycon.typeParams)
1618
+ if iargs ne bargs then
1619
+ val updates =
1620
+ for
1621
+ (barg, iarg) <- bargs.lazyZip(iargs)
1622
+ if barg ne iarg
1623
+ aarg <- aargs.find(_ eq barg)
1624
+ yield (aarg, iarg)
1625
+ if updates.nonEmpty then AppliedType (atycon, aargs.map(updates.toMap))
1626
+ else actual
1627
+ else actual
1628
+ case _ => actual
1629
+ else actual
1630
+ case _ =>
1631
+ actual
1632
+ case actual @ RefinedType (aparent, aname, ainfo) =>
1633
+ expected.dealias.stripCapturing match
1634
+ case RefinedType (eparent, ename, einfo) if aname == ename =>
1635
+ actual.derivedRefinedType(
1636
+ improveReadOnly(aparent, eparent),
1637
+ aname,
1638
+ improveReadOnly(ainfo, einfo))
1639
+ case _ =>
1640
+ actual
1641
+ case actual @ AnnotatedType (parent, ann) =>
1642
+ actual.derivedAnnotatedType(improveReadOnly(parent, expected), ann)
1580
1643
case _ =>
1581
1644
actual
1645
+ end improveReadOnly
1582
1646
1583
1647
/* Currently not needed since it forms part of `adapt`
1584
1648
private def improve(actual: Type, prefix: Type)(using Context): Type =
0 commit comments