Skip to content

Commit fcd99c5

Browse files
committed
Generate shallower ASTs in pattern translation
Given: ``` $ cat sandbox/test.scala class Test { import reflect.runtime.universe._ (null: Tree) match { case Literal(Constant(value)) => } } ``` Emit: ``` $ qscalac -Xprint:patmat sandbox/test.scala [[syntax trees at end of patmat]] // test.scala package <empty> { class Test extends scala.AnyRef { def <init>(): Test = { Test.super.<init>(); () }; { case <synthetic> val x1: reflect.runtime.universe.Tree = (null: reflect.runtime.universe.Tree); case11(){ if (x1.ne(null).unary_!) case12(); <synthetic> val o16: Option[reflect.runtime.universe.Literal] = scala.reflect.runtime.`package`.universe.LiteralTag.unapply(x1); if (o16.isEmpty) case12(); <synthetic> val p3: reflect.runtime.universe.Literal = o16.get; if (p3.ne(null).unary_!) case12(); <synthetic> val o15: Option[reflect.runtime.universe.Constant] = scala.reflect.runtime.`package`.universe.Literal.unapply(p3); if (o15.isEmpty) case12(); <synthetic> val p5: reflect.runtime.universe.Constant = o15.get; if (p5.ne(null).unary_!) case12(); <synthetic> val o14: Option[reflect.runtime.universe.Constant] = scala.reflect.runtime.`package`.universe.ConstantTag.unapply(p5); if (o14.isEmpty) case12(); <synthetic> val p7: reflect.runtime.universe.Constant = o14.get; if (p7.ne(null).unary_!) case12(); <synthetic> val o13: Option[Any] = scala.reflect.runtime.`package`.universe.Constant.unapply(p7); if (o13.isEmpty) case12(); matchEnd10(()) }; case12(){ matchEnd10(throw new MatchError(x1)) }; matchEnd10(x: Unit){ x } } } } ``` Rather than: ``` $ scalac-ref 2.13.x -Xprint:patmat sandbox/test.scala [[syntax trees at end of patmat]] // test.scala package <empty> { class Test extends scala.AnyRef { def <init>(): Test = { Test.super.<init>(); () }; { case <synthetic> val x1: reflect.runtime.universe.Tree = (null: reflect.runtime.universe.Tree); case11(){ if (x1.ne(null)) { <synthetic> val o16: Option[reflect.runtime.universe.Literal] = scala.reflect.runtime.`package`.universe.LiteralTag.unapply(x1); if (o16.isEmpty.unary_!) { <synthetic> val p3: reflect.runtime.universe.Literal = o16.get; if (p3.ne(null)) { <synthetic> val o15: Option[reflect.runtime.universe.Constant] = scala.reflect.runtime.`package`.universe.Literal.unapply(p3); if (o15.isEmpty.unary_!) { <synthetic> val p5: reflect.runtime.universe.Constant = o15.get; if (p5.ne(null)) { <synthetic> val o14: Option[reflect.runtime.universe.Constant] = scala.reflect.runtime.`package`.universe.ConstantTag.unapply(p5); if (o14.isEmpty.unary_!) { <synthetic> val p7: reflect.runtime.universe.Constant = o14.get; if (p7.ne(null)) { <synthetic> val o13: Option[Any] = scala.reflect.runtime.`package`.universe.Constant.unapply(p7); if (o13.isEmpty.unary_!) matchEnd10(()) else case12() } else case12() } else case12() } else case12() } else case12() } else case12() } else case12() } else case12() }; case12(){ matchEnd10(throw new MatchError(x1)) }; matchEnd10(x: Unit){ x } } } } ```
1 parent b5029ab commit fcd99c5

File tree

8 files changed

+133
-84
lines changed

8 files changed

+133
-84
lines changed

