@@ -75,8 +75,11 @@ import StdNames.nme
7575 * Unreachable jumps will be eliminated by local dead code analysis.
7676 * After JVM is smart enough to remove next-line jumps
7777 *
78- * Note that Label DefDefs can be only nested in Block, otherwise no one would
79- * be able to call them Other DefDefs are eliminated
78+ * Note that his phase Ychecking this phase required softening scoping rules
79+ * as it intentionally allowed to break scoping rules inside methods for labels.
80+ * This is modified by setting `labelsReordered` flag in Phases.
81+ *
82+ * @author Dmitry Petrashko
8083 */
8184class LabelDefs extends MiniPhaseTransform {
8285 def phaseName : String = " labelDef"
@@ -90,76 +93,24 @@ class LabelDefs extends MiniPhaseTransform {
9093 else {
9194 collectLabelDefs.clear
9295 val newRhs = collectLabelDefs.transform(tree.rhs)
93- val labelCalls = collectLabelDefs.labelCalls
94- var entryPoints = collectLabelDefs.parentLabelCalls
9596 var labelDefs = collectLabelDefs.labelDefs
96- var callCounts = collectLabelDefs.callCounts
97-
98- // make sure that for every label there's a single location it should return and single entry point
99- // if theres already a location that it returns to that's a failure
100- val disallowed = new mutable.HashMap [Symbol , Tree ]()
101- queue.sizeHint(labelCalls.size + entryPoints.size)
10297
10398 def putLabelDefsNearCallees = new TreeMap () {
10499
105100 override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = {
106101 tree match {
107- case t : Apply if (entryPoints.contains(t)) =>
108- entryPoints = entryPoints - t
109- labelLevel = labelLevel + 1
110- val r = Block (moveLabels(t), t)
111- labelLevel = labelLevel - 1
112- if (labelLevel == 0 ) beingAppended.clear()
113- r
114- case _ => if (entryPoints.nonEmpty && labelDefs.nonEmpty) super .transform(tree) else tree
115- }
102+ case t : Apply if labelDefs.contains(t.symbol) =>
103+ val labelDef = labelDefs(t.symbol)
104+ labelDefs -= t.symbol
116105
117- }
118- }
106+ val labelDef2 = transform(labelDef)
107+ Block (labelDef2 :: Nil , t)
119108
120- def moveLabels (entryPoint : Apply ): List [Tree ] = {
121- val entrySym = entryPoint.symbol
122- if ((entrySym is Flags .Label ) && labelDefs.contains(entrySym)) {
123- val visitedNow = new mutable.HashMap [Symbol , Tree ]()
124- val treesToAppend = new ArrayBuffer [Tree ]() // order matters. parents should go first
125- treesToAppend += labelDefs(entrySym)
126- queue.clear()
127-
128- var visited = 0
129- queue += entryPoint
130- while (visited < queue.size) {
131- val owningLabelDefSym = queue(visited).symbol
132- for (call <- labelCalls(owningLabelDefSym)) {
133- val callSym = call.symbol
134- if (! beingAppended.contains(callSym)) {
135- if (disallowed.contains(callSym)) {
136- val oldCall = disallowed(callSym)
137- ctx.error(s " Multiple return locations for Label $oldCall and $call" , callSym.pos)
138- } else {
139- if ((! visitedNow.contains(callSym)) && labelDefs.contains(callSym)) {
140- val defTree = labelDefs(callSym)
141- visitedNow.put(callSym, defTree)
142- val callCount = callCounts(callSym)
143- if (callCount > 1 ) {
144- if (! treesToAppend.contains(defTree)) {
145- treesToAppend += defTree
146- queue += call
147-
148- }
149- } else if (entryPoint.symbol ne callSym) entryPoints += call
150- }
151- }
152- }
153- }
154-
155- visited += 1
109+ case _ => if (labelDefs.nonEmpty) super .transform(tree) else tree
156110 }
157- beingAppended ++= treesToAppend.map(_.symbol)
158- treesToAppend.toList.map(putLabelDefsNearCallees.transform)
159- } else Nil
111+ }
160112 }
161113
162-
163114 val res = cpy.DefDef (tree)(rhs = putLabelDefsNearCallees.transform(newRhs))
164115
165116 res
@@ -168,22 +119,11 @@ class LabelDefs extends MiniPhaseTransform {
168119
169120 object collectLabelDefs extends TreeMap () {
170121
171- // label calls from this DefDef
172- var parentLabelCalls : mutable.Set [Tree ] = new mutable.HashSet [Tree ]()
173- var callCounts : mutable.Map [Symbol , Int ] = new mutable.HashMap [Symbol , Int ]().withDefaultValue(0 )
174-
175- def shouldMoveLabel = true
176-
177122 // labelSymbol -> Defining tree
178123 val labelDefs = new mutable.HashMap [Symbol , Tree ]()
179- // owner -> all calls by this owner
180- val labelCalls = new mutable.HashMap [Symbol , mutable.Set [Tree ]]()
181- var owner : Symbol = null
182124
183125 def clear = {
184- parentLabelCalls.clear()
185126 labelDefs.clear()
186- labelCalls.clear()
187127 }
188128
189129 override def transform (tree : tpd.Tree )(implicit ctx : Context ): tpd.Tree = tree match {
@@ -196,30 +136,14 @@ class LabelDefs extends MiniPhaseTransform {
196136 }
197137 case t : DefDef =>
198138 assert(t.symbol is Flags .Label )
199-
200- val st = parentLabelCalls
201- parentLabelCalls = new mutable.HashSet [Tree ]()
202- val symt = owner
203- owner = t.symbol
204-
205139 val r = super .transform(tree)
206-
207- owner = symt
208- labelCalls(r.symbol) = parentLabelCalls
209- parentLabelCalls = st
210-
211- if (shouldMoveLabel) {
212- labelDefs(r.symbol) = r
213- EmptyTree
214- } else r
140+ labelDefs(r.symbol) = r
141+ EmptyTree
215142 case t : Apply if t.symbol is Flags .Label =>
216143 val sym = t.symbol
217- parentLabelCalls = parentLabelCalls + t
218- if (owner != sym) callCounts(sym) = callCounts(sym) + 1
219144 super .transform(tree)
220145 case _ =>
221146 super .transform(tree)
222-
223147 }
224148 }
225149}
0 commit comments