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