summaryrefslogtreecommitdiff
path: root/src/reflect/scala/reflect/internal/Mirrors.scala
blob: 6b1063ccd9ba8e81ea772a300fa2778ab123b203 (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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/* NSC -- new Scala compiler
 * Copyright 2005-2013 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala
package reflect
package internal

import Flags._

trait Mirrors extends api.Mirrors {
  thisUniverse: SymbolTable =>

  override type Mirror >: Null <: RootsBase

  // root symbols hold a strong reference to the enclosing mirror
  // this prevents the mirror from being collected
  // if there are any symbols created by that mirror
  trait RootSymbol extends Symbol { def mirror: Mirror }

  abstract class RootsBase(rootOwner: Symbol) extends scala.reflect.api.Mirror[Mirrors.this.type] { thisMirror =>
    private[this] var initialized = false
    def isMirrorInitialized = initialized

    protected[scala] def rootLoader: LazyType

    val RootClass: ClassSymbol
    val RootPackage: ModuleSymbol
    val EmptyPackageClass: ClassSymbol
    val EmptyPackage: ModuleSymbol

    def symbolOf[T: universe.WeakTypeTag]: universe.TypeSymbol = universe.weakTypeTag[T].in(this).tpe.typeSymbolDirect.asType

    def findMemberFromRoot(fullName: Name): Symbol = {
      val segs = nme.segments(fullName.toString, fullName.isTermName)
      if (segs.isEmpty) NoSymbol
      else definitions.findNamedMember(segs.tail, RootClass.info member segs.head)
    }

    /** Todo: organize similar to mkStatic in scala.reflect.Base */
    private def getModuleOrClass(path: Name, len: Int): Symbol = {
      val point = path lastPos('.', len - 1)
      val owner =
        if (point > 0) getModuleOrClass(path.toTermName, point)
        else RootClass
      val name = path subName (point + 1, len)
      val sym = owner.info member name
      val result = if (path.isTermName) sym.suchThat(_ hasFlag MODULE) else sym
      if (result != NoSymbol) result
      else {
        if (settings.debug) { log(sym.info); log(sym.info.members) }//debug
        thisMirror.missingHook(owner, name) orElse {
          MissingRequirementError.notFound((if (path.isTermName) "object " else "class ")+path+" in "+thisMirror)
        }
      }
    }

    /** If you're looking for a class, pass a type name.
     *  If a module, a term name.
     *
     *  Unlike `getModuleOrClass`, this function
     *  loads unqualified names from the root package.
     */
    private def getModuleOrClass(path: Name): Symbol =
      getModuleOrClass(path, path.length)

    /** If you're looking for a class, pass a type name.
     *  If a module, a term name.
     *
     *  Unlike `getModuleOrClass`, this function
     *  loads unqualified names from the empty package.
     */
    private def staticModuleOrClass(path: Name): Symbol = {
      val isPackageless = path.pos('.') == path.length
      if (isPackageless) EmptyPackageClass.info decl path
      else getModuleOrClass(path)
    }

    protected def mirrorMissingHook(owner: Symbol, name: Name): Symbol = NoSymbol

    protected def universeMissingHook(owner: Symbol, name: Name): Symbol = thisUniverse.missingHook(owner, name)

    private[scala] def missingHook(owner: Symbol, name: Name): Symbol = logResult(s"missingHook($owner, $name)")(
      mirrorMissingHook(owner, name) orElse universeMissingHook(owner, name)
    )

    // todo: get rid of most the methods here and keep just staticClass/Module/Package

    /************************ loaders of class symbols ************************/

    private def ensureClassSymbol(fullname: String, sym: Symbol): ClassSymbol = {
      var result = sym
      result match {
        case x: ClassSymbol => x
        case _              => MissingRequirementError.notFound("class " + fullname)
      }
    }

    def getClassByName(fullname: Name): ClassSymbol =
      ensureClassSymbol(fullname.toString, getModuleOrClass(fullname.toTypeName))

    def getRequiredClass(fullname: String): ClassSymbol =
      getClassByName(newTypeNameCached(fullname))

    def requiredClass[T: ClassTag] : ClassSymbol =
      getRequiredClass(erasureName[T])

    def getClassIfDefined(fullname: String): Symbol =
      getClassIfDefined(newTypeNameCached(fullname))

    def getClassIfDefined(fullname: Name): Symbol =
      wrapMissing(getClassByName(fullname.toTypeName))

    /** @inheritdoc
     *
     *  Unlike getClassByName/getRequiredClass this function can also load packageless symbols.
     *  Compiler might ignore them, but they should be loadable with macros.
     */
    override def staticClass(fullname: String): ClassSymbol =
      try ensureClassSymbol(fullname, staticModuleOrClass(newTypeNameCached(fullname)))
      catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) }

    /************************ loaders of module symbols ************************/

    private def ensureModuleSymbol(fullname: String, sym: Symbol, allowPackages: Boolean): ModuleSymbol =
      sym match {
        case x: ModuleSymbol if allowPackages || !x.hasPackageFlag => x
        case _                                                     => MissingRequirementError.notFound("object " + fullname)
      }

    def getModuleByName(fullname: Name): ModuleSymbol =
      ensureModuleSymbol(fullname.toString, getModuleOrClass(fullname.toTermName), allowPackages = true)

    def getRequiredModule(fullname: String): ModuleSymbol =
      getModuleByName(newTermNameCached(fullname))

    // TODO: What syntax do we think should work here? Say you have an object
    // like scala.Predef.  You can't say requiredModule[scala.Predef] since there's
    // no accompanying Predef class, and if you say requiredModule[scala.Predef.type]
    // the name found via the erasure is scala.Predef$.  For now I am
    // removing the trailing $, but I think that classTag should have
    // a method which returns a usable name, one which doesn't expose this
    // detail of the backend.
    def requiredModule[T: ClassTag] : ModuleSymbol =
      getRequiredModule(erasureName[T] stripSuffix "$")

    def getModuleIfDefined(fullname: String): Symbol =
      getModuleIfDefined(newTermNameCached(fullname))

    def getModuleIfDefined(fullname: Name): Symbol =
      wrapMissing(getModuleByName(fullname.toTermName))

    /** @inheritdoc
     *
     *  Unlike getModule/getRequiredModule this function can also load packageless symbols.
     *  Compiler might ignore them, but they should be loadable with macros.
     */
    override def staticModule(fullname: String): ModuleSymbol =
      try ensureModuleSymbol(fullname, staticModuleOrClass(newTermNameCached(fullname)), allowPackages = false)
      catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) }

    /************************ loaders of package symbols ************************/

    private def ensurePackageSymbol(fullname: String, sym: Symbol, allowModules: Boolean): ModuleSymbol =
      sym match {
        case x: ModuleSymbol if allowModules || x.hasPackageFlag => x
        case _                                                   => MissingRequirementError.notFound("package " + fullname)
      }

    def getPackage(fullname: TermName): ModuleSymbol =
      ensurePackageSymbol(fullname.toString, getModuleOrClass(fullname), allowModules = true)

    def getPackageIfDefined(fullname: TermName): Symbol =
      wrapMissing(getPackage(fullname))

    @deprecated("use getPackage", "2.11.0") def getRequiredPackage(fullname: String): ModuleSymbol =
      getPackage(newTermNameCached(fullname))

    def getPackageObject(fullname: String): ModuleSymbol = getPackageObject(newTermName(fullname))
    def getPackageObject(fullname: TermName): ModuleSymbol =
      (getPackage(fullname).packageObject) match {
        case x: ModuleSymbol => x
        case _               => MissingRequirementError.notFound("package object " + fullname)
      }

    def getPackageObjectIfDefined(fullname: String): Symbol =
      getPackageObjectIfDefined(newTermNameCached(fullname))

    def getPackageObjectIfDefined(fullname: TermName): Symbol =
      wrapMissing(getPackageObject(fullname))

    override def staticPackage(fullname: String): ModuleSymbol =
      try ensurePackageSymbol(fullname.toString, getModuleOrClass(newTermNameCached(fullname)), allowModules = false)
      catch { case mre: MissingRequirementError => throw new ScalaReflectionException(mre.msg) }

    /************************ helpers ************************/

    def erasureName[T: ClassTag] : String = {
      /* We'd like the String representation to be a valid
       * scala type, so we have to decode the jvm's secret language.
       */
      def erasureString(clazz: Class[_]): String = {
        if (clazz.isArray) "Array[" + erasureString(clazz.getComponentType) + "]"
        else clazz.getName
      }
      erasureString(classTag[T].runtimeClass)
    }

   @inline final def wrapMissing(body: => Symbol): Symbol =
      try body
      catch { case _: MissingRequirementError => NoSymbol }

    def init() {
      if (initialized) return
      // Still fiddling with whether it's cleaner to do some of this setup here
      // or from constructors.  The latter approach tends to invite init order issues.

      EmptyPackageClass setInfo rootLoader
      EmptyPackage setInfo EmptyPackageClass.tpe

      connectModuleToClass(EmptyPackage, EmptyPackageClass)
      connectModuleToClass(RootPackage, RootClass)

      RootClass.info.decls enter EmptyPackage
      RootClass.info.decls enter RootPackage

      if (rootOwner != NoSymbol) {
        // synthetic core classes are only present in root mirrors
        // because Definitions.scala, which initializes and enters them, only affects rootMirror
        // therefore we need to enter them manually for non-root mirrors
        definitions.syntheticCoreClasses foreach (theirSym => {
          val theirOwner = theirSym.owner
          assert(theirOwner.isPackageClass, s"theirSym = $theirSym, theirOwner = $theirOwner")
          val ourOwner = staticPackage(theirOwner.fullName).moduleClass
          val ourSym = theirSym // just copy the symbol into our branch of the symbol table
          ourOwner.info.decls enterIfNew ourSym
        })
      }

      initialized = true
    }
  }

  abstract class Roots(rootOwner: Symbol) extends RootsBase(rootOwner) { thisMirror =>

    // TODO - having these as objects means they elude the attempt to
    // add synchronization in SynchronizedSymbols.  But we should either
    // flip on object overrides or find some other accommodation, because
    // lazy vals are unnecessarily expensive relative to objects and it
    // is very beneficial for a handful of bootstrap symbols to have
    // first class identities
    sealed trait WellKnownSymbol extends Symbol {
      this initFlags (PackageFlags | STATIC)
    }
    // Features common to RootClass and RootPackage, the roots of all
    // type and term symbols respectively.
    sealed trait RootSymbol extends WellKnownSymbol with thisUniverse.RootSymbol {
      final override def isRootSymbol = true
      override def owner              = rootOwner
      override def typeOfThis         = thisSym.tpe
      def mirror                      = thisMirror.asInstanceOf[Mirror]
    }

    class RootPackage extends ModuleSymbol(rootOwner, NoPosition, nme.ROOTPKG) with RootSymbol {
      this setInfo NullaryMethodType(RootClass.tpe)

      override def isRootPackage = true
    }

    // This is the package _root_.  The actual root cannot be referenced at
    // the source level, but _root_ is essentially a function => <root>.
    lazy val RootPackage = new RootPackage

    class RootClass extends PackageClassSymbol(rootOwner, NoPosition, tpnme.ROOT) with RootSymbol {
      this setInfo rootLoader

      override def isRoot            = true
      override def isEffectiveRoot   = true
      override def isNestedClass     = false
      override def sourceModule      = RootPackage
    }

    // This is <root>, the actual root of everything except the package _root_.
    // <root> and _root_ (RootPackage and RootClass) should be the only "well known"
    // symbols owned by NoSymbol.  All owner chains should go through RootClass,
    // although it is probable that some symbols are created as direct children
    // of NoSymbol to ensure they will not be stumbled upon.  (We should designate
    // a better encapsulated place for that.)
    lazy val RootClass = new RootClass

    class EmptyPackage extends ModuleSymbol(RootClass, NoPosition, nme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
      override def isEmptyPackage = true
    }

    // The empty package, which holds all top level types without given packages.
    lazy val EmptyPackage = new EmptyPackage

    class EmptyPackageClass extends PackageClassSymbol(RootClass, NoPosition, tpnme.EMPTY_PACKAGE_NAME) with WellKnownSymbol {
      override def isEffectiveRoot     = true
      override def isEmptyPackageClass = true
      override def sourceModule        = EmptyPackage
    }

    lazy val EmptyPackageClass = new EmptyPackageClass
  }
}