Skip to content

Commit 7050335

Browse files
committed
Allow attachments for symbols, just like for trees.
Removes the two global hash maps in Namers, and the one in NamesDefaults. Also fixes SI-5975.
1 parent 4b6ae39 commit 7050335

File tree

15 files changed

+140
-74
lines changed

15 files changed

+140
-74
lines changed

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,6 @@ trait Namers extends MethodSynthesis {
5252
def newNamerFor(context: Context, tree: Tree): Namer =
5353
newNamer(context.makeNewScope(tree, tree.symbol))
5454

55-
// In the typeCompleter (templateSig) of a case class (resp it's module),
56-
// synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute
57-
// their signatures, the corresponding ClassDef is needed.
58-
// During naming, for each case class module symbol, the corresponding ClassDef
59-
// is stored in this map. The map is cleared lazily, i.e. when the new symbol
60-
// is created with the same name, the old one (if present) is wiped out, or the
61-
// entry is deleted when it is used and no longer needed.
62-
private val classOfModuleClass = perRunCaches.newWeakMap[Symbol, WeakReference[ClassDef]]()
63-
64-
// Default getters of constructors are added to the companion object in the
65-
// typeCompleter of the constructor (methodSig). To compute the signature,
66-
// we need the ClassDef. To create and enter the symbols into the companion
67-
// object, we need the templateNamer of that module class.
68-
// This map is extended during naming of classes, the Namer is added in when
69-
// it's available, i.e. in the type completer (templateSig) of the module class.
70-
private[typechecker] val classAndNamerOfModule = perRunCaches.newMap[Symbol, (ClassDef, Namer)]()
71-
72-
def resetNamer() {
73-
classAndNamerOfModule.clear()
74-
}
75-
7655
abstract class Namer(val context: Context) extends MethodSynth with NamerContextErrors { thisNamer =>
7756

7857
import NamerErrorGen._
@@ -621,15 +600,15 @@ trait Namers extends MethodSynthesis {
621600
MaxParametersCaseClassError(tree)
622601

623602
val m = ensureCompanionObject(tree, caseModuleDef)
624-
classOfModuleClass(m.moduleClass) = new WeakReference(tree)
603+
m.moduleClass.addAttachment(new ClassForCaseCompanionAttachment(tree))
625604
}
626605
val hasDefault = impl.body exists {
627606
case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => mexists(vparamss)(_.mods.hasDefault)
628607
case _ => false
629608
}
630609
if (hasDefault) {
631610
val m = ensureCompanionObject(tree)
632-
classAndNamerOfModule(m) = (tree, null)
611+
m.addAttachment(new ConstructorDefaultsAttachment(tree, null))
633612
}
634613
val owner = tree.symbol.owner
635614
if (settings.lint.value && owner.isPackageObjectClass && !mods.isImplicit) {
@@ -660,7 +639,8 @@ trait Namers extends MethodSynthesis {
660639
if (sym.isLazy)
661640
sym.lazyAccessor andAlso enterIfNotThere
662641

663-
defaultParametersOfMethod(sym) foreach { symRef => enterIfNotThere(symRef()) }
642+
for (defAtt <- sym.attachments.get[DefaultsOfLocalMethodAttachment])
643+
defAtt.defaultGetters foreach enterIfNotThere
664644
}
665645
this.context
666646
}
@@ -849,23 +829,20 @@ trait Namers extends MethodSynthesis {
849829
// add apply and unapply methods to companion objects of case classes,
850830
// unless they exist already; here, "clazz" is the module class
851831
if (clazz.isModuleClass) {
852-
Namers.this.classOfModuleClass get clazz foreach { cdefRef =>
853-
val cdef = cdefRef()
854-
if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer)
855-
classOfModuleClass -= clazz
832+
clazz.attachments.get[ClassForCaseCompanionAttachment] foreach { cma =>
833+
val cdef = cma.caseClass
834+
assert(cdef.mods.isCase, "expected case class: "+ cdef)
835+
addApplyUnapply(cdef, templateNamer)
856836
}
857837
}
858838

859839
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
860840
// the namer phase must traverse this copy method to create default getters for its parameters.
861841
// here, clazz is the ClassSymbol of the case class (not the module).
862-
// @check: this seems to work only if the type completer of the class runs before the one of the
863-
// module class: the one from the module class removes the entry from classOfModuleClass (see above).
864842
if (clazz.isClass && !clazz.hasModuleFlag) {
865843
val modClass = companionSymbolOf(clazz, context).moduleClass
866-
Namers.this.classOfModuleClass get modClass map { cdefRef =>
867-
val cdef = cdefRef()
868-
844+
modClass.attachments.get[ClassForCaseCompanionAttachment] foreach { cma =>
845+
val cdef = cma.caseClass
869846
def hasCopy(decls: Scope) = (decls lookup nme.copy) != NoSymbol
870847
if (cdef.mods.isCase && !hasCopy(decls) &&
871848
!parents.exists(p => hasCopy(p.typeSymbol.info.decls)) &&
@@ -877,9 +854,8 @@ trait Namers extends MethodSynthesis {
877854
// if default getters (for constructor defaults) need to be added to that module, here's the namer
878855
// to use. clazz is the ModuleClass. sourceModule works also for classes defined in methods.
879856
val module = clazz.sourceModule
880-
classAndNamerOfModule get module foreach {
881-
case (cdef, _) =>
882-
classAndNamerOfModule(module) = (cdef, templateNamer)
857+
for (cda <- module.attachments.get[ConstructorDefaultsAttachment]) {
858+
cda.companionModuleClassNamer = templateNamer
883859
}
884860
ClassInfoType(parents, decls, clazz)
885861
}
@@ -1100,13 +1076,15 @@ trait Namers extends MethodSynthesis {
11001076
val module = companionSymbolOf(clazz, context)
11011077
module.initialize // call type completer (typedTemplate), adds the
11021078
// module's templateNamer to classAndNamerOfModule
1103-
classAndNamerOfModule get module match {
1104-
case s @ Some((cdef, nmr)) if nmr != null =>
1105-
moduleNamer = s
1106-
(cdef, nmr)
1079+
module.attachments.get[ConstructorDefaultsAttachment] match {
1080+
// by martin: the null case can happen in IDE; this is really an ugly hack on top of an ugly hack but it seems to work
1081+
// later by lukas: disabled when fixing SI-5975, i think it cannot happen anymore
1082+
case Some(cda) /*if cma.companionModuleClassNamer == null*/ =>
1083+
val p = (cda.classWithDefault, cda.companionModuleClassNamer)
1084+
moduleNamer = Some(p)
1085+
p
11071086
case _ =>
11081087
return // fix #3649 (prevent crash in erroneous source code)
1109-
// nmr == null can happen in IDE; this is really an ugly hack on top[ of an ugly hack but it seems to work
11101088
}
11111089
}
11121090
deftParams = cdef.tparams map copyUntypedInvariant
@@ -1144,11 +1122,14 @@ trait Namers extends MethodSynthesis {
11441122
clazz.resetFlag(INTERFACE) // there's a concrete member now
11451123
val default = parentNamer.enterSyntheticSym(defaultTree)
11461124
if (forInteractive && default.owner.isTerm) {
1147-
// enter into map from method symbols to default arguments.
1148-
// if compiling the same local block several times (which can happen in interactive mode)
1149-
// we might otherwise not find the default symbol, because the second time it the
1150-
// method symbol will be re-entered in the scope but the default parameter will not.
1151-
defaultParametersOfMethod(meth) += new WeakReference(default)
1125+
// save the default getters as attachments in the method symbol. if compiling the
1126+
// same local block several times (which can happen in interactive mode) we might
1127+
// otherwise not find the default symbol, because the second time it the method
1128+
// symbol will be re-entered in the scope but the default parameter will not.
1129+
val att = meth.attachments.get[DefaultsOfLocalMethodAttachment] match {
1130+
case Some(att) => att.defaultGetters += default
1131+
case None => meth.addAttachment(new DefaultsOfLocalMethodAttachment(default))
1132+
}
11521133
}
11531134
} else if (baseHasDefault) {
11541135
// the parameter does not have a default itself, but the

src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,19 @@ trait NamesDefaults { self: Analyzer =>
2121
import definitions._
2222
import NamesDefaultsErrorsGen._
2323

24-
val defaultParametersOfMethod =
25-
perRunCaches.newWeakMap[Symbol, Set[WeakReference[Symbol]]]() withDefaultValue Set()
24+
// Default getters of constructors are added to the companion object in the
25+
// typeCompleter of the constructor (methodSig). To compute the signature,
26+
// we need the ClassDef. To create and enter the symbols into the companion
27+
// object, we need the templateNamer of that module class. These two are stored
28+
// as an attachment in the companion module symbol
29+
class ConstructorDefaultsAttachment(val classWithDefault: ClassDef, var companionModuleClassNamer: Namer)
30+
31+
// To attach the default getters of local (term-owned) methods to the method symbol.
32+
// Used in Namer.enterExistingSym: it needs to re-enter the method symbol and also
33+
// default getters, which could not be found otherwise.
34+
class DefaultsOfLocalMethodAttachment(val defaultGetters: mutable.Set[Symbol]) {
35+
def this(default: Symbol) = this(mutable.Set(default))
36+
}
2637

2738
case class NamedApplyInfo(
2839
qual: Option[Tree],

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ trait Typers extends Modes with Adaptations with Tags {
4747
def resetTyper() {
4848
//println("resetTyper called")
4949
resetContexts()
50-
resetNamer()
5150
resetImplicits()
5251
transformed.clear()
5352
}

src/compiler/scala/tools/nsc/typechecker/Unapplies.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ trait Unapplies extends ast.TreeDSL
2323

2424
private val unapplyParamName = nme.x_0
2525

26+
27+
// In the typeCompleter (templateSig) of a case class (resp it's module),
28+
// synthetic `copy` (reps `apply`, `unapply`) methods are added. To compute
29+
// their signatures, the corresponding ClassDef is needed. During naming (in
30+
// `enterClassDef`), the case class ClassDef is added as an attachment to the
31+
// moduleClass symbol of the companion module.
32+
class ClassForCaseCompanionAttachment(val caseClass: ClassDef)
33+
2634
/** returns type list for return type of the extraction */
2735
def unapplyTypeList(ufn: Symbol, ufntpe: Type) = {
2836
assert(ufn.isMethod, ufn)

src/reflect/scala/reflect/internal/StdAttachments.scala

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,24 @@ package internal
44
trait StdAttachments {
55
self: SymbolTable =>
66

7+
/**
8+
* Common code between reflect-internal Symbol and Tree related to Attachments.
9+
*/
10+
trait Attachable {
11+
protected var rawatt: base.Attachments { type Pos = Position } = NoPosition
12+
def attachments = rawatt
13+
def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this }
14+
def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
15+
16+
// cannot be final due to SynchronizedSymbols
17+
def pos: Position = rawatt.pos
18+
def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos)
19+
def setPos(newpos: Position): this.type = { pos = newpos; this }
20+
}
21+
722
case object BackquotedIdentifierAttachment
823

924
case class CompoundTypeTreeOriginalAttachment(parents: List[Tree], stats: List[Tree])
1025

1126
case class MacroExpansionAttachment(original: Tree)
12-
}
27+
}

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import scala.collection.{ mutable, immutable }
1010
import scala.collection.mutable.ListBuffer
1111
import util.Statistics
1212
import Flags._
13+
import base.Attachments
1314

1415
trait Symbols extends api.Symbols { self: SymbolTable =>
1516
import definitions._
@@ -154,7 +155,8 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
154155
abstract class Symbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: Name)
155156
extends SymbolContextApiImpl
156157
with HasFlags
157-
with Annotatable[Symbol] {
158+
with Annotatable[Symbol]
159+
with Attachable {
158160

159161
type AccessBoundaryType = Symbol
160162
type AnnotationType = AnnotationInfo
@@ -176,7 +178,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
176178
def rawowner = _rawowner
177179
def rawflags = _rawflags
178180

179-
private var rawpos = initPos
181+
rawatt = initPos
180182

181183
val id = nextId() // identity displayed when -uniqid
182184
//assert(id != 3390, initName)
@@ -189,8 +191,6 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
189191
def validTo = _validTo
190192
def validTo_=(x: Period) { _validTo = x}
191193

192-
def pos = rawpos
193-
def setPos(pos: Position): this.type = { this.rawpos = pos; this }
194194
def setName(name: Name): this.type = { this.name = asNameType(name) ; this }
195195

196196
// Update the surrounding scopes
@@ -1616,6 +1616,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
16161616
setInfo (this.info cloneInfo clone)
16171617
setAnnotations this.annotations
16181618
)
1619+
this.attachments.all.foreach(clone.addAttachment)
16191620
if (clone.thisSym != clone)
16201621
clone.typeOfThis = (clone.typeOfThis cloneInfo clone)
16211622

src/reflect/scala/reflect/internal/Trees.scala

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,13 @@ trait Trees extends api.Trees { self: SymbolTable =>
1515

1616
private[scala] var nodeCount = 0
1717

18-
abstract class Tree extends TreeContextApiImpl with Product {
18+
abstract class Tree extends TreeContextApiImpl with Attachable with Product {
1919
val id = nodeCount // TODO: add to attachment?
2020
nodeCount += 1
2121

2222
Statistics.incCounter(TreesStats.nodeByType, getClass)
2323

24-
@inline final def pos: Position = rawatt.pos
25-
def pos_=(pos: Position): Unit = rawatt = (rawatt withPos pos)
26-
def setPos(newpos: Position): this.type = { pos = newpos; this }
27-
28-
private var rawatt: Attachments { type Pos = Position } = NoPosition
29-
def attachments = rawatt
30-
def addAttachment(attachment: Any): this.type = { rawatt = rawatt.add(attachment); this }
31-
def removeAttachment[T: ClassTag]: this.type = { rawatt = rawatt.remove[T]; this }
24+
@inline final override def pos: Position = rawatt.pos
3225

3326
private[this] var rawtpe: Type = _
3427
@inline final def tpe = rawtpe

src/reflect/scala/reflect/makro/Universe.scala

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,24 @@ abstract class Universe extends scala.reflect.api.Universe {
55

66
val treeBuild: TreeBuilder { val global: Universe.this.type }
77

8+
trait AttachableApi {
9+
/** ... */
10+
def attachments: base.Attachments { type Pos = Position }
11+
12+
/** ... */
13+
def addAttachment(attachment: Any): AttachableApi.this.type
14+
15+
/** ... */
16+
def removeAttachment[T: ClassTag]: AttachableApi.this.type
17+
}
18+
819
// Symbol extensions ---------------------------------------------------------------
920

1021
override type Symbol >: Null <: SymbolContextApi
1122

1223
/** The extended API of symbols that's supported in macro context universes
1324
*/
14-
trait SymbolContextApi extends SymbolApi { this: Symbol =>
25+
trait SymbolContextApi extends SymbolApi with AttachableApi { this: Symbol =>
1526

1627
// [Eugene++ to Martin] should we also add mutability methods here (similarly to what's done below for trees)?
1728
// I'm talking about `setAnnotations` and friends
@@ -23,7 +34,7 @@ abstract class Universe extends scala.reflect.api.Universe {
2334

2435
/** The extended API of trees that's supported in macro context universes
2536
*/
26-
trait TreeContextApi extends TreeApi { this: Tree =>
37+
trait TreeContextApi extends TreeApi with AttachableApi { this: Tree =>
2738

2839
/** ... */
2940
def pos_=(pos: Position): Unit
@@ -62,15 +73,6 @@ abstract class Universe extends scala.reflect.api.Universe {
6273

6374
/** ... */
6475
def setSymbol(sym: Symbol): this.type
65-
66-
/** ... */
67-
def attachments: base.Attachments { type Pos = Position }
68-
69-
/** ... */
70-
def addAttachment(attachment: Any): this.type
71-
72-
/** ... */
73-
def removeAttachment[T: ClassTag]: this.type
7476
}
7577

7678
override type SymTree >: Null <: Tree with SymTreeContextApi
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Test OK
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
-sourcepath src

0 commit comments

Comments
 (0)