@@ -21,8 +21,11 @@ import dotty.tools.dotc.transform.SymUtils._
21
21
import dotty .tools .dotc .util .Spans ._
22
22
import dotty .tools .dotc .core .Contexts ._
23
23
import dotty .tools .dotc .core .Phases ._
24
+ import dotty .tools .dotc .core .NameKinds .{PatMatResultName , PatMatAltsName , UniqueName , PatMatStdBinderName }
24
25
import dotty .tools .dotc .report
25
26
27
+ import scala .collection .mutable
28
+
26
29
/*
27
30
*
28
31
* @author Miguel Garcia, http://lamp.epfl.ch/~magarcia/ScalaCompilerCornerReloaded/
@@ -67,6 +70,97 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
67
70
}
68
71
}
69
72
73
+ private def transformStringMatchLabelled (tree : Labeled ): Tree =
74
+ import dotty .tools .dotc .core .{Flags => flg }
75
+ // report.echo(i"transforming $tree")
76
+ def extract (tree : Labeled ) =
77
+ var inits : List [tpd.Tree ] = Nil
78
+ var litBuilder = mutable.ArrayBuilder .ofRef[(Literal , Literal )]
79
+ var caseBuilder = mutable.ListBuffer .empty[CaseDef ]
80
+ var selector : Symbol = null
81
+ var default : CaseDef = null
82
+ def extractMatch (tree : Match ) =
83
+ selector = tree.selector.symbol
84
+ var idx = 0
85
+ val it = tree.cases.iterator
86
+ while it.hasNext do
87
+ val caseDef = it.next
88
+ caseDef.pat match
89
+ case lit : Literal =>
90
+ val ord = Literal (Constant (idx))
91
+ litBuilder += ((lit, ord))
92
+ caseBuilder += CaseDef (ord, EmptyTree , caseDef.body)
93
+ idx += 1
94
+ case defaultIdent : Ident =>
95
+ assert(default eq null , s " multiple default targets in a Match node, at ${tree.span}" )
96
+ default = CaseDef (Underscore (defn.IntType ), EmptyTree , caseDef.body)
97
+ case Alternative (alts) =>
98
+ val indices = alts.indices
99
+ val ords = indices.map(i => Literal (Constant (i + idx)))
100
+ alts.lazyZip(ords) foreach {
101
+ case pair @ (_ : Literal , _) =>
102
+ litBuilder += pair.asInstanceOf [(Literal , Literal )]
103
+ case _ =>
104
+ abort(s " Invalid alternative in alternative pattern in Match node: $tree at: ${tree.span}" )
105
+ }
106
+ caseBuilder += CaseDef (Alternative (ords.toList), EmptyTree , caseDef.body)
107
+ idx += indices.size
108
+ case _ =>
109
+ end while
110
+ if default ne null then
111
+ caseBuilder += default
112
+ end extractMatch
113
+ tree.expr match
114
+ case Block (stats, tree : Match ) =>
115
+ inits = stats
116
+ extractMatch(tree)
117
+ case tree : Match => extractMatch(tree)
118
+ (inits, ref(selector), litBuilder.result, caseBuilder.toList)
119
+ end extract
120
+ val (inits, selectorRef, lits, ordinalCases) = extract(tree)
121
+ val labelOwner = tree.bind.symbol.owner
122
+ val ordinal = UniqueName .fresh(nme.ordinal)
123
+ val ordinalSym = newSymbol(labelOwner, ordinal, flg.Synthetic | flg.Local | flg.Mutable , defn.IntType )
124
+ val ordinalRef = ref(ordinalSym)
125
+ val ordinalDef = ValDef (ordinalSym, Literal (Constant (- 1 )))
126
+ val ordinalLabel =
127
+ newSymbol(labelOwner, PatMatResultName .fresh(), flg.Synthetic | flg.Label , defn.UnitType )
128
+ val hash = PatMatStdBinderName .fresh()
129
+ val hashSym = newSymbol(labelOwner, hash, flg.Synthetic | flg.Local | flg.Case , defn.IntType )
130
+ val hashDef = ValDef (hashSym, If (
131
+ cond = selectorRef.select(nme.eq).appliedTo(tpd.nullLiteral),
132
+ thenp = Literal (Constant (0 )),
133
+ elsep = selectorRef.select(nme.hashCode_).ensureApplied))
134
+ val hashCases = lits.groupBy(_._1.const.stringValue.hashCode).toList.sortBy(_._1).map((hash, pairing) =>
135
+ CaseDef (Literal (Constant (hash)), EmptyTree , {
136
+ val cases = pairing.toList.foldRight(tpd.unitLiteral: Tree ) { (p, acc) =>
137
+ val (str, idx) = p
138
+ If (str.select(nme.equals_).appliedTo(selectorRef), Assign (ordinalRef, idx), acc)
139
+ }
140
+ Return (cases, ordinalLabel)
141
+ })
142
+ ) ::: CaseDef (Underscore (defn.IntType ), EmptyTree , Return (tpd.unitLiteral, ordinalLabel)) :: Nil
143
+ val hashBlock = Labeled (Bind (ordinalLabel, EmptyTree ), Block (
144
+ hashDef :: Nil ,
145
+ Match (ref(hashSym), hashCases)
146
+ ))
147
+ val ordinalScrut = PatMatStdBinderName .fresh()
148
+ val ordinalScrutSym = newSymbol(labelOwner, ordinalScrut, flg.Synthetic | flg.Local | flg.Case , defn.IntType )
149
+ val ordinalScrutDef = ValDef (ordinalScrutSym, ref(ordinalSym))
150
+ val ordinalBlock = Labeled (tree.bind, Block (
151
+ ordinalScrutDef :: Nil ,
152
+ Match (ref(ordinalScrutSym), ordinalCases)
153
+ ))
154
+ val res = Block (
155
+ inits :::
156
+ ordinalDef ::
157
+ hashBlock :: Nil ,
158
+ ordinalBlock
159
+ )
160
+ // report.echo(i"check res: $res")
161
+ res
162
+ end transformStringMatchLabelled
163
+
70
164
/*
71
165
* Emits code that adds nothing to the operand stack.
72
166
* Two main cases: `tree` is an assignment,
@@ -276,6 +370,25 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
276
370
277
371
lineNumber(tree)
278
372
373
+ def isStringMatchBlock (tree : Tree ) =
374
+ def isStringMatch (m : Match ) = m.cases.exists { _.pat match {
375
+ case Literal (Constant (_ : String )) => true
376
+ case Alternative (alts) => alts.exists {
377
+ case Literal (Constant (_ : String )) => true
378
+ case _ => false
379
+ }
380
+ case _ => false
381
+ }}
382
+ tree match
383
+ case Block (stats, expr) =>
384
+ (expr :: stats).exists {
385
+ case m : Match => isStringMatch(m)
386
+ case _ => false
387
+ }
388
+ case m : Match => isStringMatch(m)
389
+ case _ => false
390
+ end isStringMatchBlock
391
+
279
392
tree match {
280
393
case ValDef (nme.THIS , _, _) =>
281
394
report.debuglog(" skipping trivial assign to _$this: " + tree)
@@ -298,6 +411,9 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
298
411
case t @ If (_, _, _) =>
299
412
generatedType = genLoadIf(t, expectedType)
300
413
414
+ case t @ Labeled (label, expr) if (label.name.is(PatMatResultName ) || label.name.is(PatMatAltsName )) && isStringMatchBlock(expr) =>
415
+ genLoad(transformStringMatchLabelled(t))
416
+
301
417
case t @ Labeled (_, _) =>
302
418
generatedType = genLabeled(t)
303
419
@@ -549,7 +665,6 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
549
665
550
666
private def genLabeled (tree : Labeled ): BType = tree match {
551
667
case Labeled (bind, expr) =>
552
-
553
668
val resKind = tpeTK(tree)
554
669
genLoad(expr, resKind)
555
670
markProgramPoint(programPoint(bind.symbol))
0 commit comments