Skip to content

Commit 22ed2fb

Browse files
authored
Tighten closure extractor in TreeInfo (#21621)
The previous extractor for closures matches also arbitrary blocks that ended in a (possible deeply nested) closure. This caused wrong use sets in #21620. The new definition is stricter. There is also a new blockEndingInclosure extractor that keeps the old behavior. Fixes #21620
2 parents 4293a45 + 614314a commit 22ed2fb

File tree

5 files changed

+54
-6
lines changed

5 files changed

+54
-6
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

+19-5
Original file line numberDiff line numberDiff line change
@@ -814,17 +814,31 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
814814
case _ => false
815815
}
816816

817-
/** An extractor for closures, either contained in a block or standalone.
817+
/** An extractor for closures, possibly typed, and possibly including the
818+
* definition of the anonymous def.
818819
*/
819820
object closure {
820-
def unapply(tree: Tree): Option[(List[Tree], Tree, Tree)] = tree match {
821-
case Block(_, expr) => unapply(expr)
822-
case Closure(env, meth, tpt) => Some(env, meth, tpt)
823-
case Typed(expr, _) => unapply(expr)
821+
def unapply(tree: Tree)(using Context): Option[(List[Tree], Tree, Tree)] = tree match {
822+
case Block((meth : DefDef) :: Nil, closure: Closure) if meth.symbol == closure.meth.symbol =>
823+
unapply(closure)
824+
case Block(Nil, expr) =>
825+
unapply(expr)
826+
case Closure(env, meth, tpt) =>
827+
Some(env, meth, tpt)
828+
case Typed(expr, _) =>
829+
unapply(expr)
824830
case _ => None
825831
}
826832
}
827833

834+
/** An extractor for a closure or a block ending in one. This was
835+
* previously `closure` before that one was tightened.
836+
*/
837+
object blockEndingInClosure:
838+
def unapply(tree: Tree)(using Context): Option[(List[Tree], Tree, Tree)] = tree match
839+
case Block(_, expr) => unapply(expr)
840+
case _ => closure.unapply(tree)
841+
828842
/** An extractor for def of a closure contained the block of the closure. */
829843
object closureDef {
830844
def unapply(tree: Tree)(using Context): Option[DefDef] = tree match {

compiler/src/dotty/tools/dotc/typer/Migrations.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ trait Migrations:
5757
val nestedCtx = ctx.fresh.setNewTyperState()
5858
val res = typed(qual, pt1)(using nestedCtx)
5959
res match {
60-
case closure(_, _, _) =>
60+
case blockEndingInClosure(_, _, _) =>
6161
case _ =>
6262
val recovered = typed(qual)(using ctx.fresh.setExploreTyperState())
6363
val msg = OnlyFunctionsCanBeFollowedByUnderscore(recovered.tpe.widen, tree)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- [E129] Potential Issue Warning: tests/neg-custom-args/captures/i21620.scala:5:6 -------------------------------------
2+
5 | x
3+
| ^
4+
| A pure expression does nothing in statement position
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E007] Type Mismatch Error: tests/neg-custom-args/captures/i21620.scala:9:31 ----------------------------------------
8+
9 | val _: () -> () ->{x} Unit = f // error
9+
| ^
10+
| Found: () ->{f} () ->{x} Unit
11+
| Required: () -> () ->{x} Unit
12+
|
13+
| longer explanation available when compiling with `-explain`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class C
2+
def test(x: C^) =
3+
val f = () =>
4+
def foo() =
5+
x
6+
()
7+
println(s"hey: $x")
8+
() => foo()
9+
val _: () -> () ->{x} Unit = f // error
10+
()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class C
2+
def test(x: C^) =
3+
def foo() =
4+
x
5+
()
6+
val f = () =>
7+
// println() // uncomenting would give an error, but with
8+
// a different way of handling curried functions should be OK
9+
() => foo()
10+
val _: () -> () ->{x} Unit = f
11+
()

0 commit comments

Comments
 (0)