aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/core/Symbols.scala
blob: 58f7ed4f8b27a4a367748eadc3ed0504d28675ad (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
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
package dotty.tools.dotc
package core

import Periods._
import Transformers._
import Names._, Scopes._
import Flags._
import java.lang.AssertionError
import Decorators._
import Symbols._
import Contexts._
import SymDenotations._
import Types._, Annotations._
import Denotations.{ Denotation, SingleDenotation, MultiDenotation }
import collection.mutable
import reflect.io.AbstractFile

trait Symbols { this: Context =>

  def newLazyClassSymbol(owner: Symbol, name: TypeName, initFlags: FlagSet, completer: ClassCompleter, assocfile: AbstractFile = null) =
    new ClassSymbol(new LazyClassDenotation(_, owner, name, initFlags, completer, assocfile))

  def newCompleteClassSymbol(
      owner: Symbol,
      name: TypeName,
      flags: FlagSet,
      parents: List[TypeRef],
      optSelfType: Type = NoType,
      decls: Scope = newScope,
      assocFile: AbstractFile = null) =
    new ClassSymbol(new CompleteClassDenotation(
      _, owner, name, flags, parents, optSelfType, decls, assocFile))

  def newCompleteTypeSymbol(
      owner: Symbol,
      name: TypeName,
      flags: FlagSet,
      info: Type) =
    new TypeSymbol(new CompleteSymDenotation(_, owner, name, flags, info))

  def newAliasTypeSymbol(owner: Symbol, name: TypeName, alias: Type, flags: FlagSet = EmptyFlags) =
    newCompleteTypeSymbol(owner, name, flags, TypeBounds(alias, alias))

  def newCompleteTermSymbol(
      owner: Symbol,
      name: TermName,
      flags: FlagSet,
      info: Type) =
    new TermSymbol(new CompleteSymDenotation(_, owner, name, flags, info))
}

object Symbols {

  /** A Symbol represents a Scala definition/declaration or a package.
   */
  abstract class Symbol(denotf: Symbol => SymDenotation) extends DotClass {

    type ThisName <: Name

    /** Is symbol different from NoSymbol? */
    def exists = true

    /** This symbol, if it exists, otherwise the result of evaluating `that` */
    def orElse(that: => Symbol) = if (exists) this else that

    def filter(p: Symbol => Boolean): Symbol = if (p(this)) this else NoSymbol

    /** The last denotation of this symbol */
    private[this] var lastDenot: SymDenotation = denotf(this)

    /** The current denotation of this symbol */
    final def denot(implicit ctx: Context): SymDenotation = {
      var denot = lastDenot
      if (!(denot.validFor contains ctx.period)) denot = denot.current.asInstanceOf[SymDenotation]
      denot
    }

    /** Subclass tests and casts */
    def isType: Boolean = false
    def isTerm: Boolean = false
    def isClass: Boolean = false

    def asTerm: TermSymbol = asInstanceOf[TermSymbol]
    def asType: TypeSymbol = asInstanceOf[TypeSymbol]
    def asClass: ClassSymbol = asInstanceOf[ClassSymbol]

    /** A unique, densely packed integer tag for each class symbol, -1
     *  for all other symbols. To save memory, this method
     *  should be called only if class is a super class of some other class.
     */
    def superId: Int = -1

    final def entered(implicit ctx: Context): this.type = {
      owner.info.decls.enter(this)
      this
    }

    /** Is symbol a primitive value class? */
    def isPrimitiveValueClass(implicit ctx: Context) = defn.ScalaValueClasses contains this

    /** Is symbol a phantom class for which no runtime representation exists? */
    def isPhantomClass(implicit ctx: Context) = defn.PhantomClasses contains this

    // --------- Forwarders for sym methods --------------------------

    /** Special case tests for flags that are known a-priori and do not need loading
     *  flags.
     */
    def isModule(implicit ctx: Context) = denot.isModule
    def isModuleObj(implicit ctx: Context) = denot.isModuleVal
    def isModuleClass(implicit ctx: Context) = denot.isModuleClass
    def isPackage(implicit ctx: Context) = denot.isPackage
    def isPackageObj(implicit ctx: Context) = denot.isPackageVal
    def isPackageClass(implicit ctx: Context) = denot.isPackageClass

    /** The current owner of this symbol */
    final def owner(implicit ctx: Context): Symbol = denot.owner

    /** The current name of this symbol */
    final def name(implicit ctx: Context): ThisName = denot.name.asInstanceOf[ThisName]

    /** The current type info of this symbol */
    final def info(implicit ctx: Context): Type = denot.info

    /** The current flag set of this symbol */
    final def flags(implicit ctx: Context): FlagSet = denot.flags

    /** The current privateWithin boundary of this symbol, NoSymbol if no boundary is given. */
    final def privateWithin(implicit ctx: Context): Symbol = denot.privateWithin

    /** The current annotations of this symbol */
    final def annotations(implicit ctx: Context): List[Annotation] = denot.annotations

    /** Does this symbol have an annotation matching the given class symbol? */
    final def hasAnnotation(cls: Symbol)(implicit ctx: Context): Boolean = denot.hasAnnotation(cls)

    /** The chain of owners of this symbol, starting with the symbol itself */
    final def ownersIterator(implicit ctx: Context): Iterator[Symbol] = denot.ownersIterator

    /** Same as `ownersIterator contains sym` but more efficient. */
    final def hasTransOwner(sym: Symbol)(implicit ctx: Context): Boolean = denot.hasTransOwner(sym)

    /** The owner, skipping package objects. */
    def effectiveOwner(implicit ctx: Context) = denot.effectiveOwner

    /** If this is a package object or its implementing class, its owner: otherwise this.
     */
    def skipPackageObject(implicit ctx: Context): Symbol = if (this is PackageObject) owner else this

    /** The class containing this symbol */
    def enclosingClass(implicit ctx: Context): Symbol = denot.enclosingClass

    /** The top-level class containing this symbol, except for a toplevel module
     *  its module class
     */
    def topLevelClass(implicit ctx: Context): Symbol = denot.topLevelClass

    /** The package containing this symbol */
    def enclosingPackage(implicit ctx: Context): Symbol = denot.enclosingPackage

    /** The encoded full path name of this symbol, where outer names and inner names
     *  are separated by `separator` characters.
     *  Never translates expansions of operators back to operator symbol.
     *  Drops package objects.
     */
    final def fullName(separator: Char)(implicit ctx: Context): Name = denot.fullName(separator)

    /** The source or class file from which this symbol was generated, null if not applicable. */
    final def associatedFile(implicit ctx: Context): AbstractFile = denot.associatedFile

    /** The class file from which this symbol was generated, null if not applicable. */
    final def binaryFile(implicit ctx: Context): AbstractFile = denot.binaryFile

    /** The source or class file from which this symbol was generated, null if not applicable. */
    final def sourceFile(implicit ctx: Context): AbstractFile = denot.sourceFile

    /** Is this symbol defined in the same compilation unit as that symbol? */
    final def isCoDefinedWith(that: Symbol)(implicit ctx: Context): Boolean = denot.isCoDefinedWith(that)

    /** The class with the same (type-) name as this module or module class,
     *  which is the defined in the same compilation unit.
     *  NoSymbol if this class does not exist.
     */
    final def companionClass(implicit ctx: Context): Symbol = denot.companionClass

    /** The module object with the same (term-) name as this class or module class,
     *  which is the defined in the same compilation unit.
     *  NoSymbol if this class does not exist.
     */
    final def companionModule(implicit ctx: Context): Symbol = denot.companionModule

    /** If this is a class, the module class of its companion object.
     *  If this is a module class, its companion class.
     *  NoSymbol otherwise.
     */
    final def linkedClass(implicit ctx: Context): Symbol = denot.linkedClass

    /** Is this symbol a subclass of the given class? */
    final def isSubClass(cls: Symbol)(implicit ctx: Context): Boolean = denot.isSubClass(cls)

    /** Is this class symbol a subclass of `cls`,
     *  and is this class symbol also different from Null or Nothing?
     */
    final def isNonBottomSubClass(cls: Symbol)(implicit ctx: Context): Boolean = denot.isNonBottomSubClass(cls)

    /** Is this symbol a subclass of `base` or a companion object of such a subclass? */
    final def isSubClassOrCompanion(base: Symbol)(implicit ctx: Context): Boolean = denot.isSubClassOrCompanion(base)

    /** The class that encloses the owner of the current context
     *  and that is a subclass of this class.
     */
    final def enclosingSubClass(implicit ctx: Context) = denot.enclosingSubClass

    ///** Is this symbol a proper subclass of the given class? */
    //def isProperSubClass(cls: ClassSymbol)(implicit ctx: Context): Boolean = (this ne cls) && this.isSubClass(cls)

    /** The non-private symbol whose type matches the type of this symbol
     *  in in given class.
     *
     *  @param inClass   The class containing the symbol's definition
     *  @param site      The base type from which member types are computed
     */
    final def matchingSymbol(inClass: Symbol, site: Type)(implicit ctx: Context): Symbol = denot.matchingSymbol(inClass, site)

    /** The symbol, in class `inClass`, that is overridden by this symbol. */
    final def overriddenSymbol(inClass: ClassSymbol)(implicit ctx: Context): Symbol = denot.overriddenSymbol(inClass)

    /** All symbols overriden by this symbol. */
    final def allOverriddenSymbols(implicit ctx: Context): Iterator[Symbol] = denot.allOverriddenSymbols

    /** The class or term symbol up to which this symbol is accessible,
     *  or RootClass if it is public.  As java protected statics are
     *  otherwise completely inaccessible in scala, they are treated
     *  as public.
     *  @param base
     */
    final def accessBoundary(base: Symbol)(implicit ctx: Context): Symbol = denot.accessBoundary(base)

    /** Is this symbol contained in `boundary`? */
    final def isContainedIn(boundary: Symbol)(implicit ctx: Context): Boolean = denot.isContainedIn(boundary)

    /** Is this symbol accessible whenever `that` symbol is accessible?
     *  Does not take into account status of protected members.
     */
    final def isAsAccessibleAs(that: Symbol)(implicit ctx: Context): Boolean = denot.isAsAccessibleAs(that)

    /** Is this symbol a non-value class? */
    final def isNonValueClass(implicit ctx: Context): Boolean = denot.isNonValueClass

    /** Is this symbol accessible as a member of tree with type `pre`?
     *  @param pre          The type of the tree from which the selection is made
     *  @param superAccess  Access is via super
     */
    final def isAccessibleFrom(pre: Type, superAccess: Boolean = false)(implicit ctx: Context): Boolean = denot.isAccessibleFrom(pre, superAccess)

    def show(implicit ctx: Context): String = ctx.show(this)
    def showLocated(implicit ctx: Context): String = ctx.showLocated(this)
    def showDef(implicit ctx: Context): String = ctx.showDef(this)

    /** The type parameters of a class symbol, Nil for all other symbols */
    def typeParams(implicit ctx: Context): List[TypeSymbol] = denot.typeParams

    /** The type This(cls), where cls is this class symbol */
    def thisType(implicit ctx: Context): Type = denot.thisType

    /** Is this symbol the root class or its companion object? */
    def isRoot(implicit ctx: Context): Boolean = denot.isRoot

    /** Is this symbol the empty package class or its companion object? */
    def isEmptyPackage(implicit ctx: Context): Boolean = denot.isEmptyPackage

    /** Is this symbol an anonymous class? */
    def isAnonymousClass(implicit ctx: Context): Boolean = denot.isAnonymousClass

    /** Is this symbol the root class, empty package class, or one of their companion objects? */
    def isEffectiveRoot(implicit ctx: Context): Boolean = denot.isEffectiveRoot

    /** If this is a module symbol, the class defining its template, otherwise NoSymbol. */
    def moduleClass(implicit ctx: Context): Symbol = denot.moduleClass

    /** A copy of this symbol with the same denotation */
    def copy(implicit ctx: Context): Symbol = unsupported("copy")

    /** A copy of this symbol with the same denotation but a new owner */
    def copy(owner: Symbol)(implicit ctx: Context): Symbol = unsupported("copy")

    /** Can a term with this symbol be a stable value? */
    def isStable(implicit ctx: Context): Boolean = denot.isStable

    /** Is this symbol static (i.e. with no outer instance)? */
    def isStatic(implicit ctx: Context): Boolean = denot.isStatic

    /** Does this symbol denote a class that defines static symbols? */
    final def isStaticOwner(implicit ctx: Context): Boolean = denot.isStaticOwner

    //    def isOverridable: Boolean = !!! need to enforce that classes cannot be redefined

    //    def isSkolem: Boolean = ???

    //    def isAbstractType: Boolean = ???
    //    def newAbstractType(name: TypeName, info: TypeBounds): TypeSymbol = ???
    //    def newAbstractTerm(name: TermName, tpe: Type): TypeSymbol = ???

    //def isMethod(implicit ctx: Context): Boolean = denot.isMethod

  }

  class TermSymbol(denotf: Symbol => SymDenotation) extends Symbol(denotf) {
    type ThisName = TermName
    override def isTerm = true
    override def copy(implicit ctx: Context): TermSymbol = copy(owner)
    override def copy(owner: Symbol)(implicit ctx: Context): TermSymbol = new TermSymbol(denot.copy(_, owner))
  }

  class TypeSymbol(denotf: Symbol => SymDenotation) extends Symbol(denotf) {
    type ThisName = TypeName
    override def isType = true
    override def copy(implicit ctx: Context): TypeSymbol = copy(owner)
    override def copy(owner: Symbol)(implicit ctx: Context): TypeSymbol = new TypeSymbol(denot.copy(_, owner))

    /** The type representing the type constructor for this type symbol */
    def typeConstructor(implicit ctx: Context): TypeRef = denot.typeConstructor

    /** The variance of this type parameter as an Int, with
     *  +1 = Covariant, -1 = Contravariant, 0 = Nonvariant
     */
    def variance(implicit ctx: Context): Int = denot.variance
  }

  class ClassSymbol(denotf: ClassSymbol => ClassDenotation) extends TypeSymbol(s => denotf(s.asClass)) {
    override def isClass = true
    override def copy(implicit ctx: Context): ClassSymbol = copy(owner)
    override def copy(owner: Symbol)(implicit ctx: Context): ClassSymbol = new ClassSymbol(classDenot.copyClass(_, owner))
    private var superIdHint: Int = -1

    final def classDenot(implicit ctx: Context): ClassDenotation =
      denot.asInstanceOf[ClassDenotation]

    def selfType(implicit ctx: Context): Type = classDenot.selfType

    /** The base classes of this class in linearization order,
     *  with the class itself as first element.x
     */
    def baseClasses(implicit ctx: Context): List[ClassSymbol] = classDenot.baseClasses

    //    override def typeTemplate(implicit ctx: Context): Type = classDenot.typeTemplate

    def superId(implicit ctx: Context): Int = {
      val hint = superIdHint
      if (hint >= 0 && hint <= ctx.lastSuperId && (ctx.classOfId(hint) eq this)) hint
      else {
        val id = ctx.superIdOfClass get this match {
          case Some(id) =>
            id
          case None =>
            val id = ctx.nextSuperId
            ctx.superIdOfClass(this) = id
            ctx.classOfId(id) = this
            id
        }
        superIdHint = id
        id
      }
    }
  }

  class ErrorSymbol(underlying: Symbol, msg: => String)(implicit ctx: Context) extends Symbol(sym => underlying.denot) {
    override def isType = underlying.isType
    override def isTerm = underlying.isTerm
  }

  object NoSymbol extends Symbol(sym => NoDenotation) {
    override def exists = false
  }

  implicit def defn(implicit ctx: Context): Definitions = ctx.definitions

  implicit def toFlagSet(sym: Symbol)(implicit ctx: Context): FlagSet = sym.flags

}