src/compiler/scala/tools/nsc/ast/TreeDSL.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,11 @@ trait TreeDSL {
136136

137137
def NEW(tpt: Tree, args: Tree*): Tree = New(tpt, List(args.toList))
138138

139-
def NOT(tree: Tree) = Select(tree, Boolean_not)
139+
def NOT(tree: Tree) = tree match {
140+
case Select(qual, _) if tree.symbol eq Boolean_not => qual
141+
case _ => Select(tree, Boolean_not)
142+
}
143+
140144
def AND(guards: Tree*) = if (guards.isEmpty) EmptyTree else guards reduceLeft gen.mkAnd
141145

142146
def IF(tree: Tree) = new IfStart(tree, EmptyTree)

src/compiler/scala/tools/nsc/transform/patmat/MatchCodeGen.scala

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -204,22 +204,37 @@ trait MatchCodeGen extends Interface {
204204
// res: T
205205
// returns MatchMonad[T]
206206
def one(res: Tree): Tree = matchEnd APPLY (res) // a jump to a case label is special-cased in typedApply
207-
protected def zero: Tree = nextCase APPLY ()
207+
protected final def zero: Tree = nextCase APPLY ()
208+
override def ifThenElseZero(c: Tree, thenp: Tree): Tree = {
209+
thenp match {
210+
case Block(stats, expr) =>
211+
Block(If(NOT(c), zero, EmptyTree) :: stats, expr)
212+
case _ =>
213+
Block(If(NOT(c), zero, EmptyTree) :: Nil, thenp)
214+
}
215+
}
208216

209217
// prev: MatchMonad[T]
210218
// b: T
211219
// next: MatchMonad[U]
212220
// returns MatchMonad[U]
213221
def flatMap(prev: Tree, b: Symbol, next: Tree): Tree = {
214222
val prevSym = freshSym(prev.pos, prev.tpe, "o")
215-
BLOCK(
216-
ValDef(prevSym, prev),
217-
// must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
223+
val nextTree = // must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
218224
ifThenElseZero(
219225
NOT(prevSym DOT vpmName.isEmpty),
220226
Substitution(b, prevSym DOT vpmName.get)(next)
221227
)
222-
)
228+
nextTree match {
229+
case Block(stats, expr) =>
230+
Block((ValDef(prevSym, prev) :: stats), expr)
231+
case _ =>
232+
BLOCK(
233+
ValDef(prevSym, prev),
234+
// must be isEmpty and get as we don't control the target of the call (prev is an extractor call)
235+
nextTree
236+
)
237+
}
223238
}
224239

225240
// cond: Boolean
@@ -230,9 +245,14 @@ trait MatchCodeGen extends Interface {
230245
def flatMapCond(cond: Tree, res: Tree, nextBinder: Symbol, next: Tree): Tree = {
231246
val rest = (
232247
// only emit a local val for `nextBinder` if it's actually referenced in `next`
233-
if (next.exists(_.symbol eq nextBinder))
234-
Block(ValDef(nextBinder, res) :: Nil, next)
235-
else next
248+
if (next.exists(_.symbol eq nextBinder)) {
249+
next match {
250+
case Block(stats, expr) =>
251+
Block(ValDef(nextBinder, res) :: stats, expr)
252+
case _ =>
253+
Block(ValDef(nextBinder, res) :: Nil, next)
254+
}
255+
} else next
236256
)
237257
ifThenElseZero(cond, rest)
238258
}

src/compiler/scala/tools/nsc/transform/patmat/MatchTreeMaking.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,13 @@ trait MatchTreeMaking extends MatchCodeGen with Debugging {
194194
else {
195195
// only store binders actually used
196196
val (subPatBindersStored, subPatRefsStored) = stored.filter{case (b, _) => usedBinders(b)}.unzip
197-
Block(map2(subPatBindersStored.toList, subPatRefsStored.toList)(ValDef(_, _)), in)
197+
val bindings = map2(subPatBindersStored.toList, subPatRefsStored.toList)(ValDef(_, _))
198+
in match {
199+
case Block(stats, expr) =>
200+
Block(bindings ::: stats, expr)
201+
case _ =>
202+
Block(bindings, in)
203+
}
198204
}
199205
}
200206
}

src/partest-extras/scala/tools/partest/ASMConverters.scala

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,14 @@ object ASMConverters {
8181
final override def toString() = {
8282
val printOpcode = opcode != -1
8383
productPrefix + (
84-
if (printOpcode) Iterator(opcodeToString(opcode)) ++ productIterator.drop(1)
85-
else productIterator
84+
if (printOpcode) Iterator(opcodeToString(opcode)) ++ productIterator.drop(1).map(quoteString)
85+
else productIterator.map(quoteString)
8686
).mkString("(", ", ", ")")
8787
}
88+
private def quoteString(a: Any): Any = a match {
89+
case s: String => "\"" + s + "\""
90+
case x => x
91+
}
8892
}
8993

9094
case class Method(instructions: List[Instruction], handlers: List[ExceptionHandler], localVars: List[LocalVariable])

test/files/run/macroPlugins-namerHooks.check

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,12 @@ enterStat(super.<init>())
3838
enterSym(case <synthetic> val x1: Int = x$1)
3939
enterStat(case <synthetic> val x1: Int = x$1)
4040
enterSym(case <synthetic> val x1: Any = x$1)
41-
enterSym(case5(){ if (x1.isInstanceOf[C]) matchEnd4(true) else case6() })
41+
enterSym(case5(){ if (x1.isInstanceOf[C].unary_!) case6(); matchEnd4(true) })
4242
enterSym(case6(){ matchEnd4(false) })
4343
enterStat(case <synthetic> val x1: Any = x$1)
44-
enterStat(case5(){ if (x1.isInstanceOf[C]) matchEnd4(true) else case6() })
44+
enterStat(case5(){ if (x1.isInstanceOf[C].unary_!) case6(); matchEnd4(true) })
4545
enterStat(case6(){ matchEnd4(false) })
46+
enterSym(if (x1.isInstanceOf[C].unary_!) case6())
47+
enterStat(if (x1.isInstanceOf[C].unary_!) case6())
48+
enterSym(case6())
49+
enterStat(case6())

test/files/run/sd187.check

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,43 @@
1010
[205]<synthetic> var x3: [205]String = [205][205][205]null.asInstanceOf[[205]String];
1111
[205]{
1212
[205]case <synthetic> val x1: [205]Any = [205]x;
13-
[205]case8(){
14-
[313]if ([313][313]x1.isInstanceOf[[313]Option[_]])
15-
[325][325]matchEnd7([325]())
16-
else
17-
[313][313]case9()
13+
[205]case8()[313]{
14+
[313]if ([313][313][313]x1.isInstanceOf[[313]Option[_]].unary_!)
15+
[313]{
16+
[313][313]case9();
17+
[313]()
18+
};
19+
[325][325]matchEnd7([325]())
1820
};
19-
[205]case9(){
20-
[412]if ([412][412]x1.isInstanceOf[[412]String])
21+
[205]case9()[412]{
22+
[412]if ([412][412][412]x1.isInstanceOf[[412]String].unary_!)
2123
[412]{
22-
[412][412]rc6 = [412]true;
23-
[412][412]x3 = [412]([412][412]x1.asInstanceOf[[412]String]: [412]String);
24-
[412]if ([427][427]x3.==([430]"4"))
25-
[512][512]matchEnd7([512][512]x3.hashCode())
26-
else
27-
[412][412]case10()
28-
}
29-
else
30-
[412][412]case10()
24+
[412][412]case10();
25+
[412]()
26+
};
27+
[412][412]rc6 = [412]true;
28+
[412][412]x3 = [412]([412][412]x1.asInstanceOf[[412]String]: [412]String);
29+
[412]{
30+
[412]if ([412][427][427]x3.==([430]"4").unary_!)
31+
[412]{
32+
[412][412]case10();
33+
[412]()
34+
};
35+
[512][512]matchEnd7([512][512]x3.hashCode())
36+
}
3137
};
32-
[205]case10(){
33-
[612]if ([612][612]rc6.&&([627][627]x3.==([630]"6")))
34-
[712][712]matchEnd7([712][712]x3.hashCode())
35-
else
36-
[612][612]case11()
38+
[205]case10()[612]{
39+
[612]if ([612]rc6.unary_!)
40+
[612]{
41+
[612][612]case11();
42+
[612]()
43+
};
44+
[612]if ([612][627][627]x3.==([630]"6").unary_!)
45+
[612]{
46+
[612][612]case11();
47+
[612]()
48+
};
49+
[712][712]matchEnd7([712][712]x3.hashCode())
3750
};
3851
[205]case11(){
3952
[205][205]matchEnd7([205]throw [205][205][205]new [205]MatchError([205]x1))
@@ -45,23 +58,21 @@
4558
};
4659
[1007]def extractor([1017]x: [1020]<type: [1020]scala.Any>): [1007]Any = [1027]{
4760
[1027]case <synthetic> val x1: [1027]Any = [1027]x;
48-
[1027]case6(){
49-
[1120]if ([1120][1120]x1.isInstanceOf[[1120]Product2[T1,T2]])
61+
[1027]case6()[1120]{
62+
[1120]if ([1120][1120][1120]x1.isInstanceOf[[1120]Product2[T1,T2]].unary_!)
5063
[1120]{
51-
[1120]<synthetic> val x2: [1120]Product2[T1,T2] = [1120]([1120][1120]x1.asInstanceOf[[1120]Product2[T1,T2]]: [1120]Product2[T1,T2]);
52-
[1112]{
53-
[1112]<synthetic> val o8: [1112]Option[Product2[T1,T2]] = [1112][1112][1112]scala.Product2.unapply[[1112]T1, [1112]T2]([1112]x2);
54-
[1112]if ([1112]o8.isEmpty.unary_!)
55-
[1112]{
56-
[1121]val a: [1121]Any = [1121]o8.get._1;
57-
[1210][1210]matchEnd5([1210]a)
58-
}
59-
else
60-
[1112][1112]case7()
61-
}
62-
}
63-
else
64-
[1120][1120]case7()
64+
[1120][1120]case7();
65+
[1120]()
66+
};
67+
[1120]<synthetic> val x2: [1120]Product2[T1,T2] = [1120]([1120][1120]x1.asInstanceOf[[1120]Product2[T1,T2]]: [1120]Product2[T1,T2]);
68+
[1112]<synthetic> val o8: [1112]Option[Product2[T1,T2]] = [1112][1112][1112]scala.Product2.unapply[[1112]T1, [1112]T2]([1112]x2);
69+
[1112]if ([1112]o8.isEmpty)
70+
[1112]{
71+
[1112][1112]case7();
72+
[1112]()
73+
};
74+
[1121]val a: [1121]Any = [1121]o8.get._1;
75+
[1210][1210]matchEnd5([1210]a)
6576
};
6677
[1027]case7(){
6778
[1027][1027]matchEnd5([1027]throw [1027][1027][1027]new [1027]MatchError([1027]x1))
@@ -75,17 +86,19 @@
7586
} catch {
7687
[1505]case [1505](ex6 @ [1505]_) => [1505]{
7788
[1812]<synthetic> val x4: [1812]Throwable = [1812]ex6;
78-
[1505]case9(){
79-
[1812]if ([1812][1812]x4.ne([1812]null))
89+
[1505]case9()[1812]{
90+
[1812]if ([1812][1812][1812]x4.ne([1812]null).unary_!)
91+
[1812]{
92+
[1812][1812]case10();
93+
[1812]()
94+
};
95+
[1812]<synthetic> val x5: [1812]Throwable = [1812]x4;
96+
[1812]if ([1812][1915][1915][1912]"".isEmpty().unary_!)
8097
[1812]{
81-
[1812]<synthetic> val x5: [1812]Throwable = [1812]x4;
82-
[1812]if ([1915][1915][1912]"".isEmpty())
83-
[2014][2014]matchEnd8([2014][2014]x5.toString())
84-
else
85-
[1812][1812]case10()
86-
}
87-
else
88-
[1812][1812]case10()
98+
[1812][1812]case10();
99+
[1812]()
100+
};
101+
[2014][2014]matchEnd8([2014][2014]x5.toString())
89102
};
90103
[1505]case10(){
91104
[1505][1505]matchEnd8([1505]throw [1505]ex6)

test/files/run/t6288.check

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@
1010
[64]case <synthetic> val x1: [64]String = [64]"";
1111
[64]case5()[84]{
1212
[84]<synthetic> val o7: [84]Option[Int] = [84][84]Case3.unapply([84]x1);
13-
[84]if ([84]o7.isEmpty.unary_!)
14-
[97][97]matchEnd4([97]())
15-
else
16-
[84][84]case6()
13+
[84]if ([84]o7.isEmpty)
14+
[84][84]case6();
15+
[97][97]matchEnd4([97]())
1716
};
1817
[64]case6(){
1918
[64][64]matchEnd4([64]throw [64][64][64]new [64]MatchError([64]x1))
@@ -33,10 +32,11 @@
3332
[175]case <synthetic> val x1: [175]String = [175]"";
3433
[175]case5()[195]{
3534
[195]<synthetic> val o7: [195]Option[List[Int]] = [195][195]Case4.unapplySeq([195]x1);
36-
[195]if ([195][195]o7.isEmpty.unary_!.&&([195][195][195][195]o7.get.!=([195]null).&&([195][195][195][195]o7.get.lengthCompare([195]1).==([195]0))))
37-
[208][208]matchEnd4([208]())
38-
else
39-
[195][195]case6()
35+
[195]if ([195]o7.isEmpty)
36+
[195][195]case6();
37+
[195]if ([195][195][195][195][195]o7.get.!=([195]null).&&([195][195][195][195]o7.get.lengthCompare([195]1).==([195]0)).unary_!)
38+
[195][195]case6();
39+
[208][208]matchEnd4([208]())
4040
};
4141
[175]case6(){
4242
[175][175]matchEnd4([175]throw [175][175][175]new [175]MatchError([175]x1))
@@ -56,10 +56,11 @@
5656
[273]case <synthetic> val x1: [273]String = [273]"";
5757
[273]case5()[293]{
5858
[293]<synthetic> val o7: [293]Option[List[Int]] = [293][293]Case4.unapplySeq([293]x1);
59-
[293]if ([293][293]o7.isEmpty.unary_!.&&([293][293][293][293]o7.get.!=([293]null).&&([293][293][293][293]o7.get.lengthCompare([293]0).==([293]0))))
60-
[304][304]matchEnd4([304]())
61-
else
62-
[293][293]case6()
59+
[293]if ([293]o7.isEmpty)
60+
[293][293]case6();
61+
[293]if ([293][293][293][293][293]o7.get.!=([293]null).&&([293][293][293][293]o7.get.lengthCompare([293]0).==([293]0)).unary_!)
62+
[293][293]case6();
63+
[304][304]matchEnd4([304]())
6364
};
6465
[273]case6(){
6566
[273][273]matchEnd4([273]throw [273][273][273]new [273]MatchError([273]x1))

test/junit/scala/tools/nsc/backend/jvm/BytecodeTest.scala

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,24 +79,21 @@ class BytecodeTest extends BytecodeTesting {
7979

8080
val unapplyLineNumbers = getInstructions(module, "unapply").filter(_.isInstanceOf[LineNumber])
8181
assert(unapplyLineNumbers == List(LineNumber(2, Label(0))), unapplyLineNumbers)
82-
8382
val expected = List(
8483
LineNumber(4, Label(0)),
85-
LineNumber(5, Label(5)),
86-
Jump(IFEQ, Label(20)),
84+
LineNumber(5, Label(4)),
85+
Jump(IFNE, Label(10)),
86+
Jump(GOTO, Label(19)),
8787

88-
LineNumber(6, Label(11)),
88+
LineNumber(6, Label(10)),
8989
Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
90-
Jump(GOTO, Label(33)),
91-
92-
LineNumber(5, Label(20)),
93-
Jump(GOTO, Label(24)),
90+
Jump(GOTO, Label(28)),
9491

95-
LineNumber(8, Label(24)),
92+
LineNumber(8, Label(19)),
9693
Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false),
97-
Jump(GOTO, Label(33)),
94+
Jump(GOTO, Label(28)),
9895

99-
LineNumber(10, Label(33)),
96+
LineNumber(10, Label(28)),
10097
Invoke(INVOKEVIRTUAL, "scala/Predef$", "println", "(Ljava/lang/Object;)V", false)
10198
)
10299

0 commit comments

Comments
 (0)