Skip to content

Make with type operator an error#26545

Open
mbovel wants to merge 7 commits into
scala:mainfrom
dotty-staging:mb/with-type-operator-error
Open

Make with type operator an error#26545
mbovel wants to merge 7 commits into
scala:mainfrom
dotty-staging:mb/with-type-operator-error

Conversation

@mbovel

@mbovel mbovel commented Jul 14, 2026

Copy link
Copy Markdown
Member

with as a type operator (A with B) has been deprecated since 3.4. Make it an error from 3.10 by changing MigrationVersion.WithOperator's errorFrom from future to 3.10. It stays a warning in the 3.4-3.9 source versions and a rewriteable migration warning under 3.10-migration.

Migrate the test suite from A with B to A & B (a purely syntactic change: with already desugars to an intersection type via makeAndType) and regenerate the semanticdb and Scala.js check files.

Note: in typed pattern position (case x: T => ...) the type is parsed as a RefinedType, which accepts with but not the & infix operator, so the migrated case x: A with B => must be parenthesised as case x: (A & B) => (matching what the automatic rewrite does).

Have you relied on LLM-based tools in this contribution?

Yes, and I reviewed the output.

How was the solution tested?

Covered by updated existing tests.

`with` as a type operator (`A with B`) has been deprecated since 3.4.
Make it an error from 3.10 by changing `MigrationVersion.WithOperator`'s
`errorFrom` from `future` to `3.10`. It stays a warning in the 3.4-3.9
source versions and a rewriteable migration warning under 3.10-migration.

Migrate the test suite from `A with B` to `A & B` (a purely syntactic
change: `with` already desugars to an intersection type via
`makeAndType`), regenerate the semanticdb and Scala.js check files, and
reorganise the dedicated with-operator tests:
 - move the 3.4-migration case to tests/warn (it still warns),
 - drop the future-migration warn test (it is now an error),
 - add tests/neg/with-type-operator.scala for the default-source error,
 - point the rewrite test at -source 3.10-migration.

In typed pattern position (`case x: T => ...`) the type is parsed as a
`RefinedType`, which accepts `with` but not the `&` infix operator, so
the migrated `case x: A with B =>` must be parenthesised as
`case x: (A & B) =>` (matching what the automatic rewrite does).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Replaced by tests/neg/with-type-operator.scala.

mbovel and others added 4 commits July 14, 2026 15:52
Follow-up to making `with` a type-operator error: migrate the remaining
in-repo test inputs that dotty compiles under the default source version.

 - repl: i6643 (bound), and drop the now-unwritable `with` cases from
   type-printer/infix (the parallel `&` cases already cover printing).
 - presentation-compiler: completion / info / inlayHints code snippets.
 - scripted: scala2-compat/erasure dottyApp (kept scala2Lib on `with`,
   the two are still erasure-equivalent), source-dependencies/continuations
   and compilerReporter/simple.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Point the community-build submodules that use the (now removed) `with`
type operator at `with-type-operator-error` branches on the dotty-staging
forks, where `A with B` is rewritten to `A & B`. Each fix was verified
locally by running the corresponding community-build test against the
locally published compiler.

Verified green: cats, ScalaPB, scalaz, fastparse, scala-parser-combinators,
sconfig, libretto, scala-parallel-collections, scala-java8-compat,
scala-stm, Lucre, perspective, parboiled2, scala-xml.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
izumi-reflect's fix additionally rewrites `with` inside two embedded test
type snippets (assertTypeError / assertCompiles), which a type-level pass
can't see. Verified green locally: `izumi-reflect/test` = 177 succeeded,
0 failed at the default source version.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Scala.js JUnit test suite is fetched from scala-js (pinned to
v$scalaJSVersion) and compiled as-is. Those sources still use the `with`
type operator, which is an error since 3.10, breaking
`sjsJUnitTests/Test/compileIncremental`. Compile them under 3.9, where
`with` is only a (non-fatal, `-Werror` is already off here) warning; 3.9
and 3.10 enable the same language features otherwise.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mbovel

mbovel commented Jul 14, 2026

Copy link
Copy Markdown
Member Author

@sjrd does that seem reasonable to compile sjsJUnitTests with -source:3.9 (59183ed)?

mbovel and others added 2 commits July 14, 2026 20:56
Fixes the three community_build_c failures. `intent` and `pprint` used the
`with` type operator only in test sources, which the earlier discovery pass
skipped; `upickle` is built by the active `ujson` test even though its own
test entry is commented out. All three fixes are verified green locally via
their community-build tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes the community_build_b failure: cats-effect used the `with` type
operator in 7 core files (14 occurrences, including the JS and Native
platform sources CI did not reach). The fix compiles cleanly and the
full catsEffect3 community-build test passes locally, modulo one
load-induced timeout in `DispatcherSuite.complete / cancel race-3`
which passes in isolation (111/111).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mbovel
mbovel marked this pull request as ready for review July 15, 2026 07:19
@mbovel

mbovel commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

@SethTisue

SethTisue commented Jul 15, 2026

Copy link
Copy Markdown
Member

About any community build failures that occur, I wonder how many of them are because the codebase is cross-compiled for both Scala 3 and 2. As of 3.10 we're no longer trying to support that, so perhaps both community builds will need to be slimmed down somewhat.

A middle option would be to try compiling a project with -source:3.9 if it won't compile with default settings, to avoid dropping the project entirely.

@SethTisue

Copy link
Copy Markdown
Member

In any case, there was no opposition at core meeting to proceeding with this.

@mbovel

mbovel commented Jul 16, 2026

Copy link
Copy Markdown
Member Author

I wonder how many of them are because the codebase is cross-compiled for both Scala 3 and 2.

16/19 updated community build projects cross-compile for Scala 2 and 3.

Claude output

I counted, by inspecting the build configuration of each of the 19 updated submodules:

16 of 19 cross-compile for Scala 2 and 3

Project Cross versions (from build)
cats 2.12, 2.13, 3
cats-effect-3 2.12, 2.13, 3
scalaz 2.13, 3
ScalaPB 2.12, 2.13, 3 (+ scala-2/scala-3 split dirs)
izumi-reflect 2.12, 2.13, 3 (+ scala-2*/scala-3 split dirs)
upickle 2.12, 2.13, 3 (Mill)
PPrint 2.12, 2.13, 3
fastparse 2.12, 2.13, 3 (shared src/)
scala-xml 2.12, 2.13, 3
scala-parser-combinators 2.11, 2.12, 2.13, 3
scala-java8-compat 2.11, 2.12, 2.13, 3
scala-parallel-collections 2.13, 3
scala-stm 2.11, 2.12, 2.13, 3
sconfig 2.11, 2.12, 2.13, 3
parboiled2 2.12, 2.13, 3
Lucre 2.12, 2.13, 3

Scala 3 only (2): libretto and intent — their with is just legacy style from
early Dotty days, not cross-compilation.

Special case (1): perspective — not same-source cross-compiled but a hybrid with
separate scala2/ (macro implementations, 2.13) and dotty/ trees; all 155 of its
with occurrences were in the scala2/ tree, i.e. genuine Scala-2-heritage code.
(The community build force-switches every module to the tested compiler via ++3.x...!,
which is why those files errored and why the & patch verifies green there.)

So 16/19 strictly, 17/19 counting perspective's Scala-2-heritage sources. It also
correlates with volume: the biggest patch counts (scalaz 304 occurrences, cats 197,
izumi-reflect 154, ScalaPB 68) are all cross-built libraries, where A with B was the
only intersection syntax valid under both compilers.

One implication: for these cross-built projects, the & patches on our dotty-staging
fork branches are community-build-only — upstream can't adopt them until they drop
Scala 2 or move those types into version-specific source dirs. That's a real (if mild)
ecosystem-migration cost of erroring in 3.10.

A middle option would be to try compiling a project with -source:3.9 if it won't compile with default settings, to avoid dropping the project entirely.

That sounds good to me; it's the cheap way to make the errors warnings again. In that sense, what we're changing is just the default level of the diagnostic, but users can always pass -source to change it.

Comment thread .gitmodules
[submodule "community-build/community-projects/ScalaPB"]
path = community-build/community-projects/ScalaPB
url = https://github.com/dotty-staging/ScalaPB
branch = with-type-operator-error

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Note: once this PR is validated, we can point each fork's main branch to its pinned fix commit and drop the branch = with-type-operator-error entries from .gitmodules.

@mbovel
mbovel requested a review from jchyb July 16, 2026 09:05
@mbovel mbovel added the needs-squashing PR whose commits should be squashed by the author or via the "Squash and Merge" button label Jul 16, 2026

@jchyb jchyb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! As I understand the comment, this shouldn't be merged until the community build branches are updated (currently I can't even if I wanted to because of the conflict). I was initially concerned about the open community build being usable after this, but now believe it should be fine, since it seems that it will use the latest -source:3.x-migration (at least if I understand VirtusLab/community-build3#576 correctly)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-squashing PR whose commits should be squashed by the author or via the "Squash and Merge" button

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants