diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 48c81a2c4000..c3a81bf71571 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -3540,6 +3540,8 @@ object Types extends TypeUtils { else this match case tp: OrType => OrType.make(tp1, tp2, tp.isSoft) case tp: AndType => AndType.make(tp1, tp2, checkValid = true) + + override def hashIsStable: Boolean = tp1.hashIsStable && tp2.hashIsStable } abstract case class AndType(tp1: Type, tp2: Type) extends AndOrType { @@ -3585,6 +3587,10 @@ object Types extends TypeUtils { case that: AndType => tp1.eq(that.tp1) && tp2.eq(that.tp2) case _ => false } + + override protected def iso(that: Any, bs: BinderPairs) = that match + case that: AndType => tp1.equals(that.tp1, bs) && tp2.equals(that.tp2, bs) + case _ => false } final class CachedAndType(tp1: Type, tp2: Type) extends AndType(tp1, tp2) @@ -3736,6 +3742,10 @@ object Types extends TypeUtils { case that: OrType => tp1.eq(that.tp1) && tp2.eq(that.tp2) && isSoft == that.isSoft case _ => false } + + override protected def iso(that: Any, bs: BinderPairs) = that match + case that: OrType => tp1.equals(that.tp1, bs) && tp2.equals(that.tp2, bs) && isSoft == that.isSoft + case _ => false } final class CachedOrType(tp1: Type, tp2: Type, override val isSoft: Boolean) extends OrType(tp1, tp2) diff --git a/docs/_docs/reference/contextual/givens.md b/docs/_docs/reference/contextual/givens.md index bf018278c9fc..5499fc39b53c 100644 --- a/docs/_docs/reference/contextual/givens.md +++ b/docs/_docs/reference/contextual/givens.md @@ -88,6 +88,45 @@ given (using config: Config): Factory = MemoizingFactory(config) An alias given can have type parameters and context parameters just like any other given, but it can only implement a single type. +## Abstract Givens + +A given may be an abstract member, with the restriction that it must have an explicit name. + +```scala +trait HasOrd[T]: + given ord: Ord[T] +``` + +## More Structural Givens + +If an alias given instance is analogous to a lazy val, +and a structural given instance is analogous to an object, +albeit an object with an explicit type, +then a structural given may also be specified without an explicit type: + +```scala +class IntOrd extends Ord[Int]: + def compare(x: Int, y: Int) = + if x < y then -1 else if x > y then +1 else 0 + +given IntOrd() +``` + +Compare this syntax to: + +```scala +object intOrd extends IntOrd() +``` + +The empty parentheses are optional in the extends clause when defining a class, +but are required when defining a given. + +Further mixins are allowed as usual: + +```scala +given IntOrd() with OrdOps[Int] +``` + ## Given Macros Given aliases can have the `inline` and `transparent` modifiers. @@ -191,4 +230,4 @@ of given instances: - A _structural instance_ contains one or more types or constructor applications, followed by `with` and a template body that contains member definitions of the instance. - An _alias instance_ contains a type, followed by `=` and a right-hand side expression. -- An _abstract instance_ contains just the type, which is not followed by anything. +- An _abstract instance_ contains just the name and type, which is not followed by anything. diff --git a/tests/pos/i20858-min.scala b/tests/pos/i20858-min.scala new file mode 100644 index 000000000000..9c47b04031e6 --- /dev/null +++ b/tests/pos/i20858-min.scala @@ -0,0 +1,10 @@ + +type M[F[_,_]] = Int match + case 0 => String & M[F] + +type M1 = M[[x,y] =>> x | y] +type M2 = M[[x,y] =>> x | y] + +def Test: Unit = + val x: M1 = ??? + val _: M2 = x // was error diff --git a/tests/pos/i20858/defns_1.scala b/tests/pos/i20858/defns_1.scala new file mode 100644 index 000000000000..7b4b84745b58 --- /dev/null +++ b/tests/pos/i20858/defns_1.scala @@ -0,0 +1,27 @@ +import scala.compiletime.* +import scala.deriving.* + +sealed trait ZIO[-R, +E, +A] +sealed abstract class ZLayer[-RIn, +E, +ROut] +object ZLayer: + def apply[RIn, E, ROut](zio: => ZIO[RIn, E, ROut]): ZLayer[RIn, E, ROut] = ??? +type URIO[-R, +A] = ZIO[R, Nothing, A] +type IAnyType[T <: Tuple] = Tuple.Fold[T, Any, [x, y] =>> x & y] +type UAnyType[T <: Tuple] = Tuple.Fold[T, Any, [x, y] =>> x | y] + + +trait AutoLayer[A]: + def zlayer(using + p: Mirror.ProductOf[A] + ): ZLayer[IAnyType[p.MirroredElemTypes], Nothing, A] + +object AutoLayer: + inline given derived[A](using p: Mirror.ProductOf[A]): AutoLayer[A] = { + val a: ZIO[IAnyType[p.MirroredElemTypes], Nothing, A] = ??? + new AutoLayer[A]: + override def zlayer(using + pp: Mirror.ProductOf[A] + ): ZLayer[IAnyType[pp.MirroredElemTypes], Nothing, A] = ZLayer { + a.asInstanceOf[ZIO[IAnyType[pp.MirroredElemTypes], Nothing, A]] + } + } \ No newline at end of file diff --git a/tests/pos/i20858/usages_2.scala b/tests/pos/i20858/usages_2.scala new file mode 100644 index 000000000000..3a05ba54e97a --- /dev/null +++ b/tests/pos/i20858/usages_2.scala @@ -0,0 +1,2 @@ + +case class TestService(port: Int) derives AutoLayer // was error