From d802cd4722449d448730c0e84dea6dded455e731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 8 Dec 2023 11:49:53 +0100 Subject: [PATCH 1/3] Fix an illegal match type case under SIP-56. `CodecBinding` per se is not a valid type constructor for match type cases under SIP-56. We manually expand the `Tuple.InverseMap` so that we get a more precise decomposition, which allows to write a match type case that is valid under the new rules, without changing the behavior. This change allows to compile `protocol_core` but not yet its tests. --- .../core/connection/protocol/PacketIdBindings.scala | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/connection/protocol/PacketIdBindings.scala b/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/connection/protocol/PacketIdBindings.scala index c1dd0ca0..0fecc9e6 100644 --- a/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/connection/protocol/PacketIdBindings.scala +++ b/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/connection/protocol/PacketIdBindings.scala @@ -5,7 +5,6 @@ import io.github.kory33.s2mctest.core.connection.codec.dsl.DecodeFiniteBytes import io.github.kory33.s2mctest.core.generic.compiletime.* import io.github.kory33.s2mctest.core.generic.extensions.MappedTupleExt.mapToList -import scala.Tuple.{Elem, InverseMap} import scala.annotation.implicitNotFound type PacketId = Int @@ -66,10 +65,16 @@ class PacketIdBindings[PacketTup <: Tuple]( object PacketIdBindings { def apply[BindingsTup <: Tuple](bindingsTup: BindingsTup)( - using ev: Tuple.IsMappedBy[CodecBinding][BindingsTup] - ): PacketIdBindings[Tuple.InverseMap[BindingsTup, CodecBinding]] = { - new PacketIdBindings[InverseMap[BindingsTup, CodecBinding]]( + using ev: BindingsTup =:= Tuple.Map[InverseCodecBindings[BindingsTup], CodecBinding] + ): PacketIdBindings[InverseCodecBindings[BindingsTup]] = { + new PacketIdBindings[InverseCodecBindings[BindingsTup]]( ev(bindingsTup) ) } + + /** Converts a tuple `(CodecBinding[T1], ..., CodecBinding[Tn])` to `(T1, ... Tn)` */ + type InverseCodecBindings[X <: Tuple] <: Tuple = X match { + case (PacketId, ByteCodec[x]) *: t => x *: InverseCodecBindings[t] + case EmptyTuple => EmptyTuple + } } From 94ea55376f10f9cbe36c1318a64dd90d564ea6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 8 Dec 2023 11:53:11 +0100 Subject: [PATCH 2/3] Turn the abstract `type Lock[X]` into a `sealed trait Lock[X]`. An abstract type like `Lock[X]` cannot be proven disjoint from anything under SIP-56, since it *could* be instantiated to anything. In particular, it could be instantiated to `type Lock[X] = Int`, and then clearly even `Lock[Int]` and `Lock[String]` would not be disjoint. By making it a `sealed trait` instead, it is a concrete class type, and so `Lock[Int]` and `Lock[String]` are actually disjoint. --- .../kory33/s2mctest/core/generic/compiletime/Generic.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/generic/compiletime/Generic.scala b/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/generic/compiletime/Generic.scala index 2e7499f8..4033091f 100644 --- a/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/generic/compiletime/Generic.scala +++ b/protocol-core/src/main/scala/io/github/kory33/s2mctest/core/generic/compiletime/Generic.scala @@ -9,7 +9,7 @@ import scala.annotation.implicitNotFound * @see * [[IncludedInLockedT]] for an example usage. */ -type Lock[X] +sealed trait Lock[X] /** * An implicit evidence that the type [[S]] can be reduced to the singleton type [[true]]. From a4d4d323dad714c6b157f6005c01f16cb734d81b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 8 Dec 2023 11:56:18 +0100 Subject: [PATCH 3/3] Remove some tests that would still not pass under SIP-56. No matter what we do, `Int` cannot be proven disjoint from `Any` or from `1` (to take the first two tests that are removed). It happened to work under the unspecified match types before SIP-56, but there was evidence to guarantee its soundness. It does not seem like the larger project needs those particular tests to pass to be meaningful. So we suggest to remove them, and focus on types that are actually provably disjoint. --- .../kory33/s2mctest/core/generic/compiletime/TupleSpec.scala | 5 ----- 1 file changed, 5 deletions(-) diff --git a/protocol-core/src/test/scala/io/github/kory33/s2mctest/core/generic/compiletime/TupleSpec.scala b/protocol-core/src/test/scala/io/github/kory33/s2mctest/core/generic/compiletime/TupleSpec.scala index 0ca0b553..c727f683 100644 --- a/protocol-core/src/test/scala/io/github/kory33/s2mctest/core/generic/compiletime/TupleSpec.scala +++ b/protocol-core/src/test/scala/io/github/kory33/s2mctest/core/generic/compiletime/TupleSpec.scala @@ -10,16 +10,11 @@ class TupleSpec extends AnyFlatSpec with should.Matchers { summon[IncludedInT[(Int, String, Double), Double] =:= true] summon[IncludedInT[EmptyTuple, Any] =:= false] - summon[IncludedInT[(Int, String, Double), Any] =:= false] - summon[IncludedInT[(Int, String, Double), 1] =:= false] - summon[IncludedInT[(Int, String, Double), Int | String] =:= false] summon[IncludedInT[(Int, String, Double), Float] =:= false] } "IndexOfT" should "extract the index of a specific type from a tuple" in { summon[IndexOfT[Int, (String, Int)] =:= 1] - summon[IndexOfT[42, (String, Int, 42)] =:= 2] - summon[IndexOfT[Int, (String | Int, Double, Int)] =:= 2] "summon[IndexOfT[42, (0, 0)] =:= 0]" shouldNot compile "summon[IndexOfT[42, (0, 0)] =:= 1]" shouldNot compile