Skip to content

Commit ec86d5e

Browse files
committed
Expand aliases when mapping explicit types in Setup
This is necessary because the compiler is free in previous phases to dealias or not. Therefore, capture checking should not depend on aliasing. The main difference is that now arguments to type aliases are not necessarily boxed. They are boxed only if they need boxing in the dealiased type.
1 parent ecf3428 commit ec86d5e

21 files changed

+102
-83
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ object ccConfig:
4949

5050
end ccConfig
5151

52-
5352
/** Are we at checkCaptures phase? */
5453
def isCaptureChecking(using Context): Boolean =
5554
ctx.phaseId == Phases.checkCapturesPhase.id

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
278278
paramInfos = tp.paramInfos.mapConserve(_.dropAllRetains.bounds),
279279
resType = this(tp.resType))
280280
case _ =>
281-
mapOver(tp)
281+
mapFollowingAliases(tp)
282282
addVar(addCaptureRefinements(normalizeCaptures(tp1)), ctx.owner)
283283
end apply
284284
end mapInferred
@@ -364,7 +364,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
364364
// Map references to capability classes C to C^
365365
if t.derivesFromCapability && !t.isSingleton && t.typeSymbol != defn.Caps_Exists
366366
then CapturingType(t, defn.universalCSImpliedByCapability, boxed = false)
367-
else normalizeCaptures(mapOver(t))
367+
else normalizeCaptures(mapFollowingAliases(t))
368368
end toCapturing
369369

370370
def fail(msg: Message) =
@@ -821,7 +821,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI:
821821
case tp @ OrType(tp1, tp2 @ CapturingType(parent2, refs2)) =>
822822
CapturingType(OrType(tp1, parent2, tp.isSoft), refs2, tp2.isBoxed)
823823
case tp @ AppliedType(tycon, args)
824-
if !defn.isFunctionClass(tp.dealias.typeSymbol) =>
824+
if !defn.isFunctionClass(tp.dealias.typeSymbol) && (tp.dealias eq tp) =>
825825
tp.derivedAppliedType(tycon, args.mapConserve(box))
826826
case tp: RealTypeBounds =>
827827
tp.derivedTypeBounds(tp.lo, box(tp.hi))

