Skip to content

Commit 5b9966d

Browse files
committed
SI-8120 Avoid tree sharing when typechecking patmat anon functions
When typechecking an empty selector `Match` corresponding to: { case ... => ... }: (A => B) We wrap it in a `Function` and typecheck: (x$1 => x$1 match { case ... => ... }) Local symbols in this expression (representing values bound by the pattern, or just definitions in the body or guard) are then owned by the anonymous function's symbol. However, if we ever discard this `Function` and start anew with the empty selector match, as happens during the fallback to use a view on the receiver in `tryTypedApply`, we found that we had mutated the cases of the original tree, and allowed orphaned local symbols to escape into the compiler pipeline. This commit uses duplicated trees for the the cases in the synthetic `Match` to avoid this problem. `duplicateAndKeepPositions` is used to preserve range positions; without this scala-refactoring PrettyPrinterTest fails. `Tree#duplicate` uses offset positions in the copied tree, which is appropriate when both the original and the copy are going to end up in the final tree.
1 parent 66a12fc commit 5b9966d

File tree

2 files changed

+14
-1
lines changed

2 files changed

+14
-1
lines changed

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4250,7 +4250,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
42504250
}
42514251
val ids = for (p <- params) yield Ident(p.name)
42524252
val selector1 = atPos(tree.pos.focusStart) { if (arity == 1) ids.head else gen.mkTuple(ids) }
4253-
val body = treeCopy.Match(tree, selector1, cases)
4253+
// SI-8120 If we don't duplicate the cases, the original Match node will share trees with ones that
4254+
// receive symbols owned by this function. However if, after a silent mode session, we discard
4255+
// this Function and try a different approach (e.g. applying a view to the reciever) we end up
4256+
// with orphaned symbols which blows up far down the pipeline (or can be detected with -Ycheck:typer).
4257+
val body = treeCopy.Match(tree, selector1, (cases map duplicateAndKeepPositions).asInstanceOf[List[CaseDef]])
42544258
typed1(atPos(tree.pos) { Function(params, body) }, mode, pt)
42554259
}
42564260
} else

test/files/pos/t8120.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object A {
2+
class C {
3+
def m(a: Nothing): Int = 0
4+
}
5+
implicit class RichAny(a: Any) {
6+
def m(a: Any): Int = 0
7+
}
8+
(new C).m({ case (x, y) => x } : Any => Any)
9+
}

0 commit comments

Comments
 (0)