You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes#26088
## Root Issue
The issue in question is actually a manifestation of a larger issue:
```scala
addMode(foo())
```
Will correctly get instrumented by coverage to roughly:
```scala
val $1$: T = { Invoker.invoked("foo"); foo() }
Invoker.invoked("addMode")
addMode($1$)
```
But:
```scala
addMode(foo()).setA(...)
```
Will incorrectly get instrumented to roughly:
```scala
val $1$ = addMode(foo())
Invoker.invoked("setA")
$1.setA(...)
```
So, in case of chained calls `foo(x).bar(y).baz(z)`, only the last call
`baz(z)` will get proper instrumentation that respects argument
evaluation order.
## Reported Issue Impact
Consider code:
```scala
class C { def setA(a: Int): this.type = this }
def addMode(c: C): c.type = c
val x = addMode(identity(new C()).setA(???)).setA(???)
```
Its line:
```scala
val x = addMode(identity(new C()).setA(???)).setA(???)
```
Coverage instrumentation of that line:
```scala
val $2$: (?1 : C) =
addMode(
{
val $1$: C = identity[C]({ Invoker.invoked(...); new C() })
val a$1: Nothing = ???
Invoker.invoked(...)
$1$.setA(a$1)
}
)
```
`Ycheck` then fails because the result type is tied to the method
parameter placeholder `?1`, while the block result is tied to the lifted
local `$1$`:
```scala
assertion failed: Type Mismatch
Found: ($1$ : C)
Required: (?1 : C)
```
## Solution
Ensure call chains such as `foo(x).bar(y).baz(z)` have all their calls
lifted and instrumented properly to preserve evaluation order.
In the case of the issue in question, this will have the following
effect:
```scala
val c$1: C =
{
val x$1: C = { Invoker.invoked(...); new C() }
val $1$: C = identity[C](x$1)
val a$1: Nothing = ???
Invoker.invoked(...)
$1$.setA(a$1)
}
Invoker.invoked(...)
val $2$: (c$1 : C) = addMode(c$1)
```
`c.type` is preserved in `addMode`, and `addMode(...)` is traced the
same way in `addMode(...).setA(...)` as it is in `addMode(...)`.
## How much have you relied on LLM-based tools in this contribution?
Moderately, for minimization, codebase analysis, tracing, test
generation.
## How was the solution tested?
New automated tests. Added
`tests/pos-custom-args/captures/coverage-freshcontext-addmode.scala` and
`tests/coverage/run/chained-apply/test.scala`. The coverage run test
checks direct, single-chain, multi-chain, and receiver-dependent chained
applications.
```bash
sbt "testCompilation --enable-coverage-phase coverage-freshcontext-addmode"
sbt "testCompilation coverage-freshcontext-addmode"
sbt "testCompilation --coverage"
```
0 commit comments