Skip to content

Commit cb4e1b8

Browse files
committed
Fix bug in firstDiff and cleanup code
1 parent be27da0 commit cb4e1b8

File tree

3 files changed

+52
-23
lines changed

3 files changed

+52
-23
lines changed

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -584,67 +584,80 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
584584
}
585585

586586
/** The index of the first difference between lists of trees `xs` and `ys`,
587-
* where `EmptyTree`s in the second list are skipped.
587+
* where initial `EmptyTree`s in the second list are skipped.
588+
* -1 if there are no differences.
589+
*/
590+
private def firstDiffSkipInitEmptyTrees[T <: Trees.Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
591+
case x :: xs1 =>
592+
ys match {
593+
case EmptyTree :: ys1 => firstDiffSkipInitEmptyTrees(xs, ys1, n)
594+
case y :: ys1 => if (x ne y) n else firstDiff(xs1, ys1, n + 1)
595+
case nil => n
596+
}
597+
case nil =>
598+
ys match {
599+
case EmptyTree :: ys1 => firstDiffSkipInitEmptyTrees(xs, ys1, n)
600+
case y :: ys1 => n
601+
case nil => -1
602+
}
603+
}
604+
605+
/** The index of the first difference between lists of trees `xs` and `ys`
588606
* -1 if there are no differences.
589607
*/
590608
private def firstDiff[T <: Trees.Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
591609
case x :: xs1 =>
592610
ys match {
593-
case EmptyTree :: ys1 => firstDiff(xs, ys1, n)
594611
case y :: ys1 => if (x ne y) n else firstDiff(xs1, ys1, n + 1)
595612
case nil => n
596613
}
597614
case nil =>
598615
ys match {
599-
case EmptyTree :: ys1 => firstDiff(xs, ys1, n)
600616
case y :: ys1 => n
601617
case nil => -1
602618
}
603619
}
604-
private def sameSeq[T <: Trees.Tree[_]](xs: List[T], ys: List[T]): Boolean = firstDiff(xs, ys) < 0
605620

606621
val result = {
607622
var typedArgs = typedArgBuf.toList
608623
def app0 = cpy.Apply(app)(normalizedFun, typedArgs) // needs to be a `def` because typedArgs can change later
609624
val app1 =
610625
if (!success) app0.withType(UnspecifiedErrorType)
611626
else {
612-
if (!(sameSeq(args, orderedArgs) && !orderedArgs.contains(EmptyTree)) && !isJavaAnnotConstr(methRef.symbol)) {
627+
if (firstDiffSkipInitEmptyTrees(args, orderedArgs) >= 0 && !isJavaAnnotConstr(methRef.symbol)) {
613628
// need to lift arguments to maintain evaluation order in the
614629
// presence of argument reorderings.
615630
liftFun()
616-
val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse)
631+
val eqSuffixLength = firstDiffSkipInitEmptyTrees(app.args.reverse, orderedArgs.reverse)
617632
val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength)
618633

634+
// Mapping of index of each `liftable` into original args ordering
619635
var indices = ListBuffer.empty[Int]
620636
var nextDefaultParamIndex = args.size
621637
var prefixShift = 0
622638
if (liftedDefs.nonEmpty) {
623639
indices += 0
624640
prefixShift = 1
625641
}
626-
for (l <- liftable) {
627-
val pure = l match {
628-
case NamedArg(_, arg) => isPureExpr(arg)
629-
case arg => isPureExpr(arg)
630-
}
631-
632-
if (pure) { }
633-
else if (!args.contains(l)) {
634-
indices += prefixShift + nextDefaultParamIndex
635-
nextDefaultParamIndex += 1
636-
}
637-
else indices += prefixShift + args.indexOf(l)
642+
liftable.foreach {
643+
case NamedArg(_, arg) if isPureExpr(arg) =>
644+
case arg if isPureExpr(arg) =>
645+
case arg =>
646+
if (args.contains(arg)) {
647+
indices += prefixShift + args.indexOf(arg)
648+
} else {
649+
indices += prefixShift + nextDefaultParamIndex
650+
nextDefaultParamIndex += 1
651+
}
638652
}
639653

640654
typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest
641655

642-
assert(liftedDefs.size == indices.size)
643-
val newOrder = (liftedDefs zip indices).sortBy(_._2).unzip._1.toList
656+
val newOrder = (liftedDefs zip indices).sortBy(_._2).unzip._1
644657
liftedDefs = ListBuffer.empty
645658
liftedDefs ++= newOrder
646659
}
647-
if (sameSeq(typedArgs, args)) // trick to cut down on tree copying
660+
if (firstDiff(typedArgs, args) < 0) // trick to cut down on tree copying
648661
typedArgs = args.asInstanceOf[List[Tree]]
649662
assignType(app0, normalizedFun, typedArgs)
650663
}

tests/run/i2916.check

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,12 @@
5050
1
5151
3
5252
2
53+
4
54+
55+
3
56+
2
57+
4
58+
59+
1
60+
2
61+
4

tests/run/i2916.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
object Test {
22
def p(x: Int) = { println(x); x }
33
def foo(x1: Int, x2: Int, x3: Int, x4: Int = p(4), x5: Int = p(5)) = 1
4-
def traceIndented(x1: Int, x2: Int = p(2), x3: Int = p(3)) = ()
4+
def traceIndented(x1: Int, x2: Int = p(2), x3: Int = p(3), x4: Int = p(4)) = ()
5+
56
def main(args: Array[String]) = {
67
foo(p(1), p(2), p(3)) // 1 2 3 4 5
78
println()
@@ -24,7 +25,13 @@ object Test {
2425
{ println(0); Test }.foo(p(1), x3 = p(3), x4 = p(4), x2 = p(2)) // 0 1 3 4 2 5
2526
println()
2627

27-
traceIndented(p(1), x3 = p(3))
28+
traceIndented(p(1), x3 = p(3)) // 1 3 2 4
29+
println()
30+
31+
traceIndented(1, x3 = p(3)) // 3 2 4
32+
println()
33+
34+
traceIndented(p(1), x3 = 3) // 1 2 4
2835

2936
}
3037
}

0 commit comments

Comments
 (0)