Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds support for Mill 1.x build tool alongside existing Mill 0.11 and 0.12 support. It introduces platform-specific configurations to handle differences between Mill versions, particularly addressing Scala version requirements (Mill 1.x uses Scala 3.8.1 vs Scala 2.13 for legacy versions) and dependency management challenges. The changes also include Scala 3 compatibility improvements in the codegen module, updating type casting patterns and compiler options to work with newer Scala 3 versions, and refactoring string literal rendering to avoid scala-reflect dependency.
Changes:
- Introduced
MillPlatformConfigabstraction to handle version-specific Mill configurations including Scala versions, dependencies, and conflict resolution settings - Added Mill 1.x support with Scala 3.8.1, new
mill-libsdependency, and classpath conflict suppression - Updated Scala 3 compiler options to support both 3.3.x (-Ykind-projector, -release 8) and 3.8.x (-Xkind-projector, -release 17, -Werror) versions
- Refactored string literal rendering in codegen to use manual escaping instead of scala-reflect for Scala 3 compatibility
- Added Mill 1.x specific source files with updated Mill API usage and test implementations
Reviewed changes
Copilot reviewed 13 out of 17 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| project/Smithy4sBuildPlugin.scala | Introduces MillPlatformConfig abstraction and Mill 1.x support with platform-specific settings |
| project/Dependencies.scala | Adds Mill 1.x mill-libs dependency with necessary exclusions |
| modules/mill-codegen-plugin/src-mill-1/smithy4s/codegen/mill/Smithy4sModule.scala | Mill 1.x implementation of Smithy4s codegen plugin with updated Mill API |
| modules/mill-codegen-plugin/src-mill-1/smithy4s/codegen/LSP.scala | Mill 1.x LSP configuration module using new Mill API |
| modules/mill-codegen-plugin/test/src-mill-1/smithy4s/codegen/mill/Smithy4sModuleSpec.scala | Comprehensive test suite for Mill 1.x plugin functionality |
| modules/mill-codegen-plugin/test/src-mill-1/smithy4s/codegen/mill/SmithyLSPConfigSpec.scala | Tests for LSP configuration generation in Mill 1.x |
| modules/mill-codegen-plugin/src-mill-shared/smithy4s/codegen/mill/Smithy4sModuleCommon.scala | Simplified type matching using pattern matching instead of asInstanceOf |
| modules/codegen/src/smithy4s/codegen/internals/Renderer.scala | Refactored string literal rendering to use custom escaping for Scala 3 compatibility |
| modules/codegen/src/smithy4s/codegen/internals/SmithyToIR.scala | Added Scala 3-compatible type casting with @SuppressWarnings and @unchecked annotations |
| modules/codegen/src/smithy4s/codegen/transformers/ValidatedNewtypesTransformer.scala | Updated type casting pattern for Scala 3 compatibility |
| modules/codegen/src-3/smithy4s/codegen/internal/MapTypeCompanionPlatform.scala | New Scala 3-specific platform code for Map type companion |
| modules/codegen/test/src/smithy4s/codegen/internals/ScaladocSpec.scala | Removed unused empty statement |
| build.sbt | Updated codegen module to support Scala 3 and Mill Scala 3 versions with appropriate dependencies |
| modules/bootstrapped/src/generated/... | Updated generated code with improved string escaping (contractions properly escaped) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
modules/mill-codegen-plugin/test/src-mill-1/smithy4s/codegen/mill/Smithy4sModuleSpec.scala
Outdated
Show resolved
Hide resolved
| aws.auth.Sigv4(name = "dynamodb"), | ||
| aws.protocols.AwsJson1_0(http = None, eventStreamHttp = None), | ||
| Hints.dynamic(ShapeId("smithy.api", "documentation"), smithy4s.Document.fromString("<fullname>Amazon DynamoDB</fullname>\n\n\n <p>Amazon DynamoDB is a fully managed NoSQL database service that provides fast and\n predictable performance with seamless scalability. DynamoDB lets you offload the\n administrative burdens of operating and scaling a distributed database, so that you don\'t have\n to worry about hardware provisioning, setup and configuration, replication, software patching,\n or cluster scaling.</p>\n\n <p>With DynamoDB, you can create database tables that can store and retrieve any amount of\n data, and serve any level of request traffic. You can scale up or scale down your tables\'\n throughput capacity without downtime or performance degradation, and use the AWS Management\n Console to monitor resource utilization and performance metrics.</p>\n\n <p>DynamoDB automatically spreads the data and traffic for your tables over a sufficient\n number of servers to handle your throughput and storage requirements, while maintaining\n consistent and fast performance. All of your data is stored on solid state disks (SSDs) and\n automatically replicated across multiple Availability Zones in an AWS region, providing\n built-in high availability and data durability. </p>")), | ||
| Hints.dynamic(ShapeId("smithy.api", "documentation"), smithy4s.Document.fromString("<fullname>Amazon DynamoDB</fullname>\n\n\n <p>Amazon DynamoDB is a fully managed NoSQL database service that provides fast and\n predictable performance with seamless scalability. DynamoDB lets you offload the\n administrative burdens of operating and scaling a distributed database, so that you don't have\n to worry about hardware provisioning, setup and configuration, replication, software patching,\n or cluster scaling.</p>\n\n <p>With DynamoDB, you can create database tables that can store and retrieve any amount of\n data, and serve any level of request traffic. You can scale up or scale down your tables'\n throughput capacity without downtime or performance degradation, and use the AWS Management\n Console to monitor resource utilization and performance metrics.</p>\n\n <p>DynamoDB automatically spreads the data and traffic for your tables over a sufficient\n number of servers to handle your throughput and storage requirements, while maintaining\n consistent and fast performance. All of your data is stored on solid state disks (SSDs) and\n automatically replicated across multiple Availability Zones in an AWS region, providing\n built-in high availability and data durability. </p>")), |
There was a problem hiding this comment.
we used to escape a single quote , which was not necessary
| val id: ShapeId = ShapeId("smithy4s.example", "OrderType") | ||
|
|
||
| val hints: Hints = Hints( | ||
| Hints.dynamic(ShapeId("smithy.api", "documentation"), smithy4s.Document.fromString("Our order types have different ways to identify a product\nExcept for preview orders, these don\'t have an ID")), |
| val id: ShapeId = ShapeId("smithy4s.example", "InStoreOrder") | ||
|
|
||
| val hints: Hints = Hints( | ||
| Hints.dynamic(ShapeId("smithy.api", "documentation"), smithy4s.Document.fromString("For an InStoreOrder a location ID isn\'t needed")), |
| import LineSegment.NameRef | ||
|
|
||
| trait MapTypeCompanionPlatform { | ||
| val seqMapRef = NameRef("scala.collection.immutable.SeqMap") |
There was a problem hiding this comment.
same as scala 2 , just for cross compilation purposes
… and only use it for mill
| }) | ||
| } | ||
|
|
||
| private def escapeForStringLiteral(raw: String): String = { |
There was a problem hiding this comment.
This replaced the Scala 2 version of storing source code string literals without using reflection.
| scalaVersion: String, | ||
| millVersions: Seq[String] | ||
| millVersions: Seq[String], | ||
| deps: ProjectMatrix* |
There was a problem hiding this comment.
Since sbt-projectmatrix uses exact Scala version matching for .dependsOn(), the Mill 1.x row (3.8.1) can't find a matching codegen row (3.3.6).
To work around this, millPlatforms now accepts project matrix dependencies explicitly and wires them per-row using depScalaVersion
lewisjkl
left a comment
There was a problem hiding this comment.
Looks great, I think we should also update the documentation mill example to show how to setup for mill 1.x now as well
Co-authored-by: Jeff Lewis <lewisjkl@me.com>
| (duration: java.time.Duration) => line"$duration_(${renderStringLiteral(duration.toString)})" | ||
| case Primitive.Document => (node: Node) => renderNodeToLine(node) | ||
| case Primitive.Nothing => (_: Any) => sys.error("unreachable") // this case can't happen | ||
| }).asInstanceOf[T => Line] |
There was a problem hiding this comment.
This could be simplified by migrating away from Aux pattern of Primitive to normal parameterized trait like:
private[internals] sealed trait Primitive[T]
private[internals] object Primitive {
case object Unit extends Primitive[Unit]
case object Blob extends Primitive[Array[Byte]]Then Scala 3 typechecker will be satisfied with
private def renderPrimitive[T](prim: Primitive[T]): T => Line =
prim match {
case Primitive.BigDecimal =>
bd => line"scala.math.BigDecimal(${bd.toString})"
case Primitive.BigInteger => bi => line"scala.math.BigInt(${bi.toString})"
case Primitive.Unit => _ => line"()"
case Primitive.Double => t => line"${t.toString}d"
case Primitive.Float => t => line"${t.toString}f"
case Primitive.Long => t => line"${t.toString}L"
case Primitive.Int => t => line"${t.toString}"
case Primitive.Short => t => line"${t.toString}"
case Primitive.Bool => t => line"${t.toString}"
case Primitive.Uuid => uuid => line"java.util.UUID.fromString(${renderStringLiteral(uuid.toString)})"
case Primitive.String => s => renderStringLiteral(s)
case Primitive.Byte => b => line"${b.toString}"
case Primitive.Blob =>
ba =>
val blob = NameRef("smithy4s", "Blob")
if (ba.isEmpty) line"$blob.empty"
else
line"$blob(Array[Byte](${ba.mkString(", ")}))"
case Primitive.Timestamp =>
ts => line"${NameRef("smithy4s", "Timestamp")}(${ts.getEpochSecond()}L, ${ts.getNano()})"
case Primitive.Document => renderNodeToLine(_)
case Primitive.Nothing => v => (v: Nothing)
}But confirm me here, I may be wrong why Aux pattern was used here in the first place.
There was a problem hiding this comment.
Thanks for the input. Yeah it might be possible to move this direction, I'm not entirely sure. The reason it was done with Aux originally iirc has to do with the usage of recursion schemes in SmithyToIr
TypedNode. So I think it would be a larger refactor if we didn't have a GADT for primitive
lewisjkl
left a comment
There was a problem hiding this comment.
We can leave the PR open for the weekend in case anyone else wants to review, but I think it's good to go 🎉
In effort to target Mill 1.x , we need to support Scala 3 in the codegen module which must also support Scala 2.12 .
A bunch of syntax changes were made to be compatible with Scala 3 .
VarArgs expansion is the only syntax that was not supported in Scala 2 , and therefore a config was added to silence the warning in the Scalac options