Skip to content

Commit 946e2b7

Browse files
committed
fix scala#3935: add regression tests
1 parent 4b3652f commit 946e2b7

File tree

10 files changed

+115
-9
lines changed

10 files changed

+115
-9
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
scala> enum Maybe[+T] { case Something(value: T); case EmptyValue }; import Maybe._
2+
// defined class Maybe
3+
4+
scala> List(Something(1))
5+
val res0: List[Maybe[Int]] = List(Something(1))
6+
7+
scala> def listOfSomething[O <: Maybe.Something[_]](listOfSomething: List[O]): listOfSomething.type = listOfSomething
8+
def listOfSomething
9+
[O <: Maybe.Something[?]](listOfSomething: List[O]): listOfSomething.type
10+
11+
scala> listOfSomething(List(Something(1)))
12+
val res1: List[Maybe.Something[Int]] = List(Something(1))

tests/patmat/i7186.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -172,16 +172,16 @@ object printMips {
172172

173173
def oneAddr[O]
174174
( a: O, indent: String)
175-
( r: O => Dest,
175+
( r: a.type => Dest,
176176
): String = {
177177
val name = a.getClass.getSimpleName.toLowerCase
178178
s"${indent}$name ${rsrc(r(a))}$endl"
179179
}
180180

181181
def twoAddr[O]
182182
( a: O, indent: String)
183-
( d: O => Register,
184-
r: O => Dest | Constant
183+
( d: a.type => Register,
184+
r: a.type => Dest | Constant
185185
): String = {
186186
val name = a.getClass.getSimpleName.toLowerCase
187187
s"${indent}$name ${registers(d(a))}, ${rsrc(r(a))}$endl"
@@ -190,9 +190,9 @@ object printMips {
190190
def threeAddr[O]
191191
( a: O,
192192
indent: String )
193-
( d: O => Register,
194-
l: O => Register,
195-
r: O => Src
193+
( d: a.type => Register,
194+
l: a.type => Register,
195+
r: a.type => Src
196196
): String = {
197197
val name = a.getClass.getSimpleName.toLowerCase
198198
s"${indent}$name ${registers(d(a))}, ${registers(l(a))}, ${rsrc(r(a))}$endl"

tests/pos/i3935.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
enum Foo3[T](x: T) {
2+
case Bar[S, T](y: T) extends Foo3[y.type](y)
3+
}
4+
5+
val foo: Foo3.Bar[Nothing, 3] = Foo3.Bar(3)
6+
val bar = foo
7+
8+
def baz[T](f: Foo3[T]): f.type = f
9+
10+
val qux = baz(bar) // existentials are back in Dotty?
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Nat._
2+
3+
inline def toIntMacro(inline nat: Nat): Int = ${ Macros.toIntImpl('nat) }
4+
inline def ZeroMacro: Zero.type = ${ Macros.natZero }
5+
transparent inline def toNatMacro(inline int: Int): Nat = ${ Macros.toNatImpl('int) }
6+
7+
object Macros:
8+
import quoted._
9+
10+
def toIntImpl(nat: Expr[Nat])(using QuoteContext): Expr[Int] =
11+
12+
def inner(nat: Expr[Nat], acc: Int): Int = nat match
13+
case '{ Succ($nat) } => inner(nat, acc + 1)
14+
case '{ Zero } => acc
15+
16+
Expr(inner(nat, 0))
17+
18+
def natZero(using QuoteContext): Expr[Nat.Zero.type] = '{Zero}
19+
20+
def toNatImpl(int: Expr[Int])(using QuoteContext): Expr[Nat] =
21+
22+
// it seems even with the bound that the arg will always widen to Expr[Nat] unless explicit
23+
24+
def inner[N <: Nat: Type](int: Int, acc: Expr[N]): Expr[Nat] = int match
25+
case 0 => acc
26+
case n => inner[Succ[N]](n - 1, '{Succ($acc)})
27+
28+
val Const(i) = int
29+
require(i >= 0)
30+
inner[Zero.type](i, '{Zero})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
enum Nat:
2+
case Zero
3+
case Succ[N <: Nat](n: N)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Nat._
2+
3+
@main def Test: Unit =
4+
assert(toIntMacro(Succ(Succ(Succ(Zero)))) == 3)
5+
assert(toNatMacro(3) == Succ(Succ(Succ(Zero))))
6+
val zero: Zero.type = ZeroMacro
7+
assert(zero == Zero)
8+
assert(toIntMacro(toNatMacro(3)) == 3)
9+
val n: Succ[Succ[Succ[Zero.type]]] = toNatMacro(3)

tests/run-macros/i8007.check

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ true
1111

1212
true
1313

14+
true
15+
1416
false
1517

tests/run-macros/i8007/Macro_3.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ object Eq {
7373
}
7474

7575
object Macro3 {
76-
extension [T](x: =>T) inline def === (y: =>T)(using eq: Eq[T]): Boolean = eq.eqv(x, y)
76+
extension [T](inline x: T) inline def === (inline y: T)(using eq: Eq[T]): Boolean = eq.eqv(x, y)
7777

7878
implicit inline def eqGen[T]: Eq[T] = ${ Eq.derived[T] }
79-
}
79+
}

tests/run-macros/i8007/Test_4.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import Macro3.eqGen
66
case class Person(name: String, age: Int)
77

88
enum Opt[+T] {
9-
case Sm[T](t: T) extends Opt[T]
9+
case Sm(t: T)
10+
case Nn
11+
}
12+
13+
enum OptInv[+T] {
14+
case Sm[T](t: T) extends OptInv[T]
1015
case Nn
1116
}
1217

@@ -34,6 +39,10 @@ enum Opt[+T] {
3439
println(t5) // true
3540
println
3641

42+
val t5_2 = OptInv.Sm[Int](23) === OptInv.Sm(23) // invariant case will instantiate T to OptInv[Any]
43+
println(t5) // true
44+
println
45+
3746
val t6 = Sm(Person("Test", 23)) === Sm(Person("Test", 23))
3847
println(t6) // true
3948
println

tests/run/enums-precise.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
enum NonEmptyList[+T]:
2+
case Many[+U](head: U, tail: NonEmptyList[U]) extends NonEmptyList[U]
3+
case One [+U](value: U) extends NonEmptyList[U]
4+
5+
enum Ast:
6+
case Binding(name: String, tpe: String)
7+
case Lambda(args: NonEmptyList[Binding], rhs: Ast) // reference to another case of the enum
8+
case Ident(name: String)
9+
case Apply(fn: Ast, args: NonEmptyList[Ast])
10+
11+
import NonEmptyList._
12+
import Ast._
13+
14+
// This example showcases the widening when inferring enum case types.
15+
// With scala 2 case class hierarchies, if One.apply(1) returns One[Int] and Many.apply(2, One(3)) returns Many[Int]
16+
// then the `foldRight` expression below would complain that Many[Binding] is not One[Binding]. With Scala 3 enums,
17+
// .apply on the companion returns the precise class, but type inference will widen to NonEmptyList[Binding] unless
18+
// the precise class is expected.
19+
def Bindings(arg: (String, String), args: (String, String)*): NonEmptyList[Binding] =
20+
def Bind(arg: (String, String)): Binding =
21+
val (name, tpe) = arg
22+
Binding(name, tpe)
23+
24+
args.foldRight(One[Binding](Bind(arg)))((arg, acc) => Many(Bind(arg), acc))
25+
26+
@main def Test: Unit =
27+
val OneOfOne: One[1] = One[1](1)
28+
val True = Lambda(Bindings("x" -> "T", "y" -> "T"), Ident("x"))
29+
val Const = Lambda(One(Binding("x", "T")), Lambda(One(Binding("y", "U")), Ident("x"))) // precise type is forwarded
30+
31+
assert(OneOfOne.value == 1)

0 commit comments

Comments
 (0)