tests/neg-custom-args/captures/boundschecks2.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ object test {
88

99
val foo: C[Tree^] = ??? // error
1010
type T = C[Tree^] // error
11-
val bar: T -> T = ???
11+
//val bar: T -> T = ??? // --> boundschecks3.scala for what happens if we uncomment
1212
val baz: C[Tree^] -> Unit = ??? // error
1313
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- Error: tests/neg-custom-args/captures/boundschecks3.scala:11:13 -----------------------------------------------------
2+
11 | val bar: T -> T = ??? // error, since `T` is expanded here. But the msg is not very good.
3+
| ^^^^^^
4+
| test.C[box test.Tree^] captures the root capability `cap` in invariant position
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
object test {
2+
3+
class Tree
4+
5+
def f[X <: Tree](x: X): Unit = ()
6+
7+
class C[X <: Tree](x: X)
8+
9+
val foo: C[Tree^] = ??? // hidden error
10+
type T = C[Tree^] // hidden error
11+
val bar: T -> T = ??? // error, since `T` is expanded here. But the msg is not very good.
12+
val baz: C[Tree^] -> Unit = ??? // hidden error
13+
}
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/box-adapt-cases.scala:14:4 -------------------------------
2-
14 | x(cap => cap.use()) // error
3-
| ^^^^^^^^^^^^^^^^
4-
| Found: (cap: box Cap^?) ->{io} Int
5-
| Required: (cap: box Cap^{io}) -> Int
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/box-adapt-cases.scala:14:10 ------------------------------
2+
14 | x.value(cap => cap.use()) // error
3+
| ^^^^^^^^^^^^^^^^
4+
| Found: (cap: box Cap^?) ->{io} Int
5+
| Required: (cap: box Cap^{io}) -> Int
66
|
77
| longer explanation available when compiling with `-explain`
8-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/box-adapt-cases.scala:28:4 -------------------------------
9-
28 | x(cap => cap.use()) // error
10-
| ^^^^^^^^^^^^^^^^
11-
| Found: (cap: box Cap^?) ->{io, fs} Int
12-
| Required: (cap: box Cap^{io, fs}) ->{io} Int
8+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/box-adapt-cases.scala:28:10 ------------------------------
9+
28 | x.value(cap => cap.use()) // error
10+
| ^^^^^^^^^^^^^^^^
11+
| Found: (cap: box Cap^?) ->{io, fs} Int
12+
| Required: (cap: box Cap^{io, fs}) ->{io} Int
1313
|
1414
| longer explanation available when compiling with `-explain`
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
trait Cap { def use(): Int }
22

33
def test1(): Unit = {
4-
type Id[X] = [T] -> (op: X => T) -> T
4+
class Id[X](val value: [T] -> (op: X => T) -> T)
55

66
val x: Id[Cap^] = ???
7-
x(cap => cap.use())
7+
x.value(cap => cap.use())
88
}
99

1010
def test2(io: Cap^): Unit = {
11-
type Id[X] = [T] -> (op: X -> T) -> T
11+
class Id[X](val value: [T] -> (op: X -> T) -> T)
1212

1313
val x: Id[Cap^{io}] = ???
14-
x(cap => cap.use()) // error
14+
x.value(cap => cap.use()) // error
1515
}
1616

1717
def test3(io: Cap^): Unit = {
18-
type Id[X] = [T] -> (op: X ->{io} T) -> T
18+
class Id[X](val value: [T] -> (op: X ->{io} T) -> T)
1919

2020
val x: Id[Cap^{io}] = ???
21-
x(cap => cap.use()) // ok
21+
x.value(cap => cap.use()) // ok
2222
}
2323

2424
def test4(io: Cap^, fs: Cap^): Unit = {
25-
type Id[X] = [T] -> (op: X ->{io} T) -> T
25+
class Id[X](val value: [T] -> (op: X ->{io} T) -> T)
2626

2727
val x: Id[Cap^{io, fs}] = ???
28-
x(cap => cap.use()) // error
28+
x.value(cap => cap.use()) // error
2929
}
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
trait Cap
22

33
def test1(io: Cap^) = {
4-
type Op[X] = [T] -> Unit -> X
4+
class Op[+X](val value: [T] -> Unit -> X)
55
val f: Op[Cap^{io}] = ???
6-
val x: [T] -> Unit -> Cap^{io} = f // error
6+
val x: [T] -> Unit -> Cap^{io} = f.value // error
77
}
88

99
def test2(io: Cap^) = {
10-
type Op[X] = [T] -> Unit -> X^{io}
10+
class Op[+X](val value: [T] -> Unit -> X^{io})
1111
val f: Op[Cap^{io}] = ???
12-
val x: Unit -> Cap^{io} = f[Unit] // error
13-
val x1: Unit ->{io} Cap^{io} = f[Unit] // ok
12+
val x: Unit -> Cap^{io} = f.value[Unit] // error
13+
val x1: Unit ->{io} Cap^{io} = f.value[Unit] // ok
1414
}
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
trait Cap { def use(): Int }
22

33
def test1(io: Cap^): Unit = {
4-
type Id[X] = [T] -> (op: X ->{io} T) -> T
4+
class Id[X](val value: [T] -> (op: X ->{io} T) -> T)
55

66
val x: Id[Cap]^{io} = ???
7-
x(cap => cap.use()) // ok
7+
x.value(cap => cap.use()) // ok
88
}
99

1010
def test2(io: Cap^): Unit = {
11-
type Id[X] = [T] -> (op: (x: X) ->{io} T) -> T
11+
class Id[X](val value: [T] -> (op: (x: X) ->{io} T) -> T)
1212

1313
val x: Id[Cap^{io}] = ???
14-
x(cap => cap.use())
14+
x.value(cap => cap.use())
1515
// should work when the expected type is a dependent function
1616
}
1717

1818
def test3(io: Cap^): Unit = {
19-
type Id[X] = [T] -> (op: (x: X) ->{} T) -> T
19+
class Id[X](val value: [T] -> (op: (x: X) ->{} T) -> T)
2020

2121
val x: Id[Cap^{io}] = ???
22-
x(cap => cap.use()) // error
22+
x.value(cap => cap.use()) // error
2323
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
trait Cap { def use(): Int }
22

33
def test1(io: Cap^): Unit = {
4-
type Op[X] = [T] -> X -> Unit
4+
class Op[X](val value: [T] -> X -> Unit)
55
val f: [T] -> (Cap^{io}) -> Unit = ???
6-
val op: Op[Cap^{io}] = f // error
6+
val op: Op[Cap^{io}] = Op(f) // was error, now ok
77
}
88

99
def test2(io: Cap^): Unit = {
10-
type Lazy[X] = [T] -> Unit -> X
10+
class Lazy[X](val value: [T] -> Unit -> X)
1111
val f: Lazy[Cap^{io}] = ???
12-
val test: [T] -> Unit -> (Cap^{io}) = f // error
12+
val test: [T] -> Unit -> (Cap^{io}) = f.value // error
1313
}

0 commit comments

Comments
 (0)