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

Inferring tracked #21628

Merged
merged 21 commits into from
Jan 15, 2025
Merged

Inferring tracked #21628

merged 21 commits into from
Jan 15, 2025

Conversation

KacperFKorban
Copy link
Member

@KacperFKorban KacperFKorban commented Sep 23, 2024

Infer tracked for parameters that are referenced in the public signatures of the defining class.
e.g.

class OrdSet(val ord: Ordering) {
  type Set = List[ord.T]
  def empty: Set = Nil

  implicit class helper(s: Set) {
    def add(x: ord.T): Set = x :: remove(x)
    def remove(x: ord.T): Set = s.filter(e => ord.compare(x, e) != 0)
    def member(x: ord.T): Boolean = s.exists(e => ord.compare(x, e) == 0)
  }
}

In the example above, ord is referenced in the signatures of the public members of OrdSet, so a tracked modifier will be inserted automatically.

Aldo generalize the condition for infering tracked for context bounds. Explicit using val witnesses will now also be tracked by default.

This implementation should be safe with regards to not introducing spurious cyclic reference errors.
Current limitations (I'll create separate issues for them, once this is merged):

  • Inferring tracked for given classes is done after the desugaring to class + def, so the def doesn't know about tracked being set on the original constructor parameter. This might be worked around by watching the original symbol or adding an attachment pointer to the implicit wrapper.
    given mInst: (c: C) => M:
    def foo: c.T = c.foo
  • Passing parameters as an inferred tracked arguments in parents doesn't work, since forcing a parent (term) isn't safe.
    This can be replaced with a lint that is checked after Namer.

@KacperFKorban KacperFKorban force-pushed the infer-tracked branch 4 times, most recently from d1562cb to 65a5ddd Compare October 28, 2024 13:27
@KacperFKorban
Copy link
Member Author

Test logs for after enabling a subset of modularity required for tracked: https://github.com/scala/scala3/actions/runs/11557079836/job/32166261964

@KacperFKorban KacperFKorban marked this pull request as ready for review November 18, 2024 10:27
@KacperFKorban KacperFKorban changed the title Experiments into infering tracked Infering tracked Nov 18, 2024
@KacperFKorban KacperFKorban assigned mbovel and unassigned odersky Dec 12, 2024
@KacperFKorban KacperFKorban changed the title Infering tracked Inferring tracked Dec 12, 2024
Copy link
Member

@mbovel mbovel left a comment

Choose a reason for hiding this comment

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

I only have few comments about cosmetic and naming.

Otherwise looks very good to me; the diff is small and the changes are clear.

The heuristics for determining if tracked should be added look good to me at first sight, but I haven't experimented extensively with it.

@mbovel mbovel self-requested a review January 10, 2025 12:23
@KacperFKorban KacperFKorban added the release-notes Should be mentioned in the release notes label Jan 15, 2025
@KacperFKorban KacperFKorban merged commit 019d203 into scala:main Jan 15, 2025
29 checks passed
@KacperFKorban KacperFKorban deleted the infer-tracked branch January 15, 2025 11:01
bracevac pushed a commit to dotty-staging/dotty that referenced this pull request Jan 19, 2025
Infer `tracked` for parameters that are referenced in the public
signatures of the defining class.
e.g.
```scala 3
class OrdSet(val ord: Ordering) {
  type Set = List[ord.T]
  def empty: Set = Nil

  implicit class helper(s: Set) {
    def add(x: ord.T): Set = x :: remove(x)
    def remove(x: ord.T): Set = s.filter(e => ord.compare(x, e) != 0)
    def member(x: ord.T): Boolean = s.exists(e => ord.compare(x, e) == 0)
  }
}
```
In the example above, `ord` is referenced in the signatures of the
public members of `OrdSet`, so a `tracked` modifier will be inserted
automatically.

Aldo generalize the condition for infering tracked for context bounds.
Explicit `using val` witnesses will now also be `tracked` by default.

This implementation should be safe with regards to not introducing
spurious cyclic reference errors.
Current limitations (I'll create separate issues for them, once this is
merged):
- Inferring `tracked` for given classes is done after the desugaring to
class + def, so the def doesn't know about `tracked` being set on the
original constructor parameter. This might be worked around by watching
the original symbol or adding an attachment pointer to the implicit
wrapper.
  ```scala 3
  given mInst: (c: C) => M:
  def foo: c.T = c.foo
  ```
- Passing parameters as an **inferred** `tracked` arguments in parents
doesn't work, since forcing a parent (term) isn't safe.
  This can be replaced with a lint that is checked after Namer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-notes Should be mentioned in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants