Simulacrum Scalafix experiment
This project is an experiment in rewriting Typelevel Simulacrum as a set of Scalafix rules. It's currently a rough proof-of-concept, but it is able to replace Simulacrum in the Cats repository without breaking any tests or binary-compatibility checks.
Please see this Cats issue for discussion about this experiment.
@typeclass macro annotation adds three kinds of boilerplate, which this project factors into three Scalafix rules:
AddSerializable: This rule adds
extends Serializableto the root type classes in a type class hierarchy.
AddImplicitNotFound: This rule adds custom
@implicitNotFoundannotations for type classes.
TypeClassSupport: This rule adds a summoner method and syntax method support to the type class companion object.
Dotty compatibility rules
This repo currently includes a few miscellaneous Scalafix rules that may be useful for experimenting with Dotty cross-compilation:
ExpandTypeLambdas: This rule rewrites (a large subset of) kind-projector's type lambda syntax to a representation that currently works on both Scala 2 and Dotty.
ExpandPolymorphicLambdas: This rule rewrites kind-projector's polymorphic lambda values to explicit anonymous class instantiations that work on both Scala 2 and Dotty.
ParenthesizeLambdaParamWithType: This rule parenthesizes lambda parameters with type annotations as needed.
Expand rules are not intended to be a long-term solution. The issue is that right now Dotty has its own syntax for type lambdas and polymorphic function values, and it doesn't support kind-projector's syntax (despite the existence of a
-Ykind-projector compiler option, which currently doesn't actually do anything), while kind-projector doesn't support Dotty's syntax on Scala 2.
If you want to cross-compile for Scala 2 and Dotty right now, you need to use an extremely verbose encoding of type lambdas and polymorphic function values, which is what the rules in this repo target. In the future this won't be necessary, either because Dotty will add support for kind-projector syntax via its
-Ykind-projector flag, or because kind-projector will add support for Dotty syntax, or some of both (or something else entirely). In any case you almost certainly don't want to use the verbose encoding you'll get from these
Expand rules outside experimental branches.
Building Cats without macro annotations
It's not currently possible to build Cats with Dotty because Simulacrum 1 uses macro annotations, which Dotty doesn't support. The goal of this project is to change that by providing a non-macro-annotation-based version of Simulacrum.
I have a Cats branch that demonstrates how these Scalafix rules work. You can follow along with the following steps:
- Clone this repo and run
sbt +publishLocalto publish the annotations and Scalafix rules locally.
- Check out the current master branch on Cats (in my case this commit).
- If #3186, #3187, #3190, and #3191 aren't yet merged, cherry-pick their commits.
- Add Scalafix and the locally-published Scalafix rules to the Cats build and remove Simulacrum 1, Macro Paradise, etc. This takes about a dozen lines of configuration.
whileM_. This is necessary for compatibility because Simulacrum 1 didn't handle these methods.
- Open an sbt console in the Cats repo and run the following commands:
This will result in some boilerplate being added to the Cats source files:
sbt:cats> scalafix AddSerializable sbt:cats> scalafix AddImplicitNotFound sbt:cats> scalafix TypeClassSupport sbt:cats> scalafmtAll
50 files changed, 2206 insertions(+), 17 deletions(-)
sbt validateJVMto verify that tests and binary-compatibility checks pass after the change (and
sbt ++2.13.1 buildJVMif you want to check Scala 2.13 as well).
Cross-building cats-core on Dotty
You can add Dotty cross-building with a few additional steps:
- Add build configuration for Dotty. This is a net couple dozen lines.
- Move the one macro definition in cats-core into a Scala 2-specific source directory tree.
- Expand type lambdas and polymorphic function value definitions with the following commands:
This will result in a pretty big diff. Unlike the similar Simulacrum boilerplate expansion we did above, this kind-projector expansion probably isn't something we'd ever want to merge—it's just a convenient way to try out Dotty cross-building.
sbt:cats> +scalafix ExpandTypeLambdas sbt:cats> +scalafix ExpandPolymorphicLambdas sbt:cats> +scalafmtAll
- Add a couple of casts that Dotty needs for some reason.
- Compile on Dotty:
These modules should compile without errors (the other laws modules and cats-free will currently fail).
sbt:cats> ++0.21.0-bin-20191201-65a404f-NIGHTLY sbt:cats> coreJVM/compile sbt:cats> kernelLawsJVM/compile sbt:cats> alleycatsCoreJVM/compile
This experimental code is licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License.
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.