Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CC: Drop special handling in recheckApplication #21659

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Sep 27, 2024

Based on #21445

In recheckApplication we implemented a rule that computed the capture set of an
application f(a) by being the "better" of either the capture set of f union
capture set of a or the capture set of the result type of f(a). This relies
on capture monotonicity, which we try to get away from. Also, it's semantically
dubious if the type of the argument a is a type variable that can be instantiated
to a capturing type as in the following example:

trait Iterator[+A]
  ...
  def flatMap[B](f: A => IterableOnce[B]^): Iterator[B]^{this, f}

Here, we account for every capability in IterableOnce[B]^ already in f. But
those capabilities could also come from A if A is instantiated in the
actual function argument to a capturing type.

There was extensive breakage once the special handling was dropped. One example is
the flatMap definition above. We leave that as a potential soundness hold for now,
but the right way to fix flatMap would be by adding a capture set variable:

def flatMap[B, C^](f: A => IterableOnce[B]^{C^}): Iterator[B]^{this, f, C^}

The problem is that this currently cannot be done in a way that allows flatMap to be called
as before, passing a single type argument for B. We'd have to change the system to either
allow curried type parameters or optional type parameters for capture sets.

Another issue is that now more reach capabilities are registered as used by the enclosing method.
An example is lazylist-exceptions.scala, which has been moved to pending. Here, the use is spurious
because it happens inside an anonymous class creation on the right hand side of the method.
With refined use checking, the use would not propagate to the method, so the reach capability should
not be leaking. But to get there we need to implement refined use checking first.

noti0na1 and others added 7 commits September 25, 2024 21:45
This is done for comparing old with new
Add the path cases without changing the whole logic
If we refer to a path `a.b`, we should mark `a.b` as used,
which is better than marking `a`.
Needed to make stdlib2-cc go through.

There were two errors. One in LayListIterable required a type annotation
and a tweak to markFree. The other in Vieew.scala required a cast, but this could be fixed
with better handling of pattern matching. path-patmat-should-be-pos.scala is a minimization.
In recheckApplication we implemented a rule that computed the capture set of an
application `f(a)` by being the "better" of either the capture set of `f` union
capture set of `a` or the capture set of the result type of `f(a)`. This relies
on capture monotinicity, which we try to get away from. Also, it's semantically
dubious if the type of the argument `a` is a type variable that can be instantiated
to a capturing type as in the following example:
```scala
trait Iterator[+A]
  ...
  def flatMap[B](f: A => IterableOnce[B]^): Iterator[B]^{this, f}
```
Here, we account for every capability in `IterableOnce[B]^` already in `f`. But
those capabilities could also come from `A` if `A` is instantiated in the
actual function argument to a capturing type.

There was extensive breakage once the special handling was dropped. One example is
the `flatMap` definition above. We leave that as a potential soundness hold for now,
but the right way to fix `flatMap` would be by adding a capture set variable:
```scala
def flatMap[B, C^](f: A => IterableOnce[B]^{C^}): Iterator[B]^{this, f, C^}
```
The problem is that this currently cannot be done in a way that allows flatMap to be called
as before, passing a single type argument for `B`. We'd have to change the system to either
allow curried type parameters or optional type parameters for capture sets.

Another issue is that now more reach capabilities are registered as used by the enclosing method.
An example is lazylist-exceptions.scala, which has been moved to pending. Here, the use is spurious
because it happens inside an anonymous class creation on the right hand side of the method.
With refined use checking, the use would not propagate to the method, so the reach capability should
not be leaking. But to get there we need to implement refined use checking first.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants