Commit b9f2ef0
authored
Ignore orphan parameters inside a retains annotation during Ycheck (#19684)
Fixes #19661.
## Cause of the issue
As reported in #19661, the following code triggers an assertation
failure during Ycheck:
```scala
import language.experimental.captureChecking
trait MySet[A]:
def collect[B](pf: PartialFunction[A, B]^): MySet[B]^{this, pf}
class Test:
def f(xs: MySet[Int]) = xs collect { case x => x }
def g(xs: MySet[Int]): MySet[Int] = f(xs)
```
The failure happens when checking the tree `f(xs)`, whose type is
`MySet[Int]^{this, PartialFunction[Int, Int]}`. The `checkNoOrphans`
function is invoked on `this`, whose type turns out to be an orphan
parameter reference (`xs`).
We first inspect the tree outputed by `typer`:
```scala
class Test() extends Object() {
def f(xs: MySet[Int]): MySet[Int]^{this, PartialFunction[Int, Int]} =
xs.collect[Int](
{
def $anonfun(x$1: Int): Int =
x$1 match
{
case x @ _ =>
x:Int
}
closure($anonfun:PartialFunction[Int, Int])
}
)
def g(xs: MySet[Int]): MySet[Int] = this.f(xs)
}
```
The problem roots in the signature of the method `f`: in the capture set
of its result type, the `this` reference is dangling.
How come? It turns out that the `asSeenFrom` map is not working
correctly for the typing of `xs.collect`:
```
(xs.collect : [B](pf: PartialFunction[Int, B]^): MySet[B]^{this, pf})
```
Instead of replacing `this` with `xs`, `asSeenFrom` keeps `this`
untouched. This is what happened:
- When mapping `asSeenFrom` on the method type, the `asSeenFrom` map
recurses and applies on the annotated type.
- When mapping the annotation (`@retains(this, pf)`), the `asSeenFrom`
map derives a `TreeTypeMap` from itself and uses it to map the `tree` of
the annotation.
- During that, the type of `this` is properly mapped to `xs.type` but
the tree `this` is never changed (since the `TreeTypeMap` is an identity
on the structure of trees).
To solve this issue, there are (at least) two possibilities:
- Refactor the `TypeMap` machineries on annotations to enable it to
properly handle these cases. But it is hard: when mapping the capture
annotation, we are at a pre-CC phase, so tools for manipulating capture
sets are not available. And it is unnecessary: even if we compute these
references properly, it gets discarded during CC.
- During Ycheck, ignore orphan parameter references inside a normal
`@retains` annotation (as opposed to an optimised `CaptureAnnotation`).
This feels like a dangerous fix but these `@retains` annotations, even
if they are ill-formed, is already treated as being unreliable in CC and
get rechecked. Also, CC turns these concrete annotations into optimised
`CaptureAnnotation`s, which are not ignored by Ycheck.
## Fix
So this PR implements the second option:
- Ignore orphan parameter errors inside a normal `@retains` annotation
during Ycheck.
- The check for `CaptureAnnotation`s will not be bypassed.File tree
2 files changed
+27
-1
lines changed- compiler/src/dotty/tools/dotc/transform
- tests/pos-custom-args/captures
2 files changed
+27
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| |||
162 | 163 | | |
163 | 164 | | |
164 | 165 | | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
165 | 173 | | |
166 | 174 | | |
167 | 175 | | |
168 | 176 | | |
169 | 177 | | |
170 | 178 | | |
171 | 179 | | |
172 | | - | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
173 | 186 | | |
174 | 187 | | |
175 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
176 | 194 | | |
177 | 195 | | |
178 | 196 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
0 commit comments