Skip to content

Commit 7c34545

Browse files
committed
Treat added class refinements as inferred types for further processing
Without that step, class refinements can contain references to the generic root `cap`.
1 parent 1c294ef commit 7c34545

File tree

6 files changed

+60
-20
lines changed

6 files changed

+60
-20
lines changed

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,26 +166,27 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
166166
* pos.../lists.scala and pos/...curried-shorthands.scala fail.
167167
* Need to figure out why.
168168
* 3. Refine other class types C by adding capture set variables to their parameter getters
169-
* (see addCaptureRefinements)
169+
* (see addCaptureRefinements), provided `refine` is true.
170170
* 4. Add capture set variables to all types that can be tracked
171171
*
172172
* Polytype bounds are only cleaned using step 1, but not otherwise transformed.
173173
*/
174-
private def mapInferred(using Context) = new TypeMap:
174+
private def mapInferred(refine: Boolean)(using Context): TypeMap = new TypeMap:
175175
override def toString = "map inferred"
176176

177177
/** Refine a possibly applied class type C where the class has tracked parameters
178178
* x_1: T_1, ..., x_n: T_n to C { val x_1: CV_1 T_1, ..., val x_n: CV_n T_n }
179179
* where CV_1, ..., CV_n are fresh capture sets.
180180
*/
181181
def addCaptureRefinements(tp: Type): Type = tp match
182-
case _: TypeRef | _: AppliedType if tp.typeParams.isEmpty =>
182+
case _: TypeRef | _: AppliedType if refine && tp.typeParams.isEmpty =>
183183
tp.typeSymbol match
184184
case cls: ClassSymbol
185185
if !defn.isFunctionClass(cls) && cls.is(CaptureChecked) =>
186186
cls.paramGetters.foldLeft(tp) { (core, getter) =>
187187
if atPhase(thisPhase.next)(getter.termRef.isTracked) then
188-
val getterType = tp.memberInfo(getter).strippedDealias
188+
val getterType =
189+
mapInferred(refine = false)(tp.memberInfo(getter)).strippedDealias
189190
RefinedType(core, getter.name,
190191
CapturingType(getterType, CaptureSet.RefiningVar(NoSymbol, getter)))
191192
.showing(i"add capture refinement $tp --> $result", ccSetup)
@@ -254,7 +255,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
254255
end mapInferred
255256

256257
private def transformInferredType(tp: Type)(using Context): Type =
257-
mapInferred(tp)
258+
mapInferred(refine = true)(tp)
258259

259260
private def transformExplicitType(tp: Type, rootTarget: Symbol, tptToCheck: Option[Tree] = None)(using Context): Type =
260261
val expandAliases = new DeepTypeMap:

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15772.scala:20:46 ---------------------------------------
77
20 | val boxed1 : ((C^) => Unit) -> Unit = box1(c) // error
88
| ^^^^^^^
9-
| Found: (C{val arg: C^{cap[C]}}^{c} ->{'cap[main1..boxed1](from instantiating box1), c} Unit) ->{c} Unit
10-
| Required: (C^{cap[boxed1]} ->{cap[boxed1]} Unit) -> Unit
9+
| Found: (C{val arg: C^{cap[main1]}}^{c} ->{'cap[main1..boxed1](from instantiating box1), c} Unit) ->{c} Unit
10+
| Required: (C^{cap[boxed1]} ->{cap[boxed1]} Unit) -> Unit
1111
|
1212
| longer explanation available when compiling with `-explain`
1313
-- Error: tests/neg-custom-args/captures/i15772.scala:26:26 ------------------------------------------------------------
@@ -18,15 +18,15 @@
1818
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15772.scala:27:35 ---------------------------------------
1919
27 | val boxed2 : Observe[C^] = box2(c) // error
2020
| ^^^^^^^
21-
| Found: (C{val arg: C^{cap[C]}}^{c} ->{'cap[main2..boxed2](from instantiating box2), c} Unit) ->{c} Unit
22-
| Required: (C^{cap[boxed2]} ->{cap[boxed2]} Unit) -> Unit
21+
| Found: (C{val arg: C^{cap[main2]}}^{c} ->{'cap[main2..boxed2](from instantiating box2), c} Unit) ->{c} Unit
22+
| Required: (C^{cap[boxed2]} ->{cap[boxed2]} Unit) -> Unit
2323
|
2424
| longer explanation available when compiling with `-explain`
2525
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15772.scala:33:33 ---------------------------------------
2626
33 | val boxed2 : Observe[C]^ = box2(c) // error
2727
| ^^^^^^^
28-
| Found: (C{val arg: C^{cap[C]}}^{cap[main3]} ->{cap[main3]} Unit) ->{cap[main3]} Unit
29-
| Required: (C ->{cap[boxed2]} Unit) ->{cap[boxed2]} Unit
28+
| Found: (C{val arg: C^{cap[main3]}}^{cap[main3]} ->{cap[main3]} Unit) ->{cap[main3]} Unit
29+
| Required: (C ->{cap[boxed2]} Unit) ->{cap[boxed2]} Unit
3030
|
3131
| longer explanation available when compiling with `-explain`
3232
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i15772.scala:44:2 ----------------------------------------

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylist.scala:35:29 -------------------------------------
99
35 | val ref1c: LazyList[Int] = ref1 // error
1010
| ^^^^
11-
| Found: (ref1 : lazylists.LazyCons[Int]{val xs: () ->{cap1} lazylists.LazyList[Int]^}^{cap1})
12-
| Required: lazylists.LazyList[Int]
11+
| Found: lazylists.LazyCons[Int]{val xs: () ->{cap1} lazylists.LazyList[Int]^?}^{ref1}
12+
| Required: lazylists.LazyList[Int]
1313
|
1414
| longer explanation available when compiling with `-explain`
1515
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylist.scala:37:36 -------------------------------------
Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazyref.scala:19:28 --------------------------------------
22
19 | val ref1c: LazyRef[Int] = ref1 // error
33
| ^^^^
4-
| Found: (ref1 : LazyRef[Int]{val elem: () ->{cap1} Int}^{cap1})
4+
| Found: LazyRef[Int]{val elem: () ->{cap1} Int}^{ref1}
55
| Required: LazyRef[Int]
66
|
77
| longer explanation available when compiling with `-explain`
88
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazyref.scala:21:35 --------------------------------------
99
21 | val ref2c: LazyRef[Int]^{cap2} = ref2 // error
1010
| ^^^^
11-
| Found: (ref2 : LazyRef[Int]{val elem: () ->{cap[<root>]} Int}^{cap2, ref1})
12-
| Required: LazyRef[Int]^{cap2}
11+
| Found: LazyRef[Int]{val elem: () ->{cap[test]} Int}^{ref2}
12+
| Required: LazyRef[Int]^{cap2}
1313
|
1414
| longer explanation available when compiling with `-explain`
1515
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazyref.scala:23:35 --------------------------------------
1616
23 | val ref3c: LazyRef[Int]^{ref1} = ref3 // error
1717
| ^^^^
18-
| Found: (ref3 : LazyRef[Int]{val elem: () ->{cap[<root>]} Int}^{cap2, ref1})
19-
| Required: LazyRef[Int]^{ref1}
18+
| Found: LazyRef[Int]{val elem: () ->{cap[test]} Int}^{ref3}
19+
| Required: LazyRef[Int]^{ref1}
2020
|
2121
| longer explanation available when compiling with `-explain`
2222
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazyref.scala:25:35 --------------------------------------
2323
25 | val ref4c: LazyRef[Int]^{cap1} = ref4 // error
2424
| ^^^^
25-
| Found: (ref4 : LazyRef[Int]{val elem: () ->{cap[<root>]} Int}^{cap2, cap1})
26-
| Required: LazyRef[Int]^{cap1}
25+
| Found: LazyRef[Int]{val elem: () ->{cap[test]} Int}^{ref4}
26+
| Required: LazyRef[Int]^{cap1}
2727
|
2828
| longer explanation available when compiling with `-explain`
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
def f(x: (() => Unit)): (() => Unit) => (() => Unit) =
3+
def g(y: (() => Unit)): (() => Unit) = x
4+
g
5+
6+
def test1(x: (() => Unit)): Unit =
7+
def test2(y: (() => Unit)) =
8+
val a: (() => Unit) => (() => Unit) = f(y)
9+
a(x) // OK, but should be error
10+
test2(() => ())
11+
12+
def test2(x1: (() => Unit), x2: (() => Unit) => Unit) =
13+
class C1(x1: (() => Unit), xx2: (() => Unit) => Unit):
14+
def c2(y1: (() => Unit), y2: (() => Unit) => Unit): C2^{cap} = C2(y1, y2)
15+
class C2(y1: (() => Unit), y2: (() => Unit) => Unit):
16+
val a: (() => Unit) => (() => Unit) = f(y1)
17+
a(x1) //OK, but should be error
18+
C2(() => (), x => ())
19+
20+
def test3(y1: (() => Unit), y2: (() => Unit) => Unit) =
21+
val cc1/*: C1^{cap[test3]}*/ = C1(y1, y2) // error (but should be OK)
22+
val cc2 = cc1.c2(x1, x2) // error (but should be OK)
23+
()
24+
//val cc3: cc1.C2^{cap[test2]} = cc2
25+

tests/pos/functorial-functors.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class Common:
2+
3+
trait Functor:
4+
type F[X]
5+
extension [A](x: F[A]) def map[B](f: A => B): F[B]
6+
7+
trait Monad extends Functor:
8+
extension [A](x: F[A])
9+
def flatMap[B](f: A => F[B]): F[B]
10+
def map[B](f: A => B) = x.flatMap(f `andThen` pure)
11+
12+
def pure[A](x: A): F[A]
13+
end Common
14+

0 commit comments

Comments
 (0)