Skip to content

Commit 37c52ad

Browse files
committed
Fix setup of class constructors
Fox the containsCovarRetains criterion that decides when to make a parameter not provate for the purposes of capture checking. We were missing a dealias, so `A => B` was not detected to contain a capture set. Also avoid refining with the same name twice in inferred types.
1 parent 2f32850 commit 37c52ad

File tree

3 files changed

+80
-3
lines changed

3 files changed

+80
-3
lines changed

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

+11-3
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,13 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
9595
def apply(x: Boolean, tp: Type): Boolean =
9696
if x then true
9797
else if tp.derivesFromCapability && variance >= 0 then true
98-
else tp match
98+
else tp.dealiasKeepAnnots match
9999
case AnnotatedType(_, ann) if ann.symbol.isRetains && variance >= 0 => true
100100
case t: TypeRef if t.symbol.isAbstractOrParamType && !seen.contains(t.symbol) =>
101101
seen += t.symbol
102102
apply(x, t.info.bounds.hi)
103-
case _ => foldOver(x, tp)
103+
case tp1 =>
104+
foldOver(x, tp1)
104105
def apply(tp: Type): Boolean = apply(false, tp)
105106

106107
if symd.symbol.isRefiningParamAccessor
@@ -270,6 +271,8 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
270271
def mapInferred(refine: Boolean): TypeMap = new TypeMap with SetupTypeMap:
271272
override def toString = "map inferred"
272273

274+
var refiningNames: Set[Name] = Set()
275+
273276
/** Refine a possibly applied class type C where the class has tracked parameters
274277
* x_1: T_1, ..., x_n: T_n to C { val x_1: T_1^{CV_1}, ..., val x_n: T_n^{CV_n} }
275278
* where CV_1, ..., CV_n are fresh capture set variables.
@@ -282,7 +285,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
282285
cls.paramGetters.foldLeft(tp) { (core, getter) =>
283286
if atPhase(thisPhase.next)(getter.hasTrackedParts)
284287
&& getter.isRefiningParamAccessor
285-
&& !getter.is(Tracked)
288+
&& !refiningNames.contains(getter.name) // Don't add a refinement if we have already an explicit one for the same name
286289
then
287290
val getterType =
288291
mapInferred(refine = false)(tp.memberInfo(getter)).strippedDealias
@@ -306,6 +309,11 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
306309
tp.derivedLambdaType(
307310
paramInfos = tp.paramInfos.mapConserve(_.dropAllRetains.bounds),
308311
resType = this(tp.resType))
312+
case tp @ RefinedType(parent, rname, rinfo) =>
313+
val saved = refiningNames
314+
refiningNames += rname
315+
val parent1 = try this(parent) finally refiningNames = saved
316+
tp.derivedRefinedType(parent1, rname, this(rinfo))
309317
case _ =>
310318
mapFollowingAliases(tp)
311319
addVar(
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/leaky.scala:14:2 -----------------------------------------
2+
14 | val f: Any ->{a} Any = _ => // error
3+
| ^
4+
| Found: test.runnable.Transform{val fun: Any ->{a} Any}^{a}
5+
| Required: test.runnable.Transform
6+
15 | a.print()
7+
16 | ()
8+
17 | Transform(f)
9+
|
10+
| longer explanation available when compiling with `-explain`
11+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/leaky.scala:20:2 -----------------------------------------
12+
20 | val f: Any ->{a} Any = _ => // error
13+
| ^
14+
| Found: test.runnable.Transform{val fun: Any ->{a} Any}^{a}
15+
| Required: test.runnable.Transform
16+
21 | a.print()
17+
22 | ()
18+
23 | val x = Transform(f)
19+
24 | x
20+
|
21+
| longer explanation available when compiling with `-explain`
22+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/leaky.scala:27:2 -----------------------------------------
23+
27 | val f: Any ->{a} Any = _ => // error
24+
| ^
25+
| Found: test.runnable.Transform{val fun: Any ->{a} Any}^{a}
26+
| Required: test.runnable.Transform
27+
28 | a.print()
28+
29 | ()
29+
30 | val x = Transform.app(f)
30+
31 | x
31+
|
32+
| longer explanation available when compiling with `-explain`
+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package test.runnable
2+
import language.experimental.captureChecking
3+
4+
case class A() extends caps.Capability:
5+
def print() = println("leaking...")
6+
7+
class Transform(fun: Any => Any):
8+
def run() = fun(())
9+
object Transform:
10+
def app(f: Any => Any): Transform { val fun: Any->{f} Any } ^ {f} =
11+
Transform(f)
12+
13+
def leak(a: A): Transform^{} =
14+
val f: Any ->{a} Any = _ => // error
15+
a.print()
16+
()
17+
Transform(f)
18+
19+
def leak1(a: A): Transform^{} =
20+
val f: Any ->{a} Any = _ => // error
21+
a.print()
22+
()
23+
val x = Transform(f)
24+
x
25+
26+
def leak2(a: A): Transform^{} =
27+
val f: Any ->{a} Any = _ => // error
28+
a.print()
29+
()
30+
val x = Transform.app(f)
31+
x
32+
33+
def withA[T](body: A => T): T = body(A())
34+
35+
@main def Main() =
36+
val t = withA(leak)
37+
t.run()

0 commit comments

Comments
 (0)