|
1 |
| -package dotty.tools.dotc |
| 1 | +package dotty.tools |
| 2 | +package dotc |
2 | 3 | package core
|
3 | 4 |
|
4 |
| -import Contexts._, Symbols._, Types._, Flags._, Scopes._, Decorators._, NameOps._ |
| 5 | +import Contexts._, Symbols._, Types._, Flags._, Scopes._, Decorators._, Names._, NameOps._ |
5 | 6 | import Denotations._
|
6 |
| -import SymDenotations.LazyType, Names.Name, StdNames.nme |
| 7 | +import SymDenotations.{LazyType, SymDenotation}, StdNames.nme |
| 8 | +import config.Config |
| 9 | +import ast.untpd |
7 | 10 |
|
8 | 11 | /** Operations that are shared between Namer and TreeUnpickler */
|
9 | 12 | object NamerOps:
|
@@ -57,4 +60,97 @@ object NamerOps:
|
57 | 60 | else NoSymbol.assertingErrorsReported(s"no companion $name in $scope")
|
58 | 61 | }
|
59 | 62 |
|
| 63 | + /** If a class has one of these flags, it does not get a constructor companion */ |
| 64 | + private val NoConstructorProxyNeededFlags = Abstract | Trait | Case | Synthetic | Module |
| 65 | + |
| 66 | + /** The flags of a constructor companion */ |
| 67 | + private val ConstructorCompanionFlags = Synthetic | ConstructorProxy |
| 68 | + |
| 69 | + /** The flags of an `apply` method that serves as a constructor proxy */ |
| 70 | + val ApplyProxyFlags = Synthetic | ConstructorProxy | Inline | Method |
| 71 | + |
| 72 | + /** Does symbol `cls` need constructor proxies to be generated? */ |
| 73 | + def needsConstructorProxies(cls: Symbol)(using Context): Boolean = |
| 74 | + cls.isClass |
| 75 | + && !cls.flagsUNSAFE.isOneOf(NoConstructorProxyNeededFlags) |
| 76 | + && !cls.isAnonymousClass |
| 77 | + |
| 78 | + /** The completer of a constructor proxy apply method */ |
| 79 | + class ApplyProxyCompleter(constr: Symbol)(using Context) extends LazyType: |
| 80 | + def complete(denot: SymDenotation)(using Context): Unit = |
| 81 | + denot.info = constr.info |
| 82 | + |
| 83 | + /** Add constructor proxy apply methods to `scope`. Proxies are for constructors |
| 84 | + * in `cls` and they reside in `modcls`. |
| 85 | + */ |
| 86 | + def addConstructorApplies(scope: MutableScope, cls: ClassSymbol, modcls: ClassSymbol)(using Context): scope.type = |
| 87 | + def proxy(constr: Symbol): Symbol = |
| 88 | + newSymbol( |
| 89 | + modcls, nme.apply, ApplyProxyFlags | (constr.flagsUNSAFE & AccessFlags), |
| 90 | + ApplyProxyCompleter(constr), coord = constr.coord) |
| 91 | + for dcl <- cls.info.decls do |
| 92 | + if dcl.isConstructor then scope.enter(proxy(dcl)) |
| 93 | + scope |
| 94 | + end addConstructorApplies |
| 95 | + |
| 96 | + /** The completer of a constructor companion for class `cls`, where |
| 97 | + * `modul` is the companion symbol and `modcls` is its class. |
| 98 | + */ |
| 99 | + def constructorCompanionCompleter(cls: ClassSymbol)( |
| 100 | + modul: TermSymbol, modcls: ClassSymbol)(using Context): LazyType = |
| 101 | + new LazyType with SymbolLoaders.SecondCompleter { |
| 102 | + def complete(denot: SymDenotation)(using Context): Unit = |
| 103 | + val prefix = modcls.owner.thisType |
| 104 | + denot.info = ClassInfo( |
| 105 | + prefix, modcls, defn.AnyType :: Nil, |
| 106 | + addConstructorApplies(newScope, cls, modcls), TermRef(prefix, modul)) |
| 107 | + }.withSourceModule(modul) |
| 108 | + |
| 109 | + /** A new symbol that is the constructor companion for class `cls` */ |
| 110 | + def constructorCompanion(cls: ClassSymbol)(using Context): TermSymbol = |
| 111 | + val companion = newModuleSymbol( |
| 112 | + cls.owner, cls.name.toTermName, |
| 113 | + ConstructorCompanionFlags, ConstructorCompanionFlags, |
| 114 | + constructorCompanionCompleter(cls), |
| 115 | + coord = cls.coord, |
| 116 | + assocFile = cls.assocFile) |
| 117 | + companion.moduleClass.registerCompanion(cls) |
| 118 | + cls.registerCompanion(companion.moduleClass) |
| 119 | + companion |
| 120 | + |
| 121 | + /** Add all necesssary constructor proxy symbols for members of class `cls`. This means: |
| 122 | + * |
| 123 | + * - if a member is a class that needs a constructor companion, add one, |
| 124 | + * provided no member with the same name exists. |
| 125 | + * - if `cls` is a companion object of a class that needs a constructor companion, |
| 126 | + * and `cls` does not already define or inherit an `apply` method, |
| 127 | + * add `apply` methods for all constructors of the companion class. |
| 128 | + */ |
| 129 | + def addConstructorProxies(cls: ClassSymbol)(using Context): Unit = |
| 130 | + |
| 131 | + def memberExists(cls: ClassSymbol, name: TermName): Boolean = |
| 132 | + cls.baseClasses.exists(_.info.decls.lookupEntry(name) != null) |
| 133 | + for mbr <- cls.info.decls do |
| 134 | + if needsConstructorProxies(mbr) |
| 135 | + && !mbr.asClass.unforcedRegisteredCompanion.exists |
| 136 | + && !memberExists(cls, mbr.name.toTermName) |
| 137 | + then |
| 138 | + constructorCompanion(mbr.asClass).entered |
| 139 | + |
| 140 | + if cls.is(Module) |
| 141 | + && needsConstructorProxies(cls.linkedClass) |
| 142 | + && !memberExists(cls, nme.apply) |
| 143 | + then |
| 144 | + addConstructorApplies(cls.info.decls.openForMutations, cls.linkedClass.asClass, cls) |
| 145 | + end addConstructorProxies |
| 146 | + |
| 147 | + /** Turn `modul` into a constructor companion for class `cls` */ |
| 148 | + def makeConstructorCompanion(modul: TermSymbol, cls: ClassSymbol)(using Context): Unit = |
| 149 | + val modcls = modul.moduleClass.asClass |
| 150 | + modul.setFlag(ConstructorCompanionFlags) |
| 151 | + modcls.setFlag(ConstructorCompanionFlags) |
| 152 | + modcls.info = constructorCompanionCompleter(cls)(modul, modcls) |
| 153 | + cls.registeredCompanion = modcls |
| 154 | + modcls.registeredCompanion = cls |
| 155 | + |
60 | 156 | end NamerOps
|
0 commit comments