Skip to content

Commit dbfe1e8

Browse files
Backport "Fix isomorphism tests of AndOrTypes under non-empty BinderPairs" to 3.5.2 (#21468)
Backports #21017 to the 3.5.2 branch. PR submitted by the release tooling. [skip ci]
2 parents f76c34a + 7f095e9 commit dbfe1e8

File tree

5 files changed

+89
-1
lines changed

5 files changed

+89
-1
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3540,6 +3540,8 @@ object Types extends TypeUtils {
35403540
else this match
35413541
case tp: OrType => OrType.make(tp1, tp2, tp.isSoft)
35423542
case tp: AndType => AndType.make(tp1, tp2, checkValid = true)
3543+
3544+
override def hashIsStable: Boolean = tp1.hashIsStable && tp2.hashIsStable
35433545
}
35443546

35453547
abstract case class AndType(tp1: Type, tp2: Type) extends AndOrType {
@@ -3585,6 +3587,10 @@ object Types extends TypeUtils {
35853587
case that: AndType => tp1.eq(that.tp1) && tp2.eq(that.tp2)
35863588
case _ => false
35873589
}
3590+
3591+
override protected def iso(that: Any, bs: BinderPairs) = that match
3592+
case that: AndType => tp1.equals(that.tp1, bs) && tp2.equals(that.tp2, bs)
3593+
case _ => false
35883594
}
35893595

35903596
final class CachedAndType(tp1: Type, tp2: Type) extends AndType(tp1, tp2)
@@ -3736,6 +3742,10 @@ object Types extends TypeUtils {
37363742
case that: OrType => tp1.eq(that.tp1) && tp2.eq(that.tp2) && isSoft == that.isSoft
37373743
case _ => false
37383744
}
3745+
3746+
override protected def iso(that: Any, bs: BinderPairs) = that match
3747+
case that: OrType => tp1.equals(that.tp1, bs) && tp2.equals(that.tp2, bs) && isSoft == that.isSoft
3748+
case _ => false
37393749
}
37403750

37413751
final class CachedOrType(tp1: Type, tp2: Type, override val isSoft: Boolean) extends OrType(tp1, tp2)

docs/_docs/reference/contextual/givens.md

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,45 @@ given (using config: Config): Factory = MemoizingFactory(config)
8888
An alias given can have type parameters and context parameters just like any other given,
8989
but it can only implement a single type.
9090

91+
## Abstract Givens
92+
93+
A given may be an abstract member, with the restriction that it must have an explicit name.
94+
95+
```scala
96+
trait HasOrd[T]:
97+
given ord: Ord[T]
98+
```
99+
100+
## More Structural Givens
101+
102+
If an alias given instance is analogous to a lazy val,
103+
and a structural given instance is analogous to an object,
104+
albeit an object with an explicit type,
105+
then a structural given may also be specified without an explicit type:
106+
107+
```scala
108+
class IntOrd extends Ord[Int]:
109+
def compare(x: Int, y: Int) =
110+
if x < y then -1 else if x > y then +1 else 0
111+
112+
given IntOrd()
113+
```
114+
115+
Compare this syntax to:
116+
117+
```scala
118+
object intOrd extends IntOrd()
119+
```
120+
121+
The empty parentheses are optional in the extends clause when defining a class,
122+
but are required when defining a given.
123+
124+
Further mixins are allowed as usual:
125+
126+
```scala
127+
given IntOrd() with OrdOps[Int]
128+
```
129+
91130
## Given Macros
92131

93132
Given aliases can have the `inline` and `transparent` modifiers.
@@ -191,4 +230,4 @@ of given instances:
191230
- A _structural instance_ contains one or more types or constructor applications,
192231
followed by `with` and a template body that contains member definitions of the instance.
193232
- An _alias instance_ contains a type, followed by `=` and a right-hand side expression.
194-
- An _abstract instance_ contains just the type, which is not followed by anything.
233+
- An _abstract instance_ contains just the name and type, which is not followed by anything.

tests/pos/i20858-min.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
type M[F[_,_]] = Int match
3+
case 0 => String & M[F]
4+
5+
type M1 = M[[x,y] =>> x | y]
6+
type M2 = M[[x,y] =>> x | y]
7+
8+
def Test: Unit =
9+
val x: M1 = ???
10+
val _: M2 = x // was error

tests/pos/i20858/defns_1.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import scala.compiletime.*
2+
import scala.deriving.*
3+
4+
sealed trait ZIO[-R, +E, +A]
5+
sealed abstract class ZLayer[-RIn, +E, +ROut]
6+
object ZLayer:
7+
def apply[RIn, E, ROut](zio: => ZIO[RIn, E, ROut]): ZLayer[RIn, E, ROut] = ???
8+
type URIO[-R, +A] = ZIO[R, Nothing, A]
9+
type IAnyType[T <: Tuple] = Tuple.Fold[T, Any, [x, y] =>> x & y]
10+
type UAnyType[T <: Tuple] = Tuple.Fold[T, Any, [x, y] =>> x | y]
11+
12+
13+
trait AutoLayer[A]:
14+
def zlayer(using
15+
p: Mirror.ProductOf[A]
16+
): ZLayer[IAnyType[p.MirroredElemTypes], Nothing, A]
17+
18+
object AutoLayer:
19+
inline given derived[A](using p: Mirror.ProductOf[A]): AutoLayer[A] = {
20+
val a: ZIO[IAnyType[p.MirroredElemTypes], Nothing, A] = ???
21+
new AutoLayer[A]:
22+
override def zlayer(using
23+
pp: Mirror.ProductOf[A]
24+
): ZLayer[IAnyType[pp.MirroredElemTypes], Nothing, A] = ZLayer {
25+
a.asInstanceOf[ZIO[IAnyType[pp.MirroredElemTypes], Nothing, A]]
26+
}
27+
}

tests/pos/i20858/usages_2.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
case class TestService(port: Int) derives AutoLayer // was error

0 commit comments

Comments
 (0)