@@ -1568,17 +1568,81 @@ class CheckCaptures extends Recheck, SymTransformer:
15681568 * to narrow to the read-only set, since that set can be propagated
15691569 * by the type variable instantiation.
15701570 */
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)
15801643 case _ =>
15811644 actual
1645+ end improveReadOnly
15821646
15831647 /* Currently not needed since it forms part of `adapt`
15841648 private def improve(actual: Type, prefix: Type)(using Context): Type =
0 commit comments