Skip to content

Commit ce2e51e

Browse files
committed
Propagate expected type into blocks
The level checking should do the proper avoidance so that local symbols would not leak into type variables of the expected type.
1 parent 4e8f7d9 commit ce2e51e

21 files changed

+138
-162
lines changed

compiler/src/dotty/tools/dotc/transform/Recheck.scala

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -376,25 +376,21 @@ abstract class Recheck extends Phase, SymTransformer:
376376
recheck(tree.rhs, lhsType.widen)
377377
defn.UnitType
378378

379-
private def recheckBlock(stats: List[Tree], expr: Tree)(using Context): Type =
379+
private def recheckBlock(stats: List[Tree], expr: Tree, pt: Type)(using Context): Type =
380380
recheckStats(stats)
381-
val exprType = recheck(expr)
381+
val exprType = recheck(expr, pt)
382382
TypeOps.avoid(exprType, localSyms(stats).filterConserve(_.isTerm))
383383

384384
def recheckBlock(tree: Block, pt: Type)(using Context): Type = tree match
385-
case Block(Nil, expr: Block) => recheckBlock(expr, pt)
386385
case Block((mdef : DefDef) :: Nil, closure: Closure) =>
387386
recheckClosureBlock(mdef, closure.withSpan(tree.span), pt)
388-
case Block(stats, expr) => recheckBlock(stats, expr)
389-
// The expected type `pt` is not propagated. Doing so would allow variables in the
390-
// expected type to contain references to local symbols of the block, so the
391-
// local symbols could escape that way.
387+
case Block(stats, expr) => recheckBlock(stats, expr, pt)
392388

393389
def recheckClosureBlock(mdef: DefDef, expr: Closure, pt: Type)(using Context): Type =
394-
recheckBlock(mdef :: Nil, expr)
390+
recheckBlock(mdef :: Nil, expr, pt)
395391

396392
def recheckInlined(tree: Inlined, pt: Type)(using Context): Type =
397-
recheckBlock(tree.bindings, tree.expansion)(using inlineContext(tree))
393+
recheckBlock(tree.bindings, tree.expansion, pt)(using inlineContext(tree))
398394

399395
def recheckIf(tree: If, pt: Type)(using Context): Type =
400396
recheck(tree.cond, defn.BooleanType)

tests/neg-custom-args/captures/capt-test.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ def handle[E <: Exception, R <: Top](op: (CT[E] @retains[caps.cap.type]) => R)(
2020
catch case ex: E => handler(ex)
2121

2222
def test: Unit =
23-
val b = handle[Exception, () => Nothing] { // error // error
24-
(x: CanThrow[Exception]) => () => raise(new Exception)(using x)
23+
val b = handle[Exception, () => Nothing] { // error
24+
(x: CanThrow[Exception]) => () => raise(new Exception)(using x) // error
2525
} {
2626
(ex: Exception) => ???
2727
}

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

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,35 +16,31 @@
1616
| Note that capability x is not included in capture set {}.
1717
|
1818
| longer explanation available when compiling with `-explain`
19-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:15:2 -----------------------------------------
20-
15 | def f(y: Int) = if x == null then y else y // error
19+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:16:2 -----------------------------------------
20+
16 | f // error
2121
| ^
2222
| Found: (y: Int) ->{x} Int
2323
| Required: Matchable
2424
|
2525
| Note that capability x is not included in capture set {}.
26-
16 | f
2726
|
2827
| longer explanation available when compiling with `-explain`
29-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:22:2 -----------------------------------------
30-
22 | class F(y: Int) extends A: // error
31-
| ^
28+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:24:2 -----------------------------------------
29+
24 | F(22) // error
30+
| ^^^^^
3231
| Found: A^{x}
3332
| Required: A
3433
|
3534
| Note that capability x is not included in capture set {}.
36-
23 | def m() = if x == null then y else y
37-
24 | F(22)
3835
|
3936
| longer explanation available when compiling with `-explain`
40-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:27:2 -----------------------------------------
41-
27 | new A: // error
42-
| ^
43-
| Found: A^{x}
44-
| Required: A
37+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/capt1.scala:28:40 ----------------------------------------
38+
28 | def m() = if x == null then y else y // error
39+
| ^
40+
| Found: A^{x}
41+
| Required: A
4542
|
46-
| Note that capability x is not included in capture set {}.
47-
28 | def m() = if x == null then y else y
43+
| Note that capability x is not included in capture set {}.
4844
|
4945
| longer explanation available when compiling with `-explain`
5046
-- Error: tests/neg-custom-args/captures/capt1.scala:36:16 -------------------------------------------------------------

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,20 @@ def h1(x: C @retains[caps.cap.type], y: C): Any =
1212
() => f() // ok
1313

1414
def h2(x: C @retains[caps.cap.type]): Matchable =
15-
def f(y: Int) = if x == null then y else y // error
16-
f
15+
def f(y: Int) = if x == null then y else y
16+
f // error
1717

1818
class A
1919
type Cap = C @retains[caps.cap.type]
2020

2121
def h3(x: Cap): A =
22-
class F(y: Int) extends A: // error
22+
class F(y: Int) extends A:
2323
def m() = if x == null then y else y
24-
F(22)
24+
F(22) // error
2525

2626
def h4(x: Cap, y: Int): A =
27-
new A: // error
28-
def m() = if x == null then y else y
27+
new A:
28+
def m() = if x == null then y else y // error
2929

3030
def f1(c: Cap): () ->{c} c.type = () => c // ok
3131

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,12 @@
77
| Note that capability f is not included in capture set {}.
88
|
99
| longer explanation available when compiling with `-explain`
10+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/eta.scala:7:7 --------------------------------------------
11+
7 | () => { stowaway.apply().apply() } // error (was ok)
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
| Found: () ->{stowaway} Unit
14+
| Required: () -> Unit
15+
|
16+
| Note that capability stowaway is not included in capture set {}.
17+
|
18+
| longer explanation available when compiling with `-explain`

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
g // error
55
val stowaway: () -> Proc^{f} =
66
bar( () => f ) // was error now OK
7-
() => { stowaway.apply().apply() }
7+
() => { stowaway.apply().apply() } // error (was ok)

tests/neg-custom-args/captures/heal-tparam-cs.check

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/heal-tparam-cs.scala:10:23 -------------------------------
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/heal-tparam-cs.scala:10:25 -------------------------------
22
10 | val test1 = localCap { c => // error
3-
| ^
3+
| ^
44
|Found: (c: Capp^'s1) ->'s2 () ->{c} Unit
55
|Required: (c: Capp^) => () ->'s3 Unit
66
|
@@ -9,7 +9,6 @@
99
|where: => refers to a fresh root capability created in value test1 when checking argument to parameter op of method localCap
1010
| ^ refers to the universal root capability
1111
11 | () => { c.use() }
12-
12 | }
1312
|
1413
| longer explanation available when compiling with `-explain`
1514
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/heal-tparam-cs.scala:15:13 -------------------------------

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,21 @@
1616
| Note that capability b is not included in capture set {}.
1717
|
1818
| longer explanation available when compiling with `-explain`
19-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23207.scala:23:2 ----------------------------------------
20-
23 | class B extends A: // error, now we see the error for the whole block since there are no nested errors
19+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23207.scala:19:2 ----------------------------------------
20+
19 | c // error
2121
| ^
22-
| Found: A^{io}
22+
| Found: A^{c}
2323
| Required: A
2424
|
25-
| Note that capability io is not included in capture set {}.
26-
24 | val hide: AnyRef^{io} = io
27-
25 | val b = new B
28-
26 | val c = b.getBox.x
29-
27 | c
25+
| Note that capability c is not included in capture set {}.
26+
|
27+
| longer explanation available when compiling with `-explain`
28+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i23207.scala:27:2 ----------------------------------------
29+
27 | c // error
30+
| ^
31+
| Found: A^{c}
32+
| Required: A
33+
|
34+
| Note that capability c is not included in capture set {}.
3035
|
3136
| longer explanation available when compiling with `-explain`

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,12 @@ def leak(io: AnyRef^): A =
1616
val c = b.getBox.x
1717
val _: B^{b} = c // ok
1818
val _: A = c // error
19-
c // no error here since we don't propagate expected type into the last expression of a block
20-
// and the whole block's span overlaps with previous errors
19+
c // error
2120

2221
def leak2(io: AnyRef^): A =
23-
class B extends A: // error, now we see the error for the whole block since there are no nested errors
22+
class B extends A:
2423
val hide: AnyRef^{io} = io
2524

2625
val b = new B
2726
val c = b.getBox.x
28-
c
27+
c // error
Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,19 @@
1-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:18:4 ------------------------------------
2-
18 | final class Mapped extends LazyList[B]: // error
3-
| ^
1+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:24:4 ------------------------------------
2+
24 | new Mapped // error
3+
| ^^^^^^^^^^
44
| Found: LazyList[B^'s1]^{f, xs}
55
| Required: LazyList[B]^{f}
66
|
77
| Note that capability xs is not included in capture set {f}.
8-
19 | this: (Mapped^{xs, f}) =>
9-
20 | def isEmpty = false
10-
21 | def head: B = f(xs.head)
11-
22 | def tail: LazyList[B]^{this} = xs.tail.map(f)
12-
23 | new Mapped
138
|
149
| longer explanation available when compiling with `-explain`
15-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:27:4 ------------------------------------
16-
27 | final class Mapped extends LazyList[B]: // error
17-
| ^
10+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:33:4 ------------------------------------
11+
33 | new Mapped // error
12+
| ^^^^^^^^^^
1813
| Found: LazyList[B^'s2]^{f, xs}
1914
| Required: LazyList[B]^{xs}
2015
|
2116
| Note that capability f is not included in capture set {xs}.
22-
28 | this: Mapped^{xs, f} =>
23-
29 | def isEmpty = false
24-
30 | def head: B = f(xs.head)
25-
31 | def tail: LazyList[B]^{this} = xs.tail.map(f)
26-
32 | new Mapped
2717
|
2818
| longer explanation available when compiling with `-explain`
2919
-- Error: tests/neg-custom-args/captures/lazylists2.scala:40:20 --------------------------------------------------------
@@ -34,22 +24,26 @@
3424
41 | def tail: LazyList[B]^{this}= xs.tail.map(f) // error
3525
| ^
3626
| reference (f : A => B) is not included in the allowed capture set {xs} of the self type of class Mapped
37-
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:45:4 ------------------------------------
38-
45 | final class Mapped extends LazyList[B]: // error
39-
| ^
27+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:51:4 ------------------------------------
28+
51 | new Mapped // error
29+
| ^^^^^^^^^^
4030
| Found: LazyList[B^'s3]^{f, xs}
4131
| Required: LazyList[B]^{xs}
4232
|
4333
| Note that capability f is not included in capture set {xs}.
44-
46 | this: (Mapped^{xs, f}) =>
45-
47 | def isEmpty = false
46-
48 | def head: B = f(xs.head)
47-
49 | def tail: LazyList[B]^{xs, f} = xs.tail.map(f)
48-
50 | new Mapped
4934
|
5035
| longer explanation available when compiling with `-explain`
5136
-- Error: tests/neg-custom-args/captures/lazylists2.scala:60:10 --------------------------------------------------------
5237
60 | class Mapped2 extends Mapped: // error
5338
| ^
5439
| references {f, xs} are not all included in the allowed capture set {} of the self type of class Mapped2
5540
61 | this: Mapped =>
41+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/lazylists2.scala:62:4 ------------------------------------
42+
62 | new Mapped2 // error
43+
| ^^^^^^^^^^^
44+
| Found: LazyList[B^'s4]^{f, xs}
45+
| Required: LazyList[B]
46+
|
47+
| Note that capability f is not included in capture set {}.
48+
|
49+
| longer explanation available when compiling with `-explain`

0 commit comments

Comments
 (0)