@@ -6,9 +6,9 @@ import core._
6
6
import util .Positions ._ , Types ._ , Contexts ._ , Constants ._ , Names ._ , NameOps ._ , Flags ._
7
7
import SymDenotations ._ , Symbols ._ , StdNames ._ , Annotations ._ , Trees ._
8
8
import Decorators ._
9
- import util .Attachment
10
9
import language .higherKinds
11
10
import collection .mutable .ListBuffer
11
+ import config .Printers ._
12
12
import typer .ErrorReporting .InfoString
13
13
import typer .Mode
14
14
@@ -22,34 +22,64 @@ object desugar {
22
22
/** Info of a variable in a pattern: The named tree and its type */
23
23
private type VarInfo = (NameTree , Tree )
24
24
25
- // ----- TypeTrees that refer to other tree's symbols -------------------
25
+ // ----- DerivedTypeTrees ---------------- -------------------
26
26
27
- /** Attachment key containing TypeTrees whose type is computed
28
- * from the symbol in this type. These type trees have marker trees
29
- * TypeRefOfSym or InfoOfSym as their originals.
30
- */
31
- val References = new Attachment .Key [List [Tree ]]
27
+ class SetterParamTree extends DerivedTypeTree {
28
+ def derivedType (sym : Symbol )(implicit ctx : Context ) = sym.info.resultType
29
+ }
32
30
33
- /** Attachment key for TypeTrees marked with TypeRefOfSym or InfoOfSym
34
- * which contains the symbol of the original tree from which this
35
- * TypeTree is derived.
36
- */
37
- val OriginalSymbol = new Attachment .Key [Symbol ]
31
+ class TypeRefTree extends DerivedTypeTree {
32
+ def derivedType (sym : Symbol )(implicit ctx : Context ) = sym.typeRef
33
+ }
38
34
39
- /** A type tree that gets its type from some other tree's symbol. Enters the
40
- * type tree in the References attachment of the `from` tree as a side effect.
41
- */
42
- abstract class DerivedTypeTree (from : Tree ) extends TypeTree (EmptyTree ) {
43
- val existing = from.attachmentOrElse(References , Nil )
44
- from.putAttachment(References , this :: existing)
35
+ class DerivedFromParamTree extends DerivedTypeTree {
45
36
46
- /** The method that computes the type of this tree */
47
- def derivedType (originalSym : Symbol )(implicit ctx : Context ): Type
37
+ /** Make sure that for all enclosing module classes their companion lasses
38
+ * are completed. Reason: We need the constructor of such companion classes to
39
+ * be completed so that OriginalSymbol attachments are pushed to DerivedTypeTrees
40
+ * in appy/unapply methods.
41
+ */
42
+ override def ensureCompletions (implicit ctx : Context ) =
43
+ if (! (ctx.owner is Package ))
44
+ if (ctx.owner is ModuleClass ) ctx.owner.linkedClass.ensureCompleted()
45
+ else ensureCompletions(ctx.outer)
46
+
47
+ /** Return info of original symbol, where all references to siblings of the
48
+ * original symbol (i.e. sibling and original symbol have the same owner)
49
+ * are rewired to same-named parameters or accessors in the scope enclosing
50
+ * the current scope. The current scope is the scope owned by the defined symbol
51
+ * itself, that's why we have to look one scope further out. If the resulting
52
+ * type is an alias type, dealias it. This is necessary because the
53
+ * accessor of a type parameter is a private type alias that cannot be accessed
54
+ * from subclasses.
55
+ */
56
+ def derivedType (sym : Symbol )(implicit ctx : Context ) = {
57
+ val relocate = new TypeMap {
58
+ val originalOwner = sym.owner
59
+ def apply (tp : Type ) = tp match {
60
+ case tp : NamedType if tp.symbol.owner eq originalOwner =>
61
+ val defctx = ctx.outersIterator.dropWhile(_.scope eq ctx.scope).next
62
+ var local = defctx.denotNamed(tp.name).suchThat(_ is ParamOrAccessor ).symbol
63
+ typr.println(s " rewiring ${tp.symbol} from ${originalOwner.showLocated} to ${local.showLocated}, current owner = ${ctx.owner.showLocated}" )
64
+ if (local.exists) (defctx.owner.thisType select local).dealias
65
+ else throw new Error (s " no matching symbol for ${sym.showLocated} in ${defctx.owner} / ${defctx.effectiveScope}" )
66
+ case _ =>
67
+ mapOver(tp)
68
+ }
69
+ }
70
+ relocate(sym.info)
71
+ }
48
72
}
49
73
50
- class SetterParam (vdef : ValDef ) extends DerivedTypeTree (vdef) {
51
- def derivedType (vsym : Symbol )(implicit ctx : Context ) = vsym.info.resultType
52
- }
74
+ /** A type definition copied from `tdef` with a rhs typetree derived from it */
75
+ def derivedTypeParam (tdef : TypeDef ) =
76
+ cpy.TypeDef (tdef, tdef.mods, tdef.name,
77
+ new DerivedFromParamTree () withPos tdef.rhs.pos watching tdef, tdef.tparams) // todo: copy type params
78
+
79
+ /** A value definition copied from `vdef` with a tpt typetree derived from it */
80
+ def derivedTermParam (vdef : ValDef ) =
81
+ cpy.ValDef (vdef, vdef.mods, vdef.name,
82
+ new DerivedFromParamTree () withPos vdef.tpt.pos watching vdef, vdef.rhs)
53
83
54
84
// ----- Desugar methods -------------------------------------------------
55
85
@@ -67,7 +97,7 @@ object desugar {
67
97
// val getter = ValDef(mods, name, tpt, rhs) withPos vdef.pos ?
68
98
// right now vdef maps via expandedTree to a thicket which concerns itself.
69
99
// I don't see a problem with that but if there is one we can avoid it by making a copy here.
70
- val setterParam = makeSyntheticParameter(tpt = new SetterParam (vdef))
100
+ val setterParam = makeSyntheticParameter(tpt = ( new SetterParamTree ).watching (vdef))
71
101
val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral
72
102
val setter = cpy.DefDef (vdef,
73
103
mods | Accessor , name.setterName, Nil , (setterParam :: Nil ) :: Nil ,
@@ -183,6 +213,9 @@ object desugar {
183
213
private def toDefParam (tparam : TypeDef ) =
184
214
cpy.TypeDef (tparam, Modifiers (Param ), tparam.name, tparam.rhs, tparam.tparams)
185
215
216
+ private def toDefParam (vparam : ValDef ) =
217
+ cpy.ValDef (vparam, Modifiers (Param | vparam.mods.flags & Implicit ), vparam.name, vparam.tpt, vparam.rhs)
218
+
186
219
/** The expansion of a class definition. See inline comments for what is involved */
187
220
def classDef (cdef : TypeDef )(implicit ctx : Context ): Tree = {
188
221
val TypeDef (
@@ -198,31 +231,35 @@ object desugar {
198
231
// prefixed by type or val). `tparams` and `vparamss` are the type parameters that
199
232
// go in `constr`, the constructor after desugaring.
200
233
201
- val tparams = constr1.tparams map toDefParam
202
- val vparamss =
234
+ val constrTparams = constr1.tparams map toDefParam
235
+ val constrVparamss =
203
236
if (constr1.vparamss.isEmpty) { // ensure parameter list is non-empty
204
237
if (mods is Case )
205
238
ctx.error(" case class needs to have at least one parameter list" , cdef.pos)
206
239
ListOfNil
207
- } else
208
- constr1.vparamss.nestedMap(vparam => cpy.ValDef (vparam,
209
- Modifiers (Param | vparam.mods.flags & Implicit ), vparam.name, vparam.tpt, vparam.rhs))
210
-
240
+ }
241
+ else constr1.vparamss.nestedMap(toDefParam)
211
242
val constr = cpy.DefDef (constr1,
212
- constr1.mods, constr1.name, tparams, vparamss, constr1.tpt, constr1.rhs)
243
+ constr1.mods, constr1.name, constrTparams, constrVparamss, constr1.tpt, constr1.rhs)
244
+
245
+ val derivedTparams = constrTparams map derivedTypeParam
246
+ val derivedVparamss = constrVparamss nestedMap derivedTermParam
247
+ val arity = constrVparamss.head.length
248
+
249
+ var classTycon : Tree = EmptyTree
213
250
214
251
// a reference to the class type, with all parameters given.
215
252
val classTypeRef /* : Tree*/ = {
216
253
// -language:keepUnions difference: classTypeRef needs type annotation, otherwise
217
254
// infers Ident | AppliedTypeTree, which
218
255
// renders the :\ in companions below untypable.
219
- val tycon = Ident (cdef.name ) withPos cdef.pos.startPos
256
+ classTycon = ( new TypeRefTree ) withPos cdef.pos.startPos // watching is set at end of method
220
257
val tparams = impl.constr.tparams
221
- if (tparams.isEmpty) tycon else AppliedTypeTree (tycon , tparams map refOfDef)
258
+ if (tparams.isEmpty) classTycon else AppliedTypeTree (classTycon , tparams map refOfDef)
222
259
}
223
260
224
261
// new C[Ts](paramss)
225
- lazy val creatorExpr = New (classTypeRef, vparamss nestedMap refOfDef)
262
+ lazy val creatorExpr = New (classTypeRef, constrVparamss nestedMap refOfDef)
226
263
227
264
// Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
228
265
// def isDefined = true
@@ -233,23 +270,23 @@ object desugar {
233
270
// def copy(p1: T1 = p1, ..., pN: TN = pN)(moreParams) = new C[...](p1, ..., pN)(moreParams)
234
271
val caseClassMeths =
235
272
if (mods is Case ) {
236
- val caseParams = vparamss.head.toArray
237
273
def syntheticProperty (name : TermName , rhs : Tree ) =
238
274
DefDef (synthetic, name, Nil , Nil , TypeTree (), rhs)
239
275
val isDefinedMeth = syntheticProperty(nme.isDefined, Literal (Constant (true )))
240
- val productArityMeth = syntheticProperty(nme.productArity, Literal (Constant (caseParams.length )))
276
+ val productArityMeth = syntheticProperty(nme.productArity, Literal (Constant (arity )))
241
277
def selectorName (n : Int ) =
242
- if (caseParams.length == 1 ) nme.get else nme.selectorName(n)
243
- val productElemMeths = for (i <- 0 until caseParams.length) yield
278
+ if (arity == 1 ) nme.get else nme.selectorName(n)
279
+ val caseParams = constrVparamss.head.toArray
280
+ val productElemMeths = for (i <- 0 until arity) yield
244
281
syntheticProperty(selectorName(i), Select (This (EmptyTypeName ), caseParams(i).name))
245
282
val copyMeths =
246
283
if (mods is Abstract ) Nil
247
284
else {
248
- val copyFirstParams = vparamss .head.map(vparam =>
285
+ val copyFirstParams = derivedVparamss .head.map(vparam =>
249
286
cpy.ValDef (vparam, vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam)))
250
- val copyRestParamss = vparamss .tail.nestedMap(vparam =>
287
+ val copyRestParamss = derivedVparamss .tail.nestedMap(vparam =>
251
288
cpy.ValDef (vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree ))
252
- DefDef (synthetic, nme.copy, tparams , copyFirstParams :: copyRestParamss, TypeTree (), creatorExpr) :: Nil
289
+ DefDef (synthetic, nme.copy, derivedTparams , copyFirstParams :: copyRestParamss, TypeTree (), creatorExpr) :: Nil
253
290
}
254
291
copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList
255
292
}
@@ -258,15 +295,14 @@ object desugar {
258
295
def anyRef = ref(defn.AnyRefAlias .typeRef)
259
296
def productConstr (n : Int ) = {
260
297
val tycon = ref(defn.ProductNClass (n).typeRef)
261
- val targs = vparamss .head map (_.tpt)
298
+ val targs = constrVparamss .head map (_.tpt)
262
299
AppliedTypeTree (tycon, targs)
263
300
}
264
301
265
302
// Case classes get a ProductN parent
266
303
var parents1 = parents
267
- val n = vparamss.head.length
268
- if ((mods is Case ) && 2 <= n && n <= Definitions .MaxTupleArity )
269
- parents1 = parents1 :+ productConstr(n)
304
+ if ((mods is Case ) && 2 <= arity && arity <= Definitions .MaxTupleArity )
305
+ parents1 = parents1 :+ productConstr(arity)
270
306
271
307
// The thicket which is the desugared version of the companion object
272
308
// synthetic object C extends parentTpt { defs }
@@ -288,17 +324,18 @@ object desugar {
288
324
val companions =
289
325
if (mods is Case ) {
290
326
val parent =
291
- if (tparams .nonEmpty) anyRef
292
- else (vparamss :\ classTypeRef) ((vparams, restpe) => Function (vparams map (_.tpt), restpe))
327
+ if (constrTparams .nonEmpty) anyRef // todo: also use anyRef if constructor has a dependent method type (or rule that out)!
328
+ else (constrVparamss :\ classTypeRef) ((vparams, restpe) => Function (vparams map (_.tpt), restpe))
293
329
val applyMeths =
294
330
if (mods is Abstract ) Nil
295
- else DefDef (
331
+ else
332
+ DefDef (
296
333
synthetic | (constr1.mods.flags & DefaultParameterized ), nme.apply,
297
- tparams, vparamss , TypeTree (), creatorExpr) :: Nil
334
+ derivedTparams, derivedVparamss , TypeTree (), creatorExpr) :: Nil
298
335
val unapplyMeth = {
299
336
val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
300
- val unapplyRHS = if (n == 0 ) Literal (Constant (true )) else Ident (unapplyParam.name)
301
- DefDef (synthetic, nme.unapply, tparams , (unapplyParam :: Nil ) :: Nil , TypeTree (), unapplyRHS)
337
+ val unapplyRHS = if (arity == 0 ) Literal (Constant (true )) else Ident (unapplyParam.name)
338
+ DefDef (synthetic, nme.unapply, derivedTparams , (unapplyParam :: Nil ) :: Nil , TypeTree (), unapplyRHS)
302
339
}
303
340
companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters)
304
341
}
@@ -315,19 +352,40 @@ object desugar {
315
352
ctx.error(" implicit classes may not be toplevel" , cdef.pos)
316
353
if (mods is Case )
317
354
ctx.error(" implicit classes may not case classes" , cdef.pos)
355
+
356
+ // implicit wrapper is typechecked in same scope as constructor, so
357
+ // we can reuse the constructor parameters; no derived params are needed.
318
358
DefDef (Modifiers (Synthetic | Implicit ), name.toTermName,
319
- tparams, vparamss , classTypeRef, creatorExpr) :: Nil
359
+ constrTparams, constrVparamss , classTypeRef, creatorExpr) :: Nil
320
360
}
321
361
else Nil
322
362
323
- val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt
324
- val self1 =
363
+ val self1 = {
364
+ val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt
325
365
if (self.isEmpty) self
326
366
else cpy.ValDef (self, self.mods | SelfName , self.name, selfType, self.rhs)
367
+ }
368
+
369
+ val cdef1 = {
370
+ val originalTparams = constr1.tparams.toIterator
371
+ val originalVparams = constr1.vparamss.toIterator.flatten
372
+ val tparamAccessors = derivedTparams map { tdef =>
373
+ cpy.TypeDef (tdef, originalTparams.next.mods, tdef.name, tdef.rhs, tdef.tparams)
374
+ }
375
+ val vparamAccessors = derivedVparamss.flatten map { vdef =>
376
+ cpy.ValDef (vdef, originalVparams.next.mods, vdef.name, vdef.tpt, vdef.rhs)
377
+ }
378
+ cpy.TypeDef (cdef, mods, name,
379
+ cpy.Template (impl, constr, parents1, self1,
380
+ tparamAccessors ::: vparamAccessors ::: body ::: caseClassMeths))
381
+ }
382
+
383
+ // install the watch on classTycon
384
+ classTycon match {
385
+ case tycon : DerivedTypeTree => tycon.watching(cdef1)
386
+ case _ =>
387
+ }
327
388
328
- val cdef1 = cpy.TypeDef (cdef, mods, name,
329
- cpy.Template (impl, constr, parents1, self1,
330
- constr1.tparams ::: constr1.vparamss.flatten ::: body ::: caseClassMeths))
331
389
flatTree(cdef1 :: companions ::: implicitWrappers)
332
390
}
333
391
0 commit comments