Skip to content

Port Capture-checked Scala 2 collections #23769

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 87 commits into from
Aug 19, 2025

Conversation

natsukagami
Copy link
Contributor

@natsukagami natsukagami commented Aug 16, 2025

Changes:

  • New final class collection.immutable.LazyListIterable[A], implements Iterable and IterableOps. LazyList and Stream are not capture-checked. Note added to LazyList.
  • New trait collection.StrictSeqOps[A, CC[_] <: Pure, C], which extends SeqOps (which can now be impure) and requires the implementation to be pure. Seq and other data structures extend this. no longer needed

Suspicious changes:

  • Might be suspicious: MapOps.keySet changes implementation to be always strict, unless it is one of the library's known strict collections

Not capture-checked (yet?)

  • Generated functions and tuples files. I tried turning CC on for functions and it hung the compiler. Maybe not a problem.
  • collection.convert.impl a.k.a Steppers, due to some purity problems (maybe because we don't compile steppers and rely on Scala 2, for specialization?).
  • LazyList and Streams.

Comment on lines +162 to +163
// CC note: seems like the compiler cannot figure out that this class <: Iterator[C^{s}],
// so we need a cast when upcasting is needed.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need an issue for this one

Comment on lines +872 to +878
// CC Problem: if we add the logically needed `^`s to the `it` parameter and the
// self type, separation checking fails in the compiler-generated equals$extends
// method of the value class. There seems to be something wrong how pattern
// matching interacts with separation checking. A minimized test case
// is pending/pos-custom-args/captures/SizeCompareOps-redux.scala.
// Without the `^`s, the `sizeIs` method needs an unsafeAssumePure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO make an issue

@@ -218,22 +237,22 @@ transparent trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
* @return an [[Iterable]] collection of the keys contained by this map
*/
@deprecatedOverriding("This method should be an alias for keySet", since="2.13.13")
def keys: Iterable[K] = keySet
def keys: Iterable[K]^{this} = this.keySet
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically this should've been an alias for this.keysIterator, which would be strictly more efficient, but alas

Comment on lines +429 to +436
private class LazyKeySet[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C](mp: MapOps[K, V, CC, C]) extends AbstractSet[K] with DefaultSerializable {
def iterator: Iterator[K] = mp.keysIterator
def diff(that: Set[K]): Set[K] = LazyKeySet.this.fromSpecific(this.view.filterNot(that))
def contains(key: K): Boolean = mp.contains(key)
override def size: Int = mp.size
override def knownSize: Int = mp.knownSize
override def isEmpty: Boolean = mp.isEmpty
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually is the old implementation of KeySet & GenKeySet

Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

See my question about LazyKetSet. This should still be addressed but it can be a separate PR.

Copy link
Member

@hamzaremmal hamzaremmal left a comment

Choose a reason for hiding this comment

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

All good, Martin's upcoming PR should solve all the issues with the bound checker for caps.Pure. There is one added bounded that will not be covered by that check and needs to be (dropped ?) solved.

Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

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

All OK from my side. Nice that we could get rid of the StrictSeqOps traits and related stuff.

@odersky
Copy link
Contributor

odersky commented Aug 19, 2025

PR for pure checking: #23784

@natsukagami natsukagami marked this pull request as ready for review August 19, 2025 21:53
@natsukagami natsukagami requested a review from a team as a code owner August 19, 2025 21:53
@odersky
Copy link
Contributor

odersky commented Aug 19, 2025

I'm going to bed now. If the tests are green we can merge.

@natsukagami natsukagami merged commit 1f13619 into scala:main Aug 19, 2025
49 checks passed
@natsukagami natsukagami deleted the port-scala2-cc branch August 19, 2025 23:26
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.

5 participants