From 8d2f6c0815b56e91284b9c434f2c530f831b016c Mon Sep 17 00:00:00 2001 From: Guillaume Raffin Date: Sat, 25 Jun 2022 23:55:26 +0200 Subject: [PATCH] Fix handling of lifted varargs in ElimRepeated Fixes #15078 --- .../tools/dotc/transform/ElimRepeated.scala | 24 +- .../tools/dotc/coverage/CoverageTests.scala | 3 +- tests/coverage/run/varargs/JavaVarargs_1.java | 7 + tests/coverage/run/varargs/test_1.check | 3 + tests/coverage/run/varargs/test_1.scala | 20 ++ .../run/varargs/test_1.scoverage.check | 293 ++++++++++++++++++ 6 files changed, 339 insertions(+), 11 deletions(-) create mode 100644 tests/coverage/run/varargs/JavaVarargs_1.java create mode 100644 tests/coverage/run/varargs/test_1.check create mode 100644 tests/coverage/run/varargs/test_1.scala create mode 100644 tests/coverage/run/varargs/test_1.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala index 9e4e45829cff..bdc2a268c1f8 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala @@ -124,17 +124,21 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase => tp override def transformApply(tree: Apply)(using Context): Tree = - val args = tree.args.mapConserve { - case arg: Typed if isWildcardStarArg(arg) => + val args = tree.args.mapConserve { arg => + if isWildcardStarArg(arg) then + val expr = arg match + case t: Typed => t.expr + case _ => arg // if the argument has been lifted it's not a Typed (often it's an Ident) + val isJavaDefined = tree.fun.symbol.is(JavaDefined) - val tpe = arg.expr.tpe if isJavaDefined then - adaptToArray(arg.expr) - else if tpe.derivesFrom(defn.ArrayClass) then - arrayToSeq(arg.expr) + adaptToArray(expr) + else if expr.tpe.derivesFrom(defn.ArrayClass) then + arrayToSeq(expr) else - arg.expr - case arg => arg + expr + else + arg } cpy.Apply(tree)(tree.fun, args) @@ -287,9 +291,9 @@ class ElimRepeated extends MiniPhase with InfoTransformer { thisPhase => val array = tp.translateFromRepeated(toArray = true) // Array[? <: T] val element = array.elemType.hiBound // T - if element <:< defn.AnyRefType || ctx.mode.is(Mode.SafeNulls) && element.stripNull <:< defn.AnyRefType - || element.typeSymbol.isPrimitiveValueClass then array + || element.typeSymbol.isPrimitiveValueClass + then array else defn.ArrayOf(TypeBounds.upper(AndType(element, defn.AnyRefType))) // Array[? <: T & AnyRef] } diff --git a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala index 1ec3058415d7..3cb30c939f52 100644 --- a/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala +++ b/compiler/test/dotty/tools/dotc/coverage/CoverageTests.scala @@ -68,10 +68,11 @@ class CoverageTests: def computeCoverageInTmp(inputFile: Path, sourceRoot: Path, run: Boolean)(using TestGroup): Path = val target = Files.createTempDirectory("coverage") val options = defaultOptions.and("-Ycheck:instrumentCoverage", "-coverage-out", target.toString, "-sourceroot", sourceRoot.toString) - val test = compileFile(inputFile.toString, options) if run then + val test = compileDir(inputFile.getParent.toString, options) test.checkRuns() else + val test = compileFile(inputFile.toString, options) test.checkCompile() target diff --git a/tests/coverage/run/varargs/JavaVarargs_1.java b/tests/coverage/run/varargs/JavaVarargs_1.java new file mode 100644 index 000000000000..2d3a300715cc --- /dev/null +++ b/tests/coverage/run/varargs/JavaVarargs_1.java @@ -0,0 +1,7 @@ +class JavaVarargs_1 { + static void method(String... args) {} + + static Object multiple(Object first, String... others) { + return String.valueOf(first) + others.length; + } +} diff --git a/tests/coverage/run/varargs/test_1.check b/tests/coverage/run/varargs/test_1.check new file mode 100644 index 000000000000..d28df10f66db --- /dev/null +++ b/tests/coverage/run/varargs/test_1.check @@ -0,0 +1,3 @@ +first0 +first0 +first3 \ No newline at end of file diff --git a/tests/coverage/run/varargs/test_1.scala b/tests/coverage/run/varargs/test_1.scala new file mode 100644 index 000000000000..0e6f76d06909 --- /dev/null +++ b/tests/coverage/run/varargs/test_1.scala @@ -0,0 +1,20 @@ +import java.nio.file.Files +import java.io.File + +def repeated(s: String*) = () + +def f(s: String) = s + +@main +def Test = + repeated() + repeated(f(""), "b") + JavaVarargs_1.method() + JavaVarargs_1.method("") + + var m = JavaVarargs_1.multiple("first") + println(m) + m = JavaVarargs_1.multiple(f("first")) + println(m) + m = JavaVarargs_1.multiple(f("first"), "a", "b", "c") + println(m) diff --git a/tests/coverage/run/varargs/test_1.scoverage.check b/tests/coverage/run/varargs/test_1.scoverage.check new file mode 100644 index 000000000000..3a242f7a97a4 --- /dev/null +++ b/tests/coverage/run/varargs/test_1.scoverage.check @@ -0,0 +1,293 @@ +# Coverage data, format version: 3.0 +# Statement data: +# - id +# - source path +# - package name +# - class name +# - class type (Class, Object or Trait) +# - full class name +# - method name +# - start offset +# - end offset +# - line number +# - symbol name +# - tree name +# - is branch +# - invocations count +# - is ignored +# - description (can be multi-line) +# ' ' sign +# ------------------------------------------ +0 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +repeated +48 +60 +3 +repeated +DefDef +false +0 +false +def repeated + +1 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +f +79 +84 +5 +f +DefDef +false +0 +false +def f + +2 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +120 +130 +9 +repeated +Apply +false +0 +false +repeated() + +3 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +142 +147 +10 +f +Apply +false +0 +false +f("") + +4 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +133 +153 +10 +repeated +Apply +false +0 +false +repeated(f(""), "b") + +5 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +156 +178 +11 +method +Apply +false +0 +false +JavaVarargs_1.method() + +6 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +181 +205 +12 +method +Apply +false +0 +false +JavaVarargs_1.method("") + +7 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +217 +248 +14 +multiple +Apply +false +0 +false +JavaVarargs_1.multiple("first") + +8 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +251 +261 +15 +println +Apply +false +0 +false +println(m) + +9 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +291 +301 +16 +f +Apply +false +0 +false +f("first") + +10 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +268 +302 +16 +multiple +Apply +false +0 +false +JavaVarargs_1.multiple(f("first")) + +11 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +305 +315 +17 +println +Apply +false +0 +false +println(m) + +12 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +345 +355 +18 +f +Apply +false +0 +false +f("first") + +13 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +322 +371 +18 +multiple +Apply +false +0 +false +JavaVarargs_1.multiple(f("first"), "a", "b", "c") + +14 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +374 +384 +19 +println +Apply +false +0 +false +println(m) + +15 +varargs/test_1.scala + +test_1$package$ +Object +.test_1$package$ +Test +101 +115 +8 +Test +DefDef +false +0 +false +@main +def Test +