Skip to content

Allow caps in result types of functions to be mapped to reaches #23275

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

Merged
merged 3 commits into from
May 28, 2025

Conversation

odersky
Copy link
Contributor

@odersky odersky commented May 27, 2025

Allow caps in result types of functions to be mapped to reach capabilities

Example: If we have val f: A => C^ then f has type A => C^{f*}. Before it had that type only if A was pure. On the other hand, result caps are not replaced anymore. We used to have for val f: (x: A) => C^ with A pure that f: (x: A) => C^{f*}. That's no longer the case. In this case, f now has type f: (x: A) => C^ with the ^ understood to be existentially bound.

This aligns the implementation with the Capless paper.

…ities

Example: If we have `val f: A => C^` then `f` has type `A => C^{f*}`. Before it had
that type only if `A` was pure. On the other hand, result caps are not replaced
anymore. We used to have for `val f: (x: A) => C^` with `A` pure that `f: (x: A) => C^{f*}`.
That's no longer the case. In this case, `f` now has type `f: (x: A) => C^` with the `^`
understood to be existentially bound.

This aligns the implementation with the Capless paper.
@odersky odersky added the area:capabilities Issues tied with scala.caps.Capabilities label May 27, 2025
@odersky odersky requested a review from Linyxus May 27, 2025 18:52
Copy link
Contributor

@Linyxus Linyxus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great to me overall!

There is one thing about which we have to be extra careful after this change: we should restrict widening a dependent function to the non-dependent one, since this will implicitly change the way caps are interpreted as existentials and mess things up. For instance, the following example typechecks currently but morally it should not:

import language.experimental.captureChecking
trait File
def usingFile[R](op: File^ => R): R = op(new File {})
def id(x: File^): File^{x} = x
def test1(): Unit =
  val op: File^ -> File^ = id  // this should be disallowed
  val g: File^ -> File^{op*} = op  // otherwise we can brand arbitrary File as simply capturing op*

The thing is that we should not widen (f: File^) -> File^{f} to File^ -> File^ since the latter means exists c. File^ -> File^{c} where the existential is quantified at the outermost level and couldn't refer to this local parameter f.

@Linyxus Linyxus assigned odersky and unassigned Linyxus May 27, 2025
@odersky
Copy link
Contributor Author

odersky commented May 28, 2025

@Linyxus The error goes undetected since we turn off separation checking by default now. With separation checking on, we get:

-- [E007] Type Mismatch Error: reach-in-results.scala:7:4 ----------------------
7 |    val y = (x: File^) => id(x)  // this should be disallowed
  |    ^
  |Found:    (x: File^) -> File^²
  |Required: (x: File^) -> File^³
  |
  |where:    ^  refers to the universal root capability
  |          ^² refers to a root capability associated with the result type of (x: File^): File^²
  |          ^³ refers to a fresh root capability in the type of value op
8 |    y
  |
  | longer explanation available when compiling with `-explain`

I'll tweak the rules so that we produce FreshCap instances even if separation checking is off.

Copy link
Contributor

@Linyxus Linyxus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@Linyxus Linyxus merged commit e8e3903 into scala:main May 28, 2025
30 checks passed
@Linyxus Linyxus deleted the revise-reach branch May 28, 2025 10:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:capabilities Issues tied with scala.caps.Capabilities
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants