Skip to content

Commit 3a35742

Browse files
committed
Tests
1 parent bdcf8a4 commit 3a35742

15 files changed

+579
-1
lines changed

tests/neg/aliasing-subtypes.scala

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
object Test {
2+
3+
trait T {
4+
type A
5+
}
6+
7+
class C extends T { this: m.type => // error: cannot instantiate
8+
type A >: Int | Test.A <: Int & Test.A
9+
10+
def reveal(x: A): Int = x
11+
def inject(x: Int): A = x
12+
13+
var a: A = ???
14+
x = a // OK!
15+
a = x // OK!
16+
}
17+
18+
val m: T = new C
19+
type A = m.A
20+
21+
var x: A = ???
22+
}

tests/neg/opaque-id.scala

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
object Test {
2+
opaque type T[X] = X
3+
object T {
4+
def f(x: T[Int]): Int = x // OK
5+
def g(x: Int): T[Int] = x // OK
6+
}
7+
val x: T[Int] = 2 // error
8+
val y: Int = x // error
9+
}

tests/neg/opaque-self-encoding.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
trait TS { type TX = Int }
21
trait TT { self: { type TX = Int } =>
32
type TX
43
def lift(x: Int): TX = x

tests/neg/opaque.scala

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
object opaquetypes {
2+
3+
opaque val x: Int = 1 // error
4+
5+
opaque class Foo // error
6+
7+
opaque type T // error
8+
9+
opaque type U <: String // error
10+
11+
opaque type Fix[F[_]] = F[Fix[F]] // error: cyclic // error
12+
13+
opaque type O = String
14+
15+
val s: O = "" // error
16+
17+
object O {
18+
val s: O = "" // should be OK
19+
}
20+
21+
}
22+
23+
object logs {
24+
opaque type Logarithm = Double
25+
26+
object Logarithm {
27+
28+
// These are the ways to lift to the logarithm type
29+
def apply(d: Double): Logarithm = math.log(d)
30+
31+
def safe(d: Double): Option[Logarithm] =
32+
if (d > 0.0) Some(math.log(d)) else None
33+
34+
// This is the first way to unlift the logarithm type
35+
def exponent(l: Logarithm): Double = l
36+
37+
// Extension methods define opaque types' public APIs
38+
implicit class LogarithmOps(val `this`: Logarithm) extends AnyVal {
39+
// This is the second way to unlift the logarithm type
40+
def toDouble: Double = math.exp(`this`)
41+
def +(that: Logarithm): Logarithm = Logarithm(math.exp(`this`) + math.exp(that))
42+
def *(that: Logarithm): Logarithm = Logarithm(`this` + that)
43+
}
44+
}
45+
46+
val l = Logarithm(2.0)
47+
val d: Double = l // error: found: Logarithm, required: Double
48+
val l2: Logarithm = 1.0 // error: found: Double, required: Logarithm
49+
l * 2 // error: found: Int(2), required: Logarithm
50+
l / l2 // error: `/` is not a member fo Logarithm
51+
}

tests/neg/tagging.scala

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import scala.reflect.ClassTag
2+
object tagging {
3+
4+
// Tagged[S, T] means that S is tagged with T
5+
opaque type Tagged[X, Y] = X
6+
7+
object Tagged {
8+
def tag[S, T](s: S): Tagged[S, T] = (s: S)
9+
def untag[S, T](st: Tagged[S, T]): S = st
10+
11+
def tags[F[_], S, T](fs: F[S]): F[Tagged[S, T]] = fs
12+
def untags[F[_], S, T](fst: F[Tagged[S, T]]): F[S] = fst
13+
14+
implicit def taggedClassTag[S, T](implicit ct: ClassTag[S]): ClassTag[Tagged[S, T]] =
15+
ct
16+
}
17+
18+
type @@[S, T] = Tagged[S, T]
19+
20+
implicit class UntagOps[S, T](st: S @@ T) extends AnyVal {
21+
def untag: S = Tagged.untag(st)
22+
}
23+
24+
implicit class UntagsOps[F[_], S, T](fs: F[S @@ T]) extends AnyVal {
25+
def untags: F[S] = Tagged.untags(fs)
26+
}
27+
28+
implicit class TagOps[S](s: S) extends AnyVal {
29+
def tag[T]: S @@ T = Tagged.tag(s)
30+
}
31+
32+
implicit class TagsOps[F[_], S](fs: F[S]) extends AnyVal {
33+
def tags[T]: F[S @@ T] = Tagged.tags(fs)
34+
}
35+
36+
trait Meter
37+
trait Foot
38+
trait Fathom
39+
40+
val x: Double @@ Meter = (1e7).tag[Meter]
41+
val y: Double @@ Foot = (123.0).tag[Foot]
42+
val xs: Array[Double @@ Meter] = Array(1.0, 2.0, 3.0).tags[Meter]
43+
44+
val o: Ordering[Double] = implicitly
45+
val om: Ordering[Double @@ Meter] = o.tags[Meter]
46+
om.compare(x, x) // 0
47+
om.compare(x, y) // error
48+
xs.min(om) // 1.0
49+
xs.min(o) // error
50+
51+
// uses ClassTag[Double] via 'Tagged.taggedClassTag'.
52+
val ys = new Array[Double @@ Foot](20)
53+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
object opaquetypes {
2+
3+
opaque type Fix[F[_]] = F[Fix2[F]]
4+
5+
opaque type Fix2[F[_]] = Fix[F]
6+
7+
object Fix {
8+
def unfold[F[_]](x: Fix[F]): F[Fix]
9+
}
10+
11+
object Fix2 {
12+
def unfold[F[_]](x: Fix2[F]: Fix[F] = x
13+
def fold[F[_]](x: Fix[F]: Fix2[F] = x
14+
}
15+
16+
}

tests/pos/opaque-aliasing.scala

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
object Test {
2+
3+
opaque type A = Int
4+
type AA = A
5+
6+
var a: A = ???
7+
var aa: AA = ???
8+
9+
object A {
10+
val x: A = a
11+
a = x
12+
val y: A = aa
13+
aa = y
14+
15+
type BB = A
16+
val z1: BB = a
17+
val z2: BB = aa
18+
a = z1
19+
aa = z2
20+
}
21+
}
22+
object Test2 {
23+
24+
opaque type A[X] = X
25+
type AA[X] = A[X]
26+
27+
var a: A[Int] = ???
28+
var aa: AA[Int] = ???
29+
30+
object A {
31+
val x: A[Int] = a
32+
a = x
33+
val y: A[Int] = aa
34+
aa = y
35+
36+
type BB[X] = A[X]
37+
val z1: BB[Int] = a
38+
val z2: BB[Int] = aa
39+
a = z1
40+
aa = z2
41+
}
42+
}

tests/pos/opaque-digits.scala

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
object pkg {
2+
3+
import Character.{isAlphabetic, isDigit}
4+
5+
class Alphabetic private[pkg] (val value: String) extends AnyVal
6+
7+
object Alphabetic {
8+
def fromString(s: String): Option[Alphabetic] =
9+
if (s.forall(isAlphabetic(_))) Some(new Alphabetic(s))
10+
else None
11+
}
12+
13+
opaque type Digits = String
14+
15+
object Digits {
16+
def fromString(s: String): Option[Digits] =
17+
if (s.forall(isDigit(_))) Some(s)
18+
else None
19+
20+
def asString(d: Digits): String = d
21+
}
22+
}

tests/pos/opaque-groups-params.scala

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package object groups {
2+
trait Semigroup[A] {
3+
def combine(x: A, y: A): A
4+
}
5+
6+
object Semigroup {
7+
def instance[A](f: (A, A) => A): Semigroup[A] =
8+
new Semigroup[A] {
9+
def combine(x: A, y: A): A = f(x, y)
10+
}
11+
}
12+
13+
type Id[A] = A
14+
15+
trait Wrapping[F[_]] {
16+
def wraps[G[_], A](ga: G[A]): G[F[A]]
17+
def unwrap[G[_], A](ga: G[F[A]]): G[A]
18+
}
19+
20+
abstract class Wrapper[F[_]] { self =>
21+
def wraps[G[_], A](ga: G[A]): G[F[A]]
22+
def unwrap[G[_], A](gfa: G[F[A]]): G[A]
23+
24+
final def apply[A](a: A): F[A] = wraps[Id, A](a)
25+
26+
implicit object WrapperWrapping extends Wrapping[F] {
27+
def wraps[G[_], A](ga: G[A]): G[F[A]] = self.wraps(ga)
28+
def unwrap[G[_], A](ga: G[F[A]]): G[A] = self.unwrap(ga)
29+
}
30+
}
31+
32+
// The following definition does not typecheck since the `First`
33+
// parent argument refers to the outer `First`, not the synthetic inner one.
34+
// See pos/opaque-groups.scala for a version that copmpiles.
35+
opaque type First[A] = A
36+
object First extends Wrapper[First] { // error: object creation impossible
37+
def wraps[G[_], A](ga: G[A]): G[First[A]] = ga // error: overriding
38+
def unwrap[G[_], A](gfa: G[First[A]]): G[A] = gfa
39+
implicit def firstSemigroup[A]: Semigroup[First[A]] =
40+
Semigroup.instance((x, y) => x)
41+
}
42+
43+
opaque type Last[A] = A
44+
object Last extends Wrapper[Last] { // error: object creation impossible
45+
def wraps[G[_], A](ga: G[A]): G[Last[A]] = ga // error: overriding
46+
def unwrap[G[_], A](gfa: G[Last[A]]): G[A] = gfa
47+
implicit def lastSemigroup[A]: Semigroup[Last[A]] =
48+
Semigroup.instance((x, y) => y)
49+
}
50+
}

tests/pos/opaque-groups.scala

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package object groups {
2+
trait Semigroup[A] {
3+
def combine(x: A, y: A): A
4+
}
5+
6+
object Semigroup {
7+
def instance[A](f: (A, A) => A): Semigroup[A] =
8+
new Semigroup[A] {
9+
def combine(x: A, y: A): A = f(x, y)
10+
}
11+
}
12+
13+
type Id[A] = A
14+
15+
trait Wrapping[F[_]] {
16+
def wraps[G[_], A](ga: G[A]): G[F[A]]
17+
def unwrap[G[_], A](ga: G[F[A]]): G[A]
18+
}
19+
20+
abstract class Wrapper { self =>
21+
type F[_]
22+
def wraps[G[_], A](ga: G[A]): G[F[A]]
23+
def unwrap[G[_], A](gfa: G[F[A]]): G[A]
24+
25+
final def apply[A](a: A): F[A] = wraps[Id, A](a)
26+
27+
implicit object WrapperWrapping extends Wrapping[F] {
28+
def wraps[G[_], A](ga: G[A]): G[F[A]] = self.wraps(ga)
29+
def unwrap[G[_], A](ga: G[F[A]]): G[A] = self.unwrap(ga)
30+
}
31+
}
32+
33+
opaque type First[A] = A
34+
object First extends Wrapper {
35+
type F = First
36+
def wraps[G[_], A](ga: G[A]): G[First[A]] = ga
37+
def unwrap[G[_], A](gfa: G[First[A]]): G[A] = gfa
38+
implicit def firstSemigroup[A]: Semigroup[First[A]] =
39+
Semigroup.instance((x, y) => x)
40+
}
41+
42+
opaque type Last[A] = A
43+
object Last extends Wrapper {
44+
type F = Last
45+
def wraps[G[_], A](ga: G[A]): G[Last[A]] = ga
46+
def unwrap[G[_], A](gfa: G[Last[A]]): G[A] = gfa
47+
implicit def lastSemigroup[A]: Semigroup[Last[A]] =
48+
Semigroup.instance((x, y) => y)
49+
}
50+
51+
opaque type Min[A] = A
52+
object Min extends Wrapper {
53+
type F = Min
54+
def wraps[G[_], A](ga: G[A]): G[Min[A]] = ga
55+
def unwrap[G[_], A](gfa: G[Min[A]]): G[A] = gfa
56+
implicit def minSemigroup[A](implicit o: Ordering[A]): Semigroup[Min[A]] =
57+
Semigroup.instance(o.min)
58+
}
59+
60+
opaque type Max[A] = A
61+
object Max extends Wrapper {
62+
type F = Max
63+
def wraps[G[_], A](ga: G[A]): G[Max[A]] = ga
64+
def unwrap[G[_], A](gfa: G[Max[A]]): G[A] = gfa
65+
implicit def maxSemigroup[A](implicit o: Ordering[A]): Semigroup[Max[A]] =
66+
Semigroup.instance(o.max)
67+
}
68+
69+
opaque type Plus[A] = A
70+
object Plus extends Wrapper {
71+
type F = Plus
72+
def wraps[G[_], A](ga: G[A]): G[Plus[A]] = ga
73+
def unwrap[G[_], A](gfa: G[Plus[A]]): G[A] = gfa
74+
implicit def plusSemigroup[A](implicit n: Numeric[A]): Semigroup[Plus[A]] =
75+
Semigroup.instance(n.plus)
76+
}
77+
78+
opaque type Times[A] = A
79+
object Times extends Wrapper {
80+
type F = Times
81+
def wraps[G[_], A](ga: G[A]): G[Times[A]] = ga
82+
def unwrap[G[_], A](gfa: G[Times[A]]): G[A] = gfa
83+
implicit def timesSemigroup[A](implicit n: Numeric[A]): Semigroup[Times[A]] =
84+
Semigroup.instance(n.times)
85+
}
86+
87+
opaque type Reversed[A] = A
88+
object Reversed extends Wrapper {
89+
type F = Reversed
90+
def wraps[G[_], A](ga: G[A]): G[Reversed[A]] = ga
91+
def unwrap[G[_], A](gfa: G[Reversed[A]]): G[A] = gfa
92+
implicit def reversedOrdering[A](implicit o: Ordering[A]): Ordering[Reversed[A]] =
93+
o.reverse
94+
}
95+
96+
opaque type Unordered[A] = A
97+
object Unordered extends Wrapper {
98+
type F = Unordered
99+
def wraps[G[_], A](ga: G[A]): G[Unordered[A]] = ga
100+
def unwrap[G[_], A](gfa: G[Unordered[A]]): G[A] = gfa
101+
implicit def unorderedOrdering[A]: Ordering[Unordered[A]] =
102+
Ordering.by(_ => ())
103+
}
104+
}

0 commit comments

Comments
 (0)