Skip to content

Commit e580166

Browse files
committed
Turn nested environment capture sets into constants at the end of box adaptation
This change lets more ref trees with underlying function types keep their singleton types.
1 parent e29f4fd commit e580166

File tree

7 files changed

+31
-17
lines changed

7 files changed

+31
-17
lines changed

compiler/src/dotty/tools/dotc/cc/CaptureSet.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,7 @@ object CaptureSet:
10801080
case _ =>
10811081
empty
10821082
recur(tp)
1083-
.showing(i"capture set of $tp = $result", captDebug)
1083+
//.showing(i"capture set of $tp = $result", captDebug)
10841084

10851085
private def deepCaptureSet(tp: Type)(using Context): CaptureSet =
10861086
val collect = new TypeAccumulator[CaptureSet]:

compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,7 +1006,7 @@ class CheckCaptures extends Recheck, SymTransformer:
10061006
if (ares1 eq ares) && (aargs1 eq aargs) then actual
10071007
else reconstruct(aargs1, ares1)
10081008

1009-
(resTp, curEnv.captured)
1009+
(resTp, CaptureSet(curEnv.captured.elems))
10101010
end adaptFun
10111011

10121012
/** Adapt type function type `actual` to the expected type.
@@ -1028,7 +1028,7 @@ class CheckCaptures extends Recheck, SymTransformer:
10281028
if ares1 eq ares then actual
10291029
else reconstruct(ares1)
10301030

1031-
(resTp, curEnv.captured)
1031+
(resTp, CaptureSet(curEnv.captured.elems))
10321032
end adaptTypeFun
10331033

10341034
def adaptInfo(actual: Type, expected: Type, covariant: Boolean): String =

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

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -842,13 +842,27 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
842842
val refs1 = tp1.captureSet
843843
try
844844
if refs1.isAlwaysEmpty then recur(tp1, parent2)
845-
else subCaptures(refs1, refs2, frozenConstraint).isOK
846-
&& sameBoxed(tp1, tp2, refs1)
847-
&& (recur(tp1.widen.stripCapturing, parent2)
848-
|| tp1.isInstanceOf[SingletonType] && recur(tp1, parent2)
849-
// this alternative is needed in case the right hand side is a
850-
// capturing type that contains the lhs as an alternative of a union type.
851-
)
845+
else
846+
// The singletonOK branch is because we sometimes have a larger capture set in a singleton
847+
// than in its underlying type. An example is `f: () -> () ->{x} T`, which might be
848+
// the type of a closure. In that case the capture set of `f.type` is `{x}` but the
849+
// capture set of the underlying type is `{}`. So without the `singletonOK` test, a singleton
850+
// might not be a subtype of its underlying type. Examples where this arises is
851+
// capt-capibility.scala and function-combinators.scala
852+
val singletonOK = tp1 match
853+
case tp1: SingletonType
854+
if subCaptures(tp1.underlying.captureSet, refs2, frozen = true).isOK =>
855+
recur(tp1.widen, tp2)
856+
case _ =>
857+
false
858+
singletonOK
859+
|| subCaptures(refs1, refs2, frozenConstraint).isOK
860+
&& sameBoxed(tp1, tp2, refs1)
861+
&& (recur(tp1.widen.stripCapturing, parent2)
862+
|| tp1.isInstanceOf[SingletonType] && recur(tp1, parent2)
863+
// this alternative is needed in case the right hand side is a
864+
// capturing type that contains the lhs as an alternative of a union type.
865+
)
852866
catch case ex: AssertionError =>
853867
println(i"assertion failed while compare captured $tp1 <:< $tp2")
854868
throw ex

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/byname.scala:4:2 -----------------------------------------
77
4 | def f() = if cap1 == cap1 then g else g // error
88
| ^
9-
| Found: (x$0: Int) ->{cap2} Int
10-
| Required: (x$0: Int) -> Int
9+
| Found: ((x$0: Int) ->{cap2} Int)^{}
10+
| Required: Int -> Int
1111
|
1212
| Note that the expected type Int ->{} Int
1313
| is the previously inferred result type of method test
1414
| which is also the type seen in separately compiled sources.
15-
| The new inferred type (x$0: Int) ->{cap2} Int
15+
| The new inferred type ((x$0: Int) ->{cap2} Int)^{}
1616
| must conform to this type.
1717
5 | def g(x: Int) = if cap2 == cap2 then 1 else x
1818
6 | def g2(x: Int) = if cap1 == cap1 then 1 else x

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/eta.scala:4:9 --------------------------------------------
22
4 | g // error
33
| ^
4-
| Found: () ->? A
4+
| Found: (g : () -> A)
55
| Required: () -> Proc^{f}
66
|
77
| longer explanation available when compiling with `-explain`

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15772.scala:44:2 ----------------------------------------
3636
44 | x: (() -> Unit) // error
3737
| ^
38-
| Found: () ->{x} Unit
38+
| Found: (x : () ->{filesList, sayHello} Unit)
3939
| Required: () -> Unit
4040
|
4141
| longer explanation available when compiling with `-explain`

tests/neg-custom-args/captures/outer-var.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/outer-var.scala:11:8 -------------------------------------
22
11 | x = q // error
33
| ^
4-
| Found: () ->{q} Unit
4+
| Found: (q : Proc)
55
| Required: () ->{p, q²} Unit
66
|
77
| where: q is a parameter in method inner
@@ -28,7 +28,7 @@
2828
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/outer-var.scala:14:8 -------------------------------------
2929
14 | y = q // error
3030
| ^
31-
| Found: () ->{q} Unit
31+
| Found: (q : Proc)
3232
| Required: () ->{p} Unit
3333
|
3434
| Note that reference (q : Proc), defined in method inner

0 commit comments

Comments
 (0)