Skip to content

Commit 936e83f

Browse files
committed
New phase: RestoreScopes
Cleans up after LambdaLift and Flatten. RestoreScopes exhibited a problem (double definition) when compiling Unpickler. The root of the problem was in Applications.scala. The effect was that arguments woulkd be lifted out, but then the argument expression would be used anyway. That caused a closure to be present twice which caused the double def error much later. -Ycheck did not catch it because the two closure expressions were in non-overlapping scopes.
1 parent 252b6d9 commit 936e83f

File tree

4 files changed

+40
-3
lines changed

4 files changed

+40
-3
lines changed

src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ class Compiler {
5656
List(new CapturedVars,
5757
new Constructors),
5858
List(new LambdaLift,
59-
new Flatten)
59+
new Flatten,
60+
new RestoreScopes)
6061
)
6162

6263
var runId = 1
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package dotty.tools.dotc
2+
package transform
3+
4+
import core._
5+
import DenotTransformers.IdentityDenotTransformer
6+
import Contexts.Context
7+
import Symbols._
8+
import Scopes._
9+
import collection.mutable
10+
import TreeTransforms.MiniPhaseTransform
11+
import ast.Trees._
12+
import TreeTransforms.TransformerInfo
13+
14+
/** The preceding lambda lift and flatten phases move symbols to different scopes
15+
* and rename them. This miniphase cleans up afterwards and makes sure that all
16+
* class scopes contain the symbols defined in them.
17+
*/
18+
class RestoreScopes extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
19+
import ast.tpd._
20+
override def phaseName = "restoreScopes"
21+
22+
override def treeTransformPhase = thisTransform.next
23+
24+
override def transformTypeDef(tree: TypeDef)(implicit ctx: Context, info: TransformerInfo) = {
25+
val TypeDef(_, _, Template(constr, _, _, body)) = tree
26+
val restoredDecls = newScope
27+
for (stat <- constr :: body)
28+
if (stat.isInstanceOf[MemberDef] && stat.symbol.exists)
29+
restoredDecls.enter(stat.symbol)
30+
val cinfo = tree.symbol.asClass.classInfo
31+
tree.symbol.copySymDenotation(
32+
info = cinfo.derivedClassInfo( // Dotty deviation: Cannot expand cinfo inline without a type error
33+
decls = restoredDecls: Scope)).installAfter(thisTransform)
34+
tree
35+
}
36+
}

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ trait Applications extends Compatibility { self: Typer =>
461461

462462
val result = {
463463
var typedArgs = typedArgBuf.toList
464-
val app0 = cpy.Apply(app)(normalizedFun, typedArgs)
464+
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
465465
val app1 =
466466
if (!success) app0.withType(ErrorType)
467467
else {

test/dotc/tests.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class tests extends CompilerTest {
1515

1616
implicit val defaultOptions = noCheckOptions ++ List(
1717
"-Yno-deep-subtypes",
18-
"-Ycheck:patternMatcher,gettersSetters,flatten"
18+
"-Ycheck:patternMatcher,gettersSetters,restoreScopes"
1919
)
2020

2121
val twice = List("#runs", "2", "-YnoDoubleBindings")

0 commit comments

Comments
 (0)