@@ -27,6 +27,27 @@ private[async] trait AnfTransform {
2727 val tree1 = adjustTypeOfTranslatedPatternMatches(block, owner)
2828
2929 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+
3051 typingTransform(tree1, owner)((tree, api) => {
3152 def blockToList(tree: Tree): List[Tree] = tree match {
3253 case Block(stats, expr) => stats :+ expr
@@ -97,8 +118,11 @@ private[async] trait AnfTransform {
97118 val ifWithAssign = treeCopy.If(tree, cond, branchWithAssign(thenp), branchWithAssign(elsep)).setType(definitions.UnitTpe)
98119 stats :+ varDef :+ ifWithAssign :+ atPos(tree.pos)(gen.mkAttributedStableRef(varDef.symbol)).setType(tree.tpe)
99120 }
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
102126
103127 case Match(scrut, cases) =>
104128 // if type of match is Unit don't introduce assignment,
@@ -134,26 +158,6 @@ private[async] trait AnfTransform {
134158 }
135159 }
136160
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-
157161 def defineVal(prefix: String, lhs: Tree, pos: Position): ValDef = {
158162 val sym = api.currentOwner.newTermSymbol(name.fresh(prefix), pos, SYNTHETIC).setInfo(uncheckedBounds(lhs.tpe))
159163 internal.valDef(sym, internal.changeOwner(lhs, api.currentOwner, sym)).setType(NoType).setPos(pos)
@@ -219,8 +223,29 @@ private[async] trait AnfTransform {
219223 funStats ++ argStatss.flatten.flatten :+ typedNewApply
220224
221225 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
224249
225250 case ValDef(mods, name, tpt, rhs) =>
226251 if (containsAwait(rhs)) {
@@ -260,7 +285,10 @@ private[async] trait AnfTransform {
260285 scrutStats :+ treeCopy.Match(tree, scrutExpr, caseDefs)
261286
262287 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))
264292
265293 case TypeApply(fun, targs) =>
266294 val funStats :+ simpleFun = linearize.transformToList(fun)
@@ -274,7 +302,7 @@ private[async] trait AnfTransform {
274302
275303 // Replace the label parameters on `matchEnd` with use of a `matchRes` temporary variable
276304 //
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
278306 // a parameter which is the result of the match (this is regular, so even Unit-typed matches have this).
279307 //
280308 // For our purposes, it is easier to:
@@ -286,34 +314,71 @@ private[async] trait AnfTransform {
286314 val caseDefToMatchResult = collection.mutable.Map[Symbol, Symbol]()
287315
288316 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.
291330 val matchResult = linearize.defineVar(name.matchRes, param.tpe, ld.pos)
292331 matchResults += matchResult
293332 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)
297346 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))
300351 tree match {
301352 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) =>
304362 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)
307367 case t => t
308368 }
309369 case _ =>
310370 api.default(tree)
311371 }
312- )
372+ }) :: Nil
313373 }
314374 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))
317382 case _ => c.error(macroPos, "Internal error: unexpected tree encountered during ANF transform " + statsExpr); statsExpr
318383 }
319384 }
0 commit comments