@@ -27,6 +27,27 @@ private[async] trait AnfTransform {
27
27
val tree1 = adjustTypeOfTranslatedPatternMatches(block, owner)
28
28
29
29
var mode : AnfMode = Anf
30
+
31
+ object trace {
32
+ private var indent = - 1
33
+
34
+ private def indentString = " " * indent
35
+
36
+ def apply [T ](args : Any )(t : => T ): T = {
37
+ def prefix = mode.toString.toLowerCase
38
+ indent += 1
39
+ def oneLine (s : Any ) = s.toString.replaceAll(""" \n""" , " \\\\ n" ).take(127 )
40
+ try {
41
+ AsyncUtils .trace(s " ${indentString}$prefix( ${oneLine(args)}) " )
42
+ val result = t
43
+ AsyncUtils .trace(s " ${indentString}= ${oneLine(result)}" )
44
+ result
45
+ } finally {
46
+ indent -= 1
47
+ }
48
+ }
49
+ }
50
+
30
51
typingTransform(tree1, owner)((tree, api) => {
31
52
def blockToList (tree : Tree ): List [Tree ] = tree match {
32
53
case Block (stats, expr) => stats :+ expr
@@ -97,8 +118,11 @@ private[async] trait AnfTransform {
97
118
val ifWithAssign = treeCopy.If (tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe )
98
119
stats :+ varDef :+ ifWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol)).setType(tree.tpe)
99
120
}
100
- case LabelDef (name, params, rhs) =>
101
- statsExprUnit
121
+ case ld @ LabelDef (name, params, rhs) =>
122
+ if (ld.symbol.info.resultType.typeSymbol == definitions.UnitClass )
123
+ statsExprUnit
124
+ else
125
+ stats :+ expr
102
126
103
127
case Match (scrut, cases) =>
104
128
// if type of match is Unit don't introduce assignment,
@@ -134,26 +158,6 @@ private[async] trait AnfTransform {
134
158
}
135
159
}
136
160
137
- object trace {
138
- private var indent = - 1
139
-
140
- private def indentString = " " * indent
141
-
142
- def apply [T ](args : Any )(t : => T ): T = {
143
- def prefix = mode.toString.toLowerCase
144
- indent += 1
145
- def oneLine (s : Any ) = s.toString.replaceAll(""" \n""" , " \\\\ n" ).take(127 )
146
- try {
147
- AsyncUtils .trace(s " ${indentString}$prefix( ${oneLine(args)}) " )
148
- val result = t
149
- AsyncUtils .trace(s " ${indentString}= ${oneLine(result)}" )
150
- result
151
- } finally {
152
- indent -= 1
153
- }
154
- }
155
- }
156
-
157
161
def defineVal (prefix : String , lhs : Tree , pos : Position ): ValDef = {
158
162
val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC ).setInfo(uncheckedBounds(lhs.tpe))
159
163
internal.valDef(sym, internal.changeOwner(lhs, api.currentOwner, sym)).setType(NoType ).setPos(pos)
@@ -219,8 +223,29 @@ private[async] trait AnfTransform {
219
223
funStats ++ argStatss.flatten.flatten :+ typedNewApply
220
224
221
225
case Block (stats, expr) =>
222
- val trees = stats.flatMap(linearize.transformToList).filterNot(isLiteralUnit) ::: linearize.transformToList(expr)
223
- eliminateMatchEndLabelParameter(trees)
226
+ val stats1 = stats.flatMap(linearize.transformToList).filterNot(isLiteralUnit)
227
+ val exprs1 = linearize.transformToList(expr)
228
+ val trees = stats1 ::: exprs1
229
+ def isMatchEndLabel (t : Tree ): Boolean = t match {
230
+ case ValDef (_, _, _, t) if isMatchEndLabel(t) => true
231
+ case ld : LabelDef if ld.name.toString.startsWith(" matchEnd" ) => true
232
+ case _ => false
233
+ }
234
+ def groupsEndingWith [T ](ts : List [T ])(f : T => Boolean ): List [List [T ]] = if (ts.isEmpty) Nil else {
235
+ ts.indexWhere(f) match {
236
+ case - 1 => List (ts)
237
+ case i =>
238
+ val (ts1, ts2) = ts.splitAt(i + 1 )
239
+ ts1 :: groupsEndingWith(ts2)(f)
240
+ }
241
+ }
242
+ val matchGroups = groupsEndingWith(trees)(isMatchEndLabel)
243
+ val trees1 = matchGroups.flatMap(eliminateMatchEndLabelParameter)
244
+ val result = trees1 flatMap {
245
+ case Block (stats, expr) => stats :+ expr
246
+ case t => t :: Nil
247
+ }
248
+ result
224
249
225
250
case ValDef (mods, name, tpt, rhs) =>
226
251
if (containsAwait(rhs)) {
@@ -260,7 +285,10 @@ private[async] trait AnfTransform {
260
285
scrutStats :+ treeCopy.Match (tree, scrutExpr, caseDefs)
261
286
262
287
case LabelDef (name, params, rhs) =>
263
- List (LabelDef (name, params, newBlock(linearize.transformToList(rhs), Literal (Constant (())))).setSymbol(tree.symbol))
288
+ if (tree.symbol.info.typeSymbol == definitions.UnitClass )
289
+ List (treeCopy.LabelDef (tree, name, params, api.typecheck(newBlock(linearize.transformToList(rhs), Literal (Constant (()))))).setSymbol(tree.symbol))
290
+ else
291
+ List (treeCopy.LabelDef (tree, name, params, api.typecheck(listToBlock(linearize.transformToList(rhs)))).setSymbol(tree.symbol))
264
292
265
293
case TypeApply (fun, targs) =>
266
294
val funStats :+ simpleFun = linearize.transformToList(fun)
@@ -274,7 +302,7 @@ private[async] trait AnfTransform {
274
302
275
303
// Replace the label parameters on `matchEnd` with use of a `matchRes` temporary variable
276
304
//
277
- // CaseDefs are translated to labels without parmeters . A terminal label, `matchEnd`, accepts
305
+ // CaseDefs are translated to labels without parameters . A terminal label, `matchEnd`, accepts
278
306
// a parameter which is the result of the match (this is regular, so even Unit-typed matches have this).
279
307
//
280
308
// For our purposes, it is easier to:
@@ -286,34 +314,71 @@ private[async] trait AnfTransform {
286
314
val caseDefToMatchResult = collection.mutable.Map [Symbol , Symbol ]()
287
315
288
316
val matchResults = collection.mutable.Buffer [Tree ]()
289
- val statsExpr0 = statsExpr.reverseMap {
290
- case ld @ LabelDef (_, param :: Nil , body) =>
317
+ def modifyLabelDef (ld : LabelDef ): (Tree , Tree ) = {
318
+ val symTab = c.universe.asInstanceOf [reflect.internal.SymbolTable ]
319
+ val param = ld.params.head
320
+ val ld2 = if (ld.params.head.tpe.typeSymbol == definitions.UnitClass ) {
321
+ // Unit typed match: eliminate the label def parameter, but don't create a matchres temp variable to
322
+ // store the result for cleaner generated code.
323
+ caseDefToMatchResult(ld.symbol) = NoSymbol
324
+ val rhs2 = substituteTrees(ld.rhs, param.symbol :: Nil , api.typecheck(literalUnit) :: Nil )
325
+ (treeCopy.LabelDef (ld, ld.name, Nil , api.typecheck(literalUnit)), rhs2)
326
+ } else {
327
+ // Otherwise, create the matchres var. We'll callers of the label def below.
328
+ // Remember: we're iterating through the statement sequence in reverse, so we'll get
329
+ // to the LabelDef and mutate `matchResults` before we'll get to its callers.
291
330
val matchResult = linearize.defineVar(name.matchRes, param.tpe, ld.pos)
292
331
matchResults += matchResult
293
332
caseDefToMatchResult(ld.symbol) = matchResult.symbol
294
- val ld2 = treeCopy.LabelDef (ld, ld.name, Nil , body.substituteSymbols(param.symbol :: Nil , matchResult.symbol :: Nil ))
295
- setInfo(ld.symbol, methodType(Nil , ld.symbol.info.resultType))
296
- ld2
333
+ val rhs2 = ld.rhs.substituteSymbols(param.symbol :: Nil , matchResult.symbol :: Nil )
334
+ (treeCopy.LabelDef (ld, ld.name, Nil , api.typecheck(literalUnit)), rhs2)
335
+ }
336
+ setInfo(ld.symbol, methodType(Nil , definitions.UnitTpe ))
337
+ ld2
338
+ }
339
+ val statsExpr0 = statsExpr.reverse.flatMap {
340
+ case ld @ LabelDef (_, param :: Nil , _) =>
341
+ val (ld1, after) = modifyLabelDef(ld)
342
+ List (after, ld1)
343
+ case a @ ValDef (mods, name, tpt, ld @ LabelDef (_, param :: Nil , _)) =>
344
+ val (ld1, after) = modifyLabelDef(ld)
345
+ List (treeCopy.ValDef (a, mods, name, tpt, after), ld1)
297
346
case t =>
298
- if (caseDefToMatchResult.isEmpty) t
299
- else typingTransform(t)((tree, api) =>
347
+ if (caseDefToMatchResult.isEmpty) t :: Nil
348
+ else typingTransform(t)((tree, api) => {
349
+ def typedPos (pos : Position )(t : Tree ): Tree =
350
+ api.typecheck(atPos(pos)(t))
300
351
tree match {
301
352
case Apply (fun, arg :: Nil ) if isLabel(fun.symbol) && caseDefToMatchResult.contains(fun.symbol) =>
302
- api.typecheck(atPos(tree.pos)(newBlock(Assign (Ident (caseDefToMatchResult(fun.symbol)), api.recur(arg)) :: Nil , treeCopy.Apply (tree, fun, Nil ))))
303
- case Block (stats, expr) =>
353
+ val temp = caseDefToMatchResult(fun.symbol)
354
+ if (temp == NoSymbol )
355
+ typedPos(tree.pos)(newBlock(api.recur(arg) :: Nil , treeCopy.Apply (tree, fun, Nil )))
356
+ else
357
+ // setType needed for LateExpansion.shadowingRefinedType test case. There seems to be an inconsistency
358
+ // in the trees after pattern matcher.
359
+ // TODO miminize the problem in patmat and fix in scalac.
360
+ typedPos(tree.pos)(newBlock(Assign (Ident (temp), api.recur(internal.setType(arg, fun.tpe.paramLists.head.head.info))) :: Nil , treeCopy.Apply (tree, fun, Nil )))
361
+ case Block (stats, expr : Apply ) if isLabel(expr.symbol) =>
304
362
api.default(tree) match {
305
- case Block (stats, Block (stats1, expr)) =>
306
- treeCopy.Block (tree, stats ::: stats1, expr)
363
+ case Block (stats0, Block (stats1, expr1)) =>
364
+ // flatten the block returned by `case Apply` above into the enclosing block for
365
+ // cleaner generated code.
366
+ treeCopy.Block (tree, stats0 ::: stats1, expr1)
307
367
case t => t
308
368
}
309
369
case _ =>
310
370
api.default(tree)
311
371
}
312
- )
372
+ }) :: Nil
313
373
}
314
374
matchResults.toList match {
315
- case Nil => statsExpr
316
- case r1 :: Nil => (r1 +: statsExpr0.reverse) :+ atPos(tree.pos)(gen.mkAttributedIdent(r1.symbol))
375
+ case _ if caseDefToMatchResult.isEmpty =>
376
+ statsExpr // return the original trees if nothing changed
377
+ case Nil =>
378
+ statsExpr0.reverse :+ literalUnit // must have been a unit-typed match, no matchRes variable to definne or refer to
379
+ case r1 :: Nil =>
380
+ // { var matchRes = _; ....; matchRes }
381
+ (r1 +: statsExpr0.reverse) :+ atPos(tree.pos)(gen.mkAttributedIdent(r1.symbol))
317
382
case _ => c.error(macroPos, " Internal error: unexpected tree encountered during ANF transform " + statsExpr); statsExpr
318
383
}
319
384
}
0 commit comments