aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/RestoreScopes.scala
blob: 8b9d2be0d02121cf3dbc25913d62471cd67c4a6a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package dotty.tools.dotc
package transform

import core._
import DenotTransformers.IdentityDenotTransformer
import Contexts.Context
import Symbols._
import Scopes._
import collection.mutable
import TreeTransforms.MiniPhaseTransform
import SymDenotations._
import ast.Trees._
import NameOps._
import TreeTransforms.TransformerInfo
import StdNames._

/** The preceding lambda lift and flatten phases move symbols to different scopes
 *  and rename them. This miniphase cleans up afterwards and makes sure that all
 *  class scopes contain the symbols defined in them.
 */
class RestoreScopes extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform =>
  import ast.tpd._
  override def phaseName = "restoreScopes"

  /* Note: We need to wait until we see a package definition because
   * DropEmptyConstructors changes template members when analyzing the
   * enclosing package definitions. So by the time RestoreScopes gets to
   * see a typedef or template, it still might be changed by DropEmptyConstructors.
   */
  override def transformPackageDef(pdef: PackageDef)(implicit ctx: Context, info: TransformerInfo) = {
    pdef.stats.foreach(restoreScope)
    pdef
  }

  private def restoreScope(tree: Tree)(implicit ctx: Context, info: TransformerInfo) = tree match {
    case TypeDef(_, impl: Template) =>
      val restoredDecls = newScope
      for (stat <- impl.constr :: impl.body)
        if (stat.isInstanceOf[MemberDef] && stat.symbol.exists)
          restoredDecls.enter(stat.symbol)
      // Enter class in enclosing package scope, in case it was an inner class before flatten.
      // For top-level classes this does nothing.
      val cls = tree.symbol.asClass
      val pkg = cls.owner.asClass

      // Bring back companion links
      val companionClass = cls.info.decls.lookup(nme.COMPANION_CLASS_METHOD)
      val companionModule = cls.info.decls.lookup(nme.COMPANION_MODULE_METHOD)

      if (companionClass.exists) {
        restoredDecls.enter(companionClass)
      }

      if (companionModule.exists) {
        restoredDecls.enter(companionModule)
      }

      pkg.enter(cls)
      val cinfo = cls.classInfo
      tree.symbol.copySymDenotation(
        info = cinfo.derivedClassInfo( // Dotty deviation: Cannot expand cinfo inline without a type error
          decls = restoredDecls: Scope)).installAfter(thisTransform)
      tree
    case tree => tree
  }
}