Skip to content

Commit ef06795

Browse files
committed
WIP
1 parent 6dd8543 commit ef06795

File tree

3 files changed

+66
-60
lines changed

3 files changed

+66
-60
lines changed

compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import BCodeHelpers.InvokeStyle
1010

1111
import dotty.tools.dotc.ast.tpd
1212
import dotty.tools.dotc.CompilationUnit
13-
import dotty.tools.dotc.core.Constants._
13+
import dotty.tools.dotc.core.Constants, Constants._
1414
import dotty.tools.dotc.core.Decorators._
1515
import dotty.tools.dotc.core.Flags.{Label => LabelFlag, _}
1616
import dotty.tools.dotc.core.Types._
@@ -72,50 +72,63 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
7272

7373
private def transformStringMatchLabelled(tree: Labeled): Tree =
7474
import dotty.tools.dotc.core.{Flags => flg}
75-
// report.echo(i"transforming $tree")
7675
def extract(tree: Labeled) =
7776
var inits: List[tpd.Tree] = Nil
78-
var litBuilder = mutable.ArrayBuilder.ofRef[(Literal, Literal)]
77+
var litBuilder = mutable.ArrayBuilder.ofRef[(Literal, (Tree, Tree) => Tree)]
7978
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
8282
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)))
8496
var idx = 0
85-
val it = tree.cases.iterator
97+
var it = tree.cases.iterator
8698
while it.hasNext do
8799
val caseDef = it.next
88100
caseDef.pat match
89101
case lit: Literal =>
90102
val ord = Literal(Constant(idx))
91-
litBuilder += ((lit, ord))
103+
addLit(lit, ord)
92104
caseBuilder += CaseDef(ord, EmptyTree, caseDef.body)
93105
idx += 1
94106
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) =>
98111
val indices = alts.indices
99112
val ords = indices.map(i => Literal(Constant(i + idx)))
100113
alts.lazyZip(ords) foreach {
101-
case pair @ (_: Literal, _) =>
102-
litBuilder += pair.asInstanceOf[(Literal, Literal)]
114+
case (lit: Literal, ord) =>
115+
addLit(lit, ord)
103116
case _ =>
104117
abort(s"Invalid alternative in alternative pattern in Match node: $tree at: ${tree.span}")
105118
}
106119
caseBuilder += CaseDef(Alternative(ords.toList), EmptyTree, caseDef.body)
107120
idx += indices.size
108121
case _ =>
109122
end while
110-
if default ne null then
111-
caseBuilder += default
112123
end extractMatch
124+
113125
tree.expr match
114126
case Block(stats, tree: Match) =>
115127
inits = stats
116128
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)
119132
end extract
120133
val (inits, selectorRef, lits, ordinalCases) = extract(tree)
121134
val labelOwner = tree.bind.symbol.owner
@@ -131,34 +144,17 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
131144
cond = selectorRef.select(nme.eq).appliedTo(tpd.nullLiteral),
132145
thenp = Literal(Constant(0)),
133146
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+
)
142151
) ::: 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(
144153
hashDef :: Nil,
145154
Match(ref(hashSym), hashCases)
146155
))
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))
162158
end transformStringMatchLabelled
163159

164160
/*
@@ -371,20 +367,12 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
371367
lineNumber(tree)
372368

373369
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
382371
tree match
383-
case Block(stats, expr) =>
384-
(expr :: stats).exists {
372+
case Block(_, expr) =>
373+
expr match
385374
case m: Match => isStringMatch(m)
386375
case _ => false
387-
}
388376
case m: Match => isStringMatch(m)
389377
case _ => false
390378
end isStringMatchBlock
@@ -412,7 +400,10 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder {
412400
generatedType = genLoadIf(t, expectedType)
413401

414402
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)
416407

417408
case t @ Labeled(_, _) =>
418409
generatedType = genLabeled(t)

compiler/src/dotty/tools/dotc/config/Printers.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ object Printers {
3333
val interactiv = noPrinter
3434
val nullables = noPrinter
3535
val overload = noPrinter
36-
val patmatch = noPrinter
36+
val patmatch = default
3737
val pickling = noPrinter
3838
val quotePickling = noPrinter
3939
val plugins = noPrinter

compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -764,14 +764,26 @@ object PatternMatcher {
764764

765765
val seenInt = mutable.Set[Int]()
766766
val seenString = mutable.Set[String]()
767+
var hasNull = false
767768

768769
def isNewConst(tree: Tree) = tree match {
769770
case Literal(const) if const.isIntRange && !seenInt.contains(const.intValue) =>
770771
seenInt += const.intValue
771772
true
772-
case Literal(Constant(str: String)) if !seenString.contains(str) =>
773+
case Literal(Constant(null | _: String)) => true
774+
case _ =>
775+
false
776+
}
777+
778+
def shouldSkip(tree: Tree) = tree match {
779+
case Literal(Constant(null)) =>
780+
val res = hasNull
781+
hasNull = true
782+
res
783+
case Literal(Constant(str: String)) =>
784+
val res = seenString.contains(str)
773785
seenString += str
774-
true
786+
res
775787
case _ =>
776788
false
777789
}
@@ -786,7 +798,8 @@ object PatternMatcher {
786798
def rec(innerPlan: Plan): Boolean = innerPlan match {
787799
case SeqPlan(TestPlan(EqualTest(tree), scrut, _, ReturnPlan(`innerLabel`)), tail)
788800
if scrut === scrutinee && isNewConst(tree) =>
789-
alts += tree
801+
if !shouldSkip(tree) then
802+
alts += tree
790803
rec(tail)
791804
case ReturnPlan(`outerLabel`) =>
792805
true
@@ -806,7 +819,8 @@ object PatternMatcher {
806819
def recur(plan: Plan): List[(List[Tree], Plan)] = plan match {
807820
case SeqPlan(testPlan @ TestPlan(EqualTest(tree), scrut, _, ons), tail)
808821
if scrut === scrutinee && !canFallThrough(ons) && isNewConst(tree) =>
809-
(tree :: Nil, ons) :: recur(tail)
822+
if shouldSkip(tree) then recur(tail)
823+
else (tree :: Nil, ons) :: recur(tail)
810824
case SeqPlan(AlternativesPlan(alts, ons), tail) =>
811825
(alts, ons) :: recur(tail)
812826
case _ =>
@@ -839,8 +853,9 @@ object PatternMatcher {
839853

840854
def literal(lit: Tree): Tree =
841855
val Literal(constant) = lit
842-
if constant.tag == Constants.IntTag || constant.tag == Constants.StringTag then lit
843-
else cpy.Literal(lit)(Constant(constant.intValue))
856+
constant.tag match
857+
case Constants.IntTag | Constants.StringTag | Constants.NullTag => lit
858+
case _ => cpy.Literal(lit)(Constant(constant.intValue))
844859

845860
val caseDefs = cases.map { (alts, ons) =>
846861
val pat = alts match {

0 commit comments

Comments
 (0)