Skip to content

Commit d5801b9

Browse files
committed
Merge pull request scala#3328 from retronym/ticket/8111
Repair symbol owners after abandoned named-/default-args
2 parents a812241 + c91d373 commit d5801b9

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3269,6 +3269,28 @@ trait Typers extends Modes with Adaptations with Tags {
32693269
// calls to the default getters. Example:
32703270
// foo[Int](a)() ==> foo[Int](a)(b = foo$qual.foo$default$2[Int](a))
32713271
checkNotMacro()
3272+
3273+
// SI-8111 transformNamedApplication eagerly shuffles around the application to preserve
3274+
// evaluation order. During this process, it calls `changeOwner` on symbols that
3275+
// are transplanted underneath synthetic temporary vals.
3276+
//
3277+
// Here, we keep track of the symbols owned by `context.owner` to enable us to
3278+
// rollback, so that we don't end up with "orphaned" symbols.
3279+
//
3280+
// TODO: Find a better way!
3281+
//
3282+
// Note that duplicating trees would not be enough to fix this problem, we would also need to
3283+
// clone local symbols in the duplicated tree to truly isolate things (in the spirit of BodyDuplicator),
3284+
// or, better yet, disentangle the logic in `transformNamedApplication` so that we could
3285+
// determine whether names/defaults is viable *before* transforming trees.
3286+
def ownerOf(sym: Symbol) = if (sym == null || sym == NoSymbol) NoSymbol else sym.owner
3287+
val symsOwnedByContextOwner = tree.collect {
3288+
case t @ (_: DefTree | _: Function) if ownerOf(t.symbol) == context.owner => t.symbol
3289+
}
3290+
def rollbackNamesDefaultsOwnerChanges() {
3291+
symsOwnedByContextOwner foreach (_.owner = context.owner)
3292+
}
3293+
32723294
val fun1 = transformNamedApplication(Typer.this, mode, pt)(fun, x => x)
32733295
if (fun1.isErroneous) duplErrTree
32743296
else {
@@ -3297,6 +3319,7 @@ trait Typers extends Modes with Adaptations with Tags {
32973319
if (!(context.diagnostic contains note)) context.diagnostic = note :: context.diagnostic
32983320
doTypedApply(tree, if (blockIsEmpty) fun else fun1, allArgs, mode, pt)
32993321
} else {
3322+
rollbackNamesDefaultsOwnerChanges()
33003323
tryTupleApply getOrElse duplErrorTree(NotEnoughArgsError(tree, fun, missing))
33013324
}
33023325
}

test/files/pos/t8111.scala

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
trait T {
2+
3+
def crashy(ma: Any) {
4+
// okay
5+
val f1 = (u: Unit) => ma
6+
foo(f1)()
7+
foo((u: Unit) => ma)
8+
foo(0, (u: Any) => ma) apply ()
9+
10+
// crash due to side effects on the onwer of the symbol in the
11+
// qualifier or arguments of the application during an abandoned
12+
// names/defaults transform. The code type checkes because of
13+
// autp-tupling which promotes and empty parmater list to `(): Unit`
14+
foo((u: Any) => ma)()
15+
16+
{{(u: Any) => ma}; this}.foo(0)()
17+
18+
foo({def foo = ma; 0})()
19+
20+
{def foo = ma; this}.foo(0)()
21+
}
22+
23+
def foo(f: Any): Any => Any
24+
}

0 commit comments

Comments
 (0)