@@ -10,7 +10,7 @@ import BCodeHelpers.InvokeStyle
10
10
11
11
import dotty .tools .dotc .ast .tpd
12
12
import dotty .tools .dotc .CompilationUnit
13
- import dotty .tools .dotc .core .Constants ._
13
+ import dotty .tools .dotc .core .Constants , Constants ._
14
14
import dotty .tools .dotc .core .Decorators ._
15
15
import dotty .tools .dotc .core .Flags .{Label => LabelFlag , _ }
16
16
import dotty .tools .dotc .core .Types ._
@@ -72,50 +72,63 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
72
72
73
73
private def transformStringMatchLabelled (tree : Labeled ): Tree =
74
74
import dotty .tools .dotc .core .{Flags => flg }
75
- // report.echo(i"transforming $tree")
76
75
def extract (tree : Labeled ) =
77
76
var inits : List [tpd.Tree ] = Nil
78
- var litBuilder = mutable.ArrayBuilder .ofRef[(Literal , Literal )]
77
+ var litBuilder = mutable.ArrayBuilder .ofRef[(Literal , ( Tree , Tree ) => Tree )]
79
78
var caseBuilder = mutable.ListBuffer .empty[CaseDef ]
80
- var selector : Symbol = null
81
- var default : CaseDef = null
79
+ var selector : Ident = null
80
+ // var defaultBody: Tree = null
81
+ var hasDefault : Boolean = false
82
82
def extractMatch (tree : Match ) =
83
- selector = tree.selector.symbol
83
+ var hasNull : Boolean = false
84
+ selector = tree.selector.asInstanceOf [Ident ]
85
+ def compareLit (str : Literal , idx : Literal )(ordinalRef : Tree , acc : Tree ) =
86
+ If (str.select(nme.equals_).appliedTo(selector), Assign (ordinalRef, idx), acc)
87
+ def compareNull (idx : Literal )(ordinalRef : Tree , acc : Tree ) =
88
+ If (tpd.nullLiteral.select(nme.eq).appliedTo(selector), Assign (ordinalRef, idx), acc)
89
+ def addLit (lit : Literal , idx : Literal ) =
90
+ if lit.const.tag == Constants .NullTag then
91
+ if (! hasNull)
92
+ hasNull = true
93
+ litBuilder += ((lit, compareNull(idx)))
94
+ else
95
+ litBuilder += ((lit, compareLit(lit, idx)))
84
96
var idx = 0
85
- val it = tree.cases.iterator
97
+ var it = tree.cases.iterator
86
98
while it.hasNext do
87
99
val caseDef = it.next
88
100
caseDef.pat match
89
101
case lit : Literal =>
90
102
val ord = Literal (Constant (idx))
91
- litBuilder += (( lit, ord) )
103
+ addLit( lit, ord)
92
104
caseBuilder += CaseDef (ord, EmptyTree , caseDef.body)
93
105
idx += 1
94
106
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) =>
107
+ assert(! hasDefault, s " multiple default targets in a Match node, at ${tree.span}" )
108
+ hasDefault = true
109
+ caseBuilder += CaseDef (Underscore (defn.IntType ), EmptyTree , caseDef.body)
110
+ case a @ Alternative (alts) =>
98
111
val indices = alts.indices
99
112
val ords = indices.map(i => Literal (Constant (i + idx)))
100
113
alts.lazyZip(ords) foreach {
101
- case pair @ ( _ : Literal , _ ) =>
102
- litBuilder += pair. asInstanceOf [( Literal , Literal )]
114
+ case ( lit : Literal , ord ) =>
115
+ addLit(lit, ord)
103
116
case _ =>
104
117
abort(s " Invalid alternative in alternative pattern in Match node: $tree at: ${tree.span}" )
105
118
}
106
119
caseBuilder += CaseDef (Alternative (ords.toList), EmptyTree , caseDef.body)
107
120
idx += indices.size
108
121
case _ =>
109
122
end while
110
- if default ne null then
111
- caseBuilder += default
112
123
end extractMatch
124
+
113
125
tree.expr match
114
126
case Block (stats, tree : Match ) =>
115
127
inits = stats
116
128
extractMatch(tree)
117
- case tree : Match => extractMatch(tree)
118
- (inits, ref(selector), litBuilder.result, caseBuilder.toList)
129
+ case tree : Match =>
130
+ extractMatch(tree)
131
+ (inits, selector, litBuilder.result, caseBuilder.toList)
119
132
end extract
120
133
val (inits, selectorRef, lits, ordinalCases) = extract(tree)
121
134
val labelOwner = tree.bind.symbol.owner
@@ -131,34 +144,17 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
131
144
cond = selectorRef.select(nme.eq).appliedTo(tpd.nullLiteral),
132
145
thenp = Literal (Constant (0 )),
133
146
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
- })
147
+ val hashCases = lits.groupMap(_._1.const.value.## )(_._2).toList.sortBy(_._1).map((hash, tests) =>
148
+ CaseDef (Literal (Constant (hash)), EmptyTree ,
149
+ Return (tests.toList.foldRight(tpd.unitLiteral: Tree )(_(ordinalRef, _)), ordinalLabel)
150
+ )
142
151
) ::: CaseDef (Underscore (defn.IntType ), EmptyTree , Return (tpd.unitLiteral, ordinalLabel)) :: Nil
143
- val hashBlock = Labeled (Bind (ordinalLabel, EmptyTree ), Block (
152
+ val hashMatch = Labeled (Bind (ordinalLabel, EmptyTree ), Block (
144
153
hashDef :: Nil ,
145
154
Match (ref(hashSym), hashCases)
146
155
))
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
156
+ val ordinalMatch = Match (ref(ordinalSym), ordinalCases)
157
+ Labeled (tree.bind, Block (inits ::: ordinalDef :: hashMatch :: Nil , ordinalMatch))
162
158
end transformStringMatchLabelled
163
159
164
160
/*
@@ -371,20 +367,12 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
371
367
lineNumber(tree)
372
368
373
369
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
- }}
370
+ def isStringMatch (m : Match ) = m.selector.tpe.widen isRef defn.StringClass
382
371
tree match
383
- case Block (stats , expr) =>
384
- ( expr :: stats).exists {
372
+ case Block (_ , expr) =>
373
+ expr match
385
374
case m : Match => isStringMatch(m)
386
375
case _ => false
387
- }
388
376
case m : Match => isStringMatch(m)
389
377
case _ => false
390
378
end isStringMatchBlock
@@ -412,7 +400,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
412
400
generatedType = genLoadIf(t, expectedType)
413
401
414
402
case t @ Labeled (label, expr) if (label.name.is(PatMatResultName ) || label.name.is(PatMatAltsName )) && isStringMatchBlock(expr) =>
415
- genLoad(transformStringMatchLabelled(t))
403
+ // report.echo(i"< $t")
404
+ val asIntMatch = transformStringMatchLabelled(t)
405
+ report.echo(i " > $asIntMatch" )
406
+ genLoad(asIntMatch)
416
407
417
408
case t @ Labeled (_, _) =>
418
409
generatedType = genLabeled(t)
0 commit comments