Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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.
- Loading branch information