Skip to content

Commit ae1fa0b

Browse files
committed
Revise avoidance scheme according to proposal by @Linyxus
1 parent 5bd67bb commit ae1fa0b

File tree

5 files changed

+45
-3
lines changed

5 files changed

+45
-3
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,18 @@ object TypeOps:
533533
val sym = tp.symbol
534534
forbidden.contains(sym)
535535

536+
/** We need to split the set into upper and lower approximations
537+
* only if it contains a local element. The idea here is that at the
538+
* time we perform an `avoid` all local elements are already accounted for
539+
* and no further elements will be added afterwards. So we can just keep
540+
* the set as it is. See comment by @linyxus on #16261.
541+
*/
542+
override def needsRangeIfInvariant(refs: CaptureSet): Boolean =
543+
refs.elems.exists {
544+
case ref: TermRef => toAvoid(ref)
545+
case _ => false
546+
}
547+
536548
override def apply(tp: Type): Type = tp match
537549
case tp: TypeVar if mapCtx.typerState.constraint.contains(tp) =>
538550
val lo = TypeComparer.instanceType(

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6025,8 +6025,11 @@ object Types {
60256025
tp.derivedLambdaType(tp.paramNames, formals, restpe)
60266026
}
60276027

6028+
/** Overridden in TypeOps.avoid */
6029+
protected def needsRangeIfInvariant(refs: CaptureSet): Boolean = true
6030+
60286031
override def mapCapturingType(tp: Type, parent: Type, refs: CaptureSet, v: Int): Type =
6029-
if v == 0 then
6032+
if v == 0 && needsRangeIfInvariant(refs) then
60306033
range(mapCapturingType(tp, parent, refs, -1), mapCapturingType(tp, parent, refs, 1))
60316034
else
60326035
super.mapCapturingType(tp, parent, refs, v)

tests/neg-custom-args/captures/try.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/try.scala:23:49 ------------------------------------------
22
23 | val a = handle[Exception, CanThrow[Exception]] { // error
33
| ^
4-
| Found: ? ({*} CT[Exception]) -> {*} CT[? >: ? Exception <: ? Exception]
5-
| Required: CanThrow[Exception] => box {*} CT[Exception]
4+
| Found: ? ({*} CT[Exception]) -> CanThrow[? Exception]
5+
| Required: CanThrow[Exception] => box {*} CT[Exception]
66
24 | (x: CanThrow[Exception]) => x
77
25 | }{
88
|
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@annotation.capability class Cap
2+
3+
class LazyRef[T](val elem: () => T):
4+
val get: {elem} () -> T = elem
5+
def map[U](f: T => U): {f, this} LazyRef[U] =
6+
new LazyRef(() => f(elem()))
7+
8+
def map[A, B](ref: {*} LazyRef[A], f: A => B): {f, ref} LazyRef[B] =
9+
new LazyRef(() => f(ref.elem()))
10+
11+
def main(io: Cap) = {
12+
def mapd[A, B]: ({io} LazyRef[A], A => B) => {*} LazyRef[B] =
13+
(ref1, f1) => map[A, B](ref1, f1)
14+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class Name
2+
class TermName extends Name
3+
class TypeName extends Name
4+
5+
trait ParamInfo:
6+
type ThisName <: Name
7+
def variance: Long
8+
object ParamInfo:
9+
type Of[N <: Name] = ParamInfo { type ThisName = N }
10+
11+
def test(tparams1: List[ParamInfo{ type ThisName = TypeName }], tparams2: List[ParamInfo.Of[TypeName]]) =
12+
tparams1.lazyZip(tparams2).map((p1, p2) => p1.variance + p2.variance)
13+

0 commit comments

Comments
 (0)