From 9edf6af618f38912b6e89531897e808d2c1a7a50 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Tue, 16 Dec 2025 16:13:39 +0100 Subject: [PATCH] bugfix: Fix issues with Scala JS and coverage --- .../dotc/transform/InstrumentCoverage.scala | 3 + tests/coverage/pos/DefaultArgs.scala | 29 ++ .../coverage/pos/DefaultArgs.scoverage.check | 411 ++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 tests/coverage/pos/DefaultArgs.scala create mode 100644 tests/coverage/pos/DefaultArgs.scoverage.check diff --git a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala index 449402f17fce..689d7e01e0ae 100644 --- a/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala +++ b/compiler/src/dotty/tools/dotc/transform/InstrumentCoverage.scala @@ -10,6 +10,7 @@ import core.Contexts.{Context, ctx, inContext} import core.DenotTransformers.IdentityDenotTransformer import core.Symbols.{defn, Symbol} import core.Constants.Constant +import core.NameKinds.DefaultGetterName import core.NameOps.isContextFunction import core.StdNames.nme import core.Types.* @@ -554,6 +555,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: !sym.isOneOf(ExcludeMethodFlags) && !isCompilerIntrinsicMethod(sym) && !(sym.isClassConstructor && isSecondaryCtorDelegateCall) + && !sym.name.is(DefaultGetterName) // https://github.com/scala/scala3/issues/20255 && (tree.typeOpt match case AppliedType(tycon: NamedType, _) => /* If the last expression in a block is a context function, we'll try to @@ -590,6 +592,7 @@ class InstrumentCoverage extends MacroTransform with IdentityDenotTransformer: && sym.info.isParameterless && !isCompilerIntrinsicMethod(sym) && !sym.info.typeSymbol.name.isContextFunction // exclude context functions like in canInstrumentApply + && !sym.name.is(DefaultGetterName) // https://github.com/scala/scala3/issues/20255 /** Does sym refer to a "compiler intrinsic" method, which only exist during compilation, * like Any.isInstanceOf? diff --git a/tests/coverage/pos/DefaultArgs.scala b/tests/coverage/pos/DefaultArgs.scala new file mode 100644 index 000000000000..1e7136b44d15 --- /dev/null +++ b/tests/coverage/pos/DefaultArgs.scala @@ -0,0 +1,29 @@ +package covtest + +// Test case for default arguments with coverage. +// Default getter methods ($default$N) should not be instrumented/lifted +// as this can cause issues with ScalaJS IR (https://github.com/scala/scala3/issues/20255). + +class DefaultArgs: + def methodWithDefaults( + a: String, + b: Int = 0, + c: Boolean = true + ): String = + s"$a, $b, $c" + + def caller(): String = + // This call uses default arguments for b and c + methodWithDefaults("test") + + def callerPartial(): String = + // This call uses default argument only for c + methodWithDefaults("test", 42) + +object DefaultArgs: + def staticMethod(x: Int = 10, y: Int = 20): Int = + x + y + + def staticCaller(): Int = + staticMethod() + staticMethod(5) + staticMethod(5, 15) + diff --git a/tests/coverage/pos/DefaultArgs.scoverage.check b/tests/coverage/pos/DefaultArgs.scoverage.check new file mode 100644 index 000000000000..91c6267acfb8 --- /dev/null +++ b/tests/coverage/pos/DefaultArgs.scoverage.check @@ -0,0 +1,411 @@ +# 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 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +methodWithDefaults +216 +238 +8 +methodWithDefaults +DefDef +false +0 +false +def methodWithDefaults + +1 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +methodWithDefaults$default$2 +268 +269 +10 + +Literal +false +0 +false +0 + +2 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +methodWithDefaults$default$2 +268 +286 +10 +methodWithDefaults$default$2 +DefDef +false +0 +false +0,\n c: Boolean + +3 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +methodWithDefaults$default$3 +288 +292 +11 + +Literal +false +0 +false +true + +4 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +methodWithDefaults$default$3 +288 +306 +11 +methodWithDefaults$default$3 +DefDef +false +0 +false +true\n ): String = + +5 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +caller +407 +433 +17 +methodWithDefaults +Apply +false +0 +false +methodWithDefaults("test") + +6 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +caller +426 +432 +17 + +Literal +false +0 +false +"test" + +7 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +caller +328 +338 +15 +caller +DefDef +false +0 +false +def caller + +8 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +callerPartial +521 +551 +21 +methodWithDefaults +Apply +false +0 +false +methodWithDefaults("test", 42) + +9 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +callerPartial +540 +546 +21 + +Literal +false +0 +false +"test" + +10 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +callerPartial +548 +550 +21 + +Literal +false +0 +false +42 + +11 +DefaultArgs.scala +covtest +DefaultArgs +Class +covtest.DefaultArgs +callerPartial +437 +454 +19 +callerPartial +DefDef +false +0 +false +def callerPartial + +12 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticMethod +629 +634 +25 ++ +Apply +false +0 +false +x + y + +13 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticMethod +575 +591 +24 +staticMethod +DefDef +false +0 +false +def staticMethod + +14 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticMethod$default$1 +601 +603 +24 + +Literal +false +0 +false +10 + +15 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticMethod$default$1 +601 +613 +24 +staticMethod$default$1 +DefDef +false +0 +false +10, y: Int = + +16 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticMethod$default$2 +614 +616 +24 + +Literal +false +0 +false +20 + +17 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticMethod$default$2 +614 +626 +24 +staticMethod$default$2 +DefDef +false +0 +false +20): Int =\n + +18 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticCaller +668 +722 +28 ++ +Apply +false +0 +false +staticMethod() + staticMethod(5) + staticMethod(5, 15) + +19 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticCaller +685 +700 +28 +staticMethod +Apply +false +0 +false +staticMethod(5) + +20 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticCaller +698 +699 +28 + +Literal +false +0 +false +5 + +21 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticCaller +703 +722 +28 +staticMethod +Apply +false +0 +false +staticMethod(5, 15) + +22 +DefaultArgs.scala +covtest +DefaultArgs +Object +covtest.DefaultArgs +staticCaller +638 +654 +27 +staticCaller +DefDef +false +0 +false +def staticCaller +