Skip to content

Commit c75c4ac

Browse files
authored
Merge pull request scala#2931 from dotty-staging/fix-i2916
Fix scala#2916: Reorder parameters
2 parents 28dec7c + 6ffa593 commit c75c4ac

File tree

4 files changed

+129
-8
lines changed

4 files changed

+129
-8
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,8 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
370370
exprPurity(expr)
371371
case Block(stats, expr) =>
372372
minOf(exprPurity(expr), stats.map(statPurity))
373+
case NamedArg(_, expr) =>
374+
exprPurity(expr)
373375
case _ =>
374376
Impure
375377
}

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

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,17 @@ import NameKinds.DefaultGetterName
2424
import ProtoTypes._
2525
import EtaExpansion._
2626
import Inferencing._
27+
2728
import collection.mutable
2829
import config.Printers.{typr, unapp, overload}
2930
import TypeApplications._
31+
3032
import language.implicitConversions
3133
import reporting.diagnostic.Message
3234
import Constants.{Constant, IntTag, LongTag}
3335

36+
import scala.collection.mutable.ListBuffer
37+
3438
object Applications {
3539
import tpd._
3640

@@ -580,20 +584,17 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
580584
myNormalizedFun = liftApp(liftedDefs, myNormalizedFun)
581585
}
582586

583-
/** The index of the first difference between lists of trees `xs` and `ys`,
584-
* where `EmptyTree`s in the second list are skipped.
587+
/** The index of the first difference between lists of trees `xs` and `ys`
585588
* -1 if there are no differences.
586589
*/
587590
private def firstDiff[T <: Trees.Tree[_]](xs: List[T], ys: List[T], n: Int = 0): Int = xs match {
588591
case x :: xs1 =>
589592
ys match {
590-
case EmptyTree :: ys1 => firstDiff(xs1, ys1, n)
591593
case y :: ys1 => if (x ne y) n else firstDiff(xs1, ys1, n + 1)
592594
case nil => n
593595
}
594596
case nil =>
595597
ys match {
596-
case EmptyTree :: ys1 => firstDiff(xs, ys1, n)
597598
case y :: ys1 => n
598599
case nil => -1
599600
}
@@ -606,13 +607,33 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
606607
val app1 =
607608
if (!success) app0.withType(UnspecifiedErrorType)
608609
else {
609-
if (!sameSeq(args, orderedArgs) && !isJavaAnnotConstr(methRef.symbol)) {
610+
if (!sameSeq(args, orderedArgs.dropWhile(_ eq EmptyTree)) && !isJavaAnnotConstr(methRef.symbol)) {
610611
// need to lift arguments to maintain evaluation order in the
611612
// presence of argument reorderings.
613+
612614
liftFun()
613-
val eqSuffixLength = firstDiff(app.args.reverse, orderedArgs.reverse)
614-
val (liftable, rest) = typedArgs splitAt (typedArgs.length - eqSuffixLength)
615-
typedArgs = liftArgs(liftedDefs, methType, liftable) ++ rest
615+
616+
// lift arguments in the definition order
617+
val argDefBuf = mutable.ListBuffer.empty[Tree]
618+
typedArgs = liftArgs(argDefBuf, methType, typedArgs)
619+
620+
// Lifted arguments ordered based on the original order of typedArgBuf and
621+
// with all non-explicit default parameters at the end in declaration order.
622+
val orderedArgDefs = {
623+
// List of original arguments that are lifted by liftArgs
624+
val impureArgs = typedArgBuf.filterNot(isPureExpr)
625+
// Assuming stable sorting all non-explicit default parameters will remain in the end with the same order
626+
val defaultParamIndex = args.size
627+
// Mapping of index of each `liftable` into original args ordering
628+
val indices = impureArgs.map { arg =>
629+
val idx = args.indexOf(arg)
630+
if (idx >= 0) idx // original index skipping pure arguments
631+
else defaultParamIndex
632+
}
633+
scala.util.Sorting.stableSort[(Tree, Int), Int](argDefBuf zip indices, x => x._2).map(_._1)
634+
}
635+
636+
liftedDefs ++= orderedArgDefs
616637
}
617638
if (sameSeq(typedArgs, args)) // trick to cut down on tree copying
618639
typedArgs = args.asInstanceOf[List[Tree]]

tests/run/i2916.check

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
1
2+
2
3+
3
4+
4
5+
5
6+
7+
1
8+
2
9+
3
10+
4
11+
5
12+
13+
1
14+
3
15+
2
16+
4
17+
5
18+
19+
1
20+
3
21+
5
22+
2
23+
4
24+
25+
1
26+
3
27+
4
28+
2
29+
5
30+
31+
1
32+
4
33+
2
34+
5
35+
36+
0
37+
1
38+
3
39+
4
40+
2
41+
5
42+
43+
0
44+
1
45+
3
46+
4
47+
2
48+
5
49+
50+
1
51+
3
52+
2
53+
4
54+
55+
3
56+
2
57+
4
58+
59+
1
60+
2
61+
4

tests/run/i2916.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
object Test {
2+
def p(x: Int) = { println(x); x }
3+
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), x4: Int = p(4)) = ()
5+
6+
def main(args: Array[String]) = {
7+
foo(p(1), p(2), p(3)) // 1 2 3 4 5
8+
println()
9+
foo(p(1), x2 = p(2), x3 = p(3)) // 1 2 3 4 5
10+
println()
11+
foo(p(1), x3 = p(3), x2 = p(2)) // 1 3 2 4 5
12+
println()
13+
foo(p(1), x3 = p(3), x5 = p(5), x2 = p(2)) // 1 3 5 2 4
14+
println()
15+
foo(p(1), x3 = p(3), x4 = p(4), x2 = p(2)) // 1 3 4 2 5
16+
println()
17+
18+
foo(p(1), x3 = 3, x4 = p(4), x2 = p(2)) // 1 4 2 5
19+
println()
20+
21+
def test = { println(0); Test }
22+
test.foo(p(1), x3 = p(3), x4 = p(4), x2 = p(2)) // 0 1 3 4 2 5
23+
println()
24+
25+
{ println(0); Test }.foo(p(1), x3 = p(3), x4 = p(4), x2 = p(2)) // 0 1 3 4 2 5
26+
println()
27+
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
35+
36+
}
37+
}

0 commit comments

Comments
 (0)