@@ -8,6 +8,7 @@ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._
8
8
import Decorators ._
9
9
import language .higherKinds
10
10
import collection .mutable .ListBuffer
11
+ import config .Printers ._
11
12
import typer .ErrorReporting .InfoString
12
13
import typer .Mode
13
14
@@ -21,6 +22,67 @@ object desugar {
21
22
/** Info of a variable in a pattern: The named tree and its type */
22
23
private type VarInfo = (NameTree , Tree )
23
24
25
+ // ----- DerivedTypeTrees -----------------------------------
26
+
27
+ class SetterParamTree extends DerivedTypeTree {
28
+ def derivedType (sym : Symbol )(implicit ctx : Context ) = sym.info.resultType
29
+ }
30
+
31
+ class TypeRefTree extends DerivedTypeTree {
32
+ def derivedType (sym : Symbol )(implicit ctx : Context ) = sym.typeRef
33
+ }
34
+
35
+ class DerivedFromParamTree extends DerivedTypeTree {
36
+
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
+ }
72
+ }
73
+
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)
83
+
84
+ // ----- Desugar methods -------------------------------------------------
85
+
24
86
/** var x: Int = expr
25
87
* ==>
26
88
* def x: Int = expr
@@ -35,7 +97,7 @@ object desugar {
35
97
// val getter = ValDef(mods, name, tpt, rhs) withPos vdef.pos ?
36
98
// right now vdef maps via expandedTree to a thicket which concerns itself.
37
99
// I don't see a problem with that but if there is one we can avoid it by making a copy here.
38
- val setterParam = makeSyntheticParameter(tpt = TypeTree ( ))
100
+ val setterParam = makeSyntheticParameter(tpt = ( new SetterParamTree ).watching(vdef ))
39
101
val setterRhs = if (vdef.rhs.isEmpty) EmptyTree else unitLiteral
40
102
val setter = cpy.DefDef (vdef,
41
103
mods | Accessor , name.setterName, Nil , (setterParam :: Nil ) :: Nil ,
@@ -151,6 +213,9 @@ object desugar {
151
213
private def toDefParam (tparam : TypeDef ) =
152
214
cpy.TypeDef (tparam, Modifiers (Param ), tparam.name, tparam.rhs, tparam.tparams)
153
215
216
+ private def toDefParam (vparam : ValDef ) =
217
+ cpy.ValDef (vparam, Modifiers (Param | vparam.mods.flags & Implicit ), vparam.name, vparam.tpt, vparam.rhs)
218
+
154
219
/** The expansion of a class definition. See inline comments for what is involved */
155
220
def classDef (cdef : TypeDef )(implicit ctx : Context ): Tree = {
156
221
val TypeDef (
@@ -166,31 +231,35 @@ object desugar {
166
231
// prefixed by type or val). `tparams` and `vparamss` are the type parameters that
167
232
// go in `constr`, the constructor after desugaring.
168
233
169
- val tparams = constr1.tparams map toDefParam
170
- val vparamss =
234
+ val constrTparams = constr1.tparams map toDefParam
235
+ val constrVparamss =
171
236
if (constr1.vparamss.isEmpty) { // ensure parameter list is non-empty
172
237
if (mods is Case )
173
238
ctx.error(" case class needs to have at least one parameter list" , cdef.pos)
174
239
ListOfNil
175
- } else
176
- constr1.vparamss.nestedMap(vparam => cpy.ValDef (vparam,
177
- Modifiers (Param | vparam.mods.flags & Implicit ), vparam.name, vparam.tpt, vparam.rhs))
178
-
240
+ }
241
+ else constr1.vparamss.nestedMap(toDefParam)
179
242
val constr = cpy.DefDef (constr1,
180
- 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
181
250
182
251
// a reference to the class type, with all parameters given.
183
252
val classTypeRef /* : Tree*/ = {
184
253
// -language:keepUnions difference: classTypeRef needs type annotation, otherwise
185
254
// infers Ident | AppliedTypeTree, which
186
255
// renders the :\ in companions below untypable.
187
- val tycon = Ident (cdef.name ) withPos cdef.pos.startPos
256
+ classTycon = ( new TypeRefTree ) withPos cdef.pos.startPos // watching is set at end of method
188
257
val tparams = impl.constr.tparams
189
- if (tparams.isEmpty) tycon else AppliedTypeTree (tycon , tparams map refOfDef)
258
+ if (tparams.isEmpty) classTycon else AppliedTypeTree (classTycon , tparams map refOfDef)
190
259
}
191
260
192
261
// new C[Ts](paramss)
193
- lazy val creatorExpr = New (classTypeRef, vparamss nestedMap refOfDef)
262
+ lazy val creatorExpr = New (classTypeRef, constrVparamss nestedMap refOfDef)
194
263
195
264
// Methods to add to a case class C[..](p1: T1, ..., pN: Tn)(moreParams)
196
265
// def isDefined = true
@@ -201,23 +270,23 @@ object desugar {
201
270
// def copy(p1: T1 = p1, ..., pN: TN = pN)(moreParams) = new C[...](p1, ..., pN)(moreParams)
202
271
val caseClassMeths =
203
272
if (mods is Case ) {
204
- val caseParams = vparamss.head.toArray
205
273
def syntheticProperty (name : TermName , rhs : Tree ) =
206
274
DefDef (synthetic, name, Nil , Nil , TypeTree (), rhs)
207
275
val isDefinedMeth = syntheticProperty(nme.isDefined, Literal (Constant (true )))
208
- val productArityMeth = syntheticProperty(nme.productArity, Literal (Constant (caseParams.length )))
276
+ val productArityMeth = syntheticProperty(nme.productArity, Literal (Constant (arity )))
209
277
def selectorName (n : Int ) =
210
- if (caseParams.length == 1 ) nme.get else nme.selectorName(n)
211
- 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
212
281
syntheticProperty(selectorName(i), Select (This (EmptyTypeName ), caseParams(i).name))
213
282
val copyMeths =
214
283
if (mods is Abstract ) Nil
215
284
else {
216
- val copyFirstParams = vparamss .head.map(vparam =>
285
+ val copyFirstParams = derivedVparamss .head.map(vparam =>
217
286
cpy.ValDef (vparam, vparam.mods, vparam.name, vparam.tpt, refOfDef(vparam)))
218
- val copyRestParamss = vparamss .tail.nestedMap(vparam =>
287
+ val copyRestParamss = derivedVparamss .tail.nestedMap(vparam =>
219
288
cpy.ValDef (vparam, vparam.mods, vparam.name, vparam.tpt, EmptyTree ))
220
- DefDef (synthetic, nme.copy, tparams , copyFirstParams :: copyRestParamss, TypeTree (), creatorExpr) :: Nil
289
+ DefDef (synthetic, nme.copy, derivedTparams , copyFirstParams :: copyRestParamss, TypeTree (), creatorExpr) :: Nil
221
290
}
222
291
copyMeths ::: isDefinedMeth :: productArityMeth :: productElemMeths.toList
223
292
}
@@ -226,15 +295,14 @@ object desugar {
226
295
def anyRef = ref(defn.AnyRefAlias .typeRef)
227
296
def productConstr (n : Int ) = {
228
297
val tycon = ref(defn.ProductNClass (n).typeRef)
229
- val targs = vparamss .head map (_.tpt)
298
+ val targs = constrVparamss .head map (_.tpt)
230
299
AppliedTypeTree (tycon, targs)
231
300
}
232
301
233
302
// Case classes get a ProductN parent
234
303
var parents1 = parents
235
- val n = vparamss.head.length
236
- if ((mods is Case ) && 2 <= n && n <= Definitions .MaxTupleArity )
237
- parents1 = parents1 :+ productConstr(n)
304
+ if ((mods is Case ) && 2 <= arity && arity <= Definitions .MaxTupleArity )
305
+ parents1 = parents1 :+ productConstr(arity)
238
306
239
307
// The thicket which is the desugared version of the companion object
240
308
// synthetic object C extends parentTpt { defs }
@@ -256,17 +324,18 @@ object desugar {
256
324
val companions =
257
325
if (mods is Case ) {
258
326
val parent =
259
- if (tparams .nonEmpty) anyRef
260
- 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))
261
329
val applyMeths =
262
330
if (mods is Abstract ) Nil
263
- else DefDef (
331
+ else
332
+ DefDef (
264
333
synthetic | (constr1.mods.flags & DefaultParameterized ), nme.apply,
265
- tparams, vparamss , TypeTree (), creatorExpr) :: Nil
334
+ derivedTparams, derivedVparamss , TypeTree (), creatorExpr) :: Nil
266
335
val unapplyMeth = {
267
336
val unapplyParam = makeSyntheticParameter(tpt = classTypeRef)
268
- val unapplyRHS = if (n == 0 ) Literal (Constant (true )) else Ident (unapplyParam.name)
269
- 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)
270
339
}
271
340
companionDefs(parent, applyMeths ::: unapplyMeth :: defaultGetters)
272
341
}
@@ -283,19 +352,40 @@ object desugar {
283
352
ctx.error(" implicit classes may not be toplevel" , cdef.pos)
284
353
if (mods is Case )
285
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.
286
358
DefDef (Modifiers (Synthetic | Implicit ), name.toTermName,
287
- tparams, vparamss , classTypeRef, creatorExpr) :: Nil
359
+ constrTparams, constrVparamss , classTypeRef, creatorExpr) :: Nil
288
360
}
289
361
else Nil
290
362
291
- val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt
292
- val self1 =
363
+ val self1 = {
364
+ val selfType = if (self.tpt.isEmpty) classTypeRef else self.tpt
293
365
if (self.isEmpty) self
294
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
+ }
295
388
296
- val cdef1 = cpy.TypeDef (cdef, mods, name,
297
- cpy.Template (impl, constr, parents1, self1,
298
- constr1.tparams ::: constr1.vparamss.flatten ::: body ::: caseClassMeths))
299
389
flatTree(cdef1 :: companions ::: implicitWrappers)
300
390
}
301
391
0 commit comments