-
Notifications
You must be signed in to change notification settings - Fork 1k
/
NamerOps.scala
181 lines (158 loc) · 7.99 KB
/
NamerOps.scala
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
package dotty.tools
package dotc
package core
import Contexts._, Symbols._, Types._, Flags._, Scopes._, Decorators._, Names._, NameOps._
import Denotations._
import SymDenotations.{LazyType, SymDenotation}, StdNames.nme
import config.Config
import ast.untpd
/** Operations that are shared between Namer and TreeUnpickler */
object NamerOps:
/** The given type, unless `sym` is a constructor, in which case the
* type of the constructed instance is returned
*/
def effectiveResultType(sym: Symbol, paramss: List[List[Symbol]], givenTp: Type)(using Context): Type =
if sym.name == nme.CONSTRUCTOR then
paramss match
case TypeSymbols(tparams) :: _ => sym.owner.typeRef.appliedTo(tparams.map(_.typeRef))
case _ => sym.owner.typeRef
else givenTp
/** if isConstructor, make sure it has one leading non-implicit parameter list */
def normalizeIfConstructor(paramss: List[List[Symbol]], isConstructor: Boolean)(using Context): List[List[Symbol]] =
if !isConstructor then paramss
else paramss match
case Nil :: _ => paramss
case TermSymbols(vparam :: _) :: _ if !vparam.isOneOf(GivenOrImplicit) => paramss
case TypeSymbols(tparams) :: paramss1 => tparams :: normalizeIfConstructor(paramss1, isConstructor)
case _ => Nil :: paramss
/** The method type corresponding to given parameters and result type */
def methodType(paramss: List[List[Symbol]], resultType: Type, isJava: Boolean = false)(using Context): Type =
def recur(paramss: List[List[Symbol]]): Type = (paramss: @unchecked) match
case Nil =>
resultType
case TermSymbols(params) :: paramss1 =>
val (isContextual, isImplicit, isErased) =
if params.isEmpty then (false, false, false)
else (params.head.is(Given), params.head.is(Implicit), params.head.is(Erased))
val make = MethodType.companion(isContextual = isContextual, isImplicit = isImplicit, isErased = isErased)
if isJava then
for param <- params do
if param.info.isDirectRef(defn.ObjectClass) then param.info = defn.AnyType
make.fromSymbols(params, recur(paramss1))
case TypeSymbols(tparams) :: paramss1 =>
PolyType.fromParams(tparams, recur(paramss1))
if paramss.isEmpty then ExprType(resultType) else recur(paramss)
end methodType
/** Add moduleClass or sourceModule functionality to completer
* for a module or module class
*/
def adjustModuleCompleter(completer: LazyType, name: Name)(using Context): LazyType =
val scope = ctx.effectiveScope
if name.isTermName then
completer.withModuleClass(findModuleBuddy(name.moduleClassName, scope))
else
completer.withSourceModule(findModuleBuddy(name.sourceModuleName, scope))
/** Find moduleClass/sourceModule in effective scope */
def findModuleBuddy(name: Name, scope: Scope)(using Context) = {
val it = scope.lookupAll(name).filter(_.is(Module))
if (it.hasNext) it.next()
else NoSymbol.assertingErrorsReported(s"no companion $name in $scope")
}
/** If a class has one of these flags, it does not get a constructor companion */
private val NoConstructorProxyNeededFlags = Abstract | Trait | Case | Synthetic | Module | Invisible
/** The flags of a constructor companion */
private val ConstructorCompanionFlags = Synthetic | ConstructorProxy
/** The flags of an `apply` method that serves as a constructor proxy */
val ApplyProxyFlags = Synthetic | ConstructorProxy | Inline | Method
/** Does symbol `cls` need constructor proxies to be generated? */
def needsConstructorProxies(sym: Symbol)(using Context): Boolean =
sym.isClass
&& !sym.flagsUNSAFE.isOneOf(NoConstructorProxyNeededFlags)
&& !sym.isAnonymousClass
||
sym.isType && sym.is(Exported)
&& sym.info.loBound.underlyingClassRef(refinementOK = false).match
case tref: TypeRef => tref.prefix.isStable
case _ => false
/** The completer of a constructor proxy apply method */
class ApplyProxyCompleter(constr: Symbol)(using Context) extends LazyType:
def complete(denot: SymDenotation)(using Context): Unit =
denot.info = constr.info
/** Add constructor proxy apply methods to `scope`. Proxies are for constructors
* in `cls` and they reside in `modcls`.
*/
def addConstructorApplies(scope: MutableScope, cls: ClassSymbol, modcls: ClassSymbol)(using Context): scope.type =
def proxy(constr: Symbol): Symbol =
newSymbol(
modcls, nme.apply, ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags),
ApplyProxyCompleter(constr), coord = constr.coord)
for dcl <- cls.info.decls do
if dcl.isConstructor then scope.enter(proxy(dcl))
scope
end addConstructorApplies
/** The completer of a constructor companion for class `cls`, where
* `modul` is the companion symbol and `modcls` is its class.
*/
def constructorCompanionCompleter(cls: ClassSymbol)(
modul: TermSymbol, modcls: ClassSymbol)(using Context): LazyType =
new LazyType with SymbolLoaders.SecondCompleter {
def complete(denot: SymDenotation)(using Context): Unit =
val prefix = modcls.owner.thisType
denot.info = ClassInfo(
prefix, modcls, defn.AnyType :: Nil,
addConstructorApplies(newScope, cls, modcls), TermRef(prefix, modul))
}.withSourceModule(modul)
/** A new symbol that is the constructor companion for class `cls` */
def classConstructorCompanion(cls: ClassSymbol)(using Context): TermSymbol =
val companion = newModuleSymbol(
cls.owner, cls.name.toTermName,
ConstructorCompanionFlags, ConstructorCompanionFlags,
constructorCompanionCompleter(cls),
coord = cls.coord,
assocFile = cls.assocFile)
companion.moduleClass.registerCompanion(cls)
cls.registerCompanion(companion.moduleClass)
companion
def typeConstructorCompanion(tsym: Symbol, prefix: Type, proxy: Symbol)(using Context): TermSymbol =
newSymbol(tsym.owner, tsym.name.toTermName,
ConstructorCompanionFlags | StableRealizable | Method, ExprType(prefix.select(proxy)), coord = tsym.coord)
/** Add all necesssary constructor proxy symbols for members of class `cls`. This means:
*
* - if a member is a class that needs a constructor companion, add one,
* provided no member with the same name exists.
* - if `cls` is a companion object of a class that needs a constructor companion,
* and `cls` does not already define or inherit an `apply` method,
* add `apply` methods for all constructors of the companion class.
*/
def addConstructorProxies(cls: ClassSymbol)(using Context): Unit =
def memberExists(cls: ClassSymbol, name: TermName): Boolean =
cls.baseClasses.exists(_.info.decls.lookupEntry(name) != null)
for mbr <- cls.info.decls do
if needsConstructorProxies(mbr) then
mbr match
case mbr: ClassSymbol =>
if !mbr.unforcedRegisteredCompanion.exists
&& !memberExists(cls, mbr.name.toTermName)
then
classConstructorCompanion(mbr).entered
case _ =>
mbr.info.loBound.underlyingClassRef(refinementOK = false) match
case ref: TypeRef =>
val proxy = ref.symbol.registeredCompanion
if proxy.is(ConstructorProxy) && !memberExists(cls, mbr.name.toTermName) then
typeConstructorCompanion(mbr, ref.prefix, proxy).entered
if cls.is(Module)
&& needsConstructorProxies(cls.linkedClass)
&& !memberExists(cls, nme.apply)
then
addConstructorApplies(cls.info.decls.openForMutations, cls.linkedClass.asClass, cls)
end addConstructorProxies
/** Turn `modul` into a constructor companion for class `cls` */
def makeConstructorCompanion(modul: TermSymbol, cls: ClassSymbol)(using Context): Unit =
val modcls = modul.moduleClass.asClass
modul.setFlag(ConstructorCompanionFlags)
modcls.setFlag(ConstructorCompanionFlags)
modcls.info = constructorCompanionCompleter(cls)(modul, modcls)
cls.registeredCompanion = modcls
modcls.registeredCompanion = cls
end NamerOps