Skip to content

Commit 7ed8464

Browse files
committed
Treat common traits and type classes alike
1 parent 6eede1d commit 7ed8464

File tree

1 file changed

+85
-82
lines changed

1 file changed

+85
-82
lines changed

tests/pos/typeclass-encoding3.scala

Lines changed: 85 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,59 @@
11
/*
22
[T : M] = [T] ... (implicit ev: Injectable[T, M]) if M is a normal trait
3-
= [T] ... (implicit ev: M.Impl[T]) if M is an extension trait
3+
= [T] ... (implicit ev: M.Impl[T]) if M is a trait with common members
44
55
M.Impl[T] = Common { type This = T }
66
M.Impl[T[_]] = Common { type This = T }
77
...
88
9-
Extension traits of different kinds cannot be mixed.
10-
Extension traits can extend normal traits.
11-
Extension traits can extend extension traits, but only with the same type parameters
12-
Normal traits cannot extend extension traits.
9+
- An extension trait is a trait that uses This or a trait inheriting an extension trait.
10+
- The kind of `This` is the kind of the extension trait.
11+
- Extension traits of different kinds cannot inherit each other and cannot be mixed using `with`.
12+
- A class implementing extension traits fixes the maning of `This`.
13+
- Such a class cannot be extended by classes that implement other extension traits.
1314
*/
1415
object runtime {
1516

16-
trait TypeClass {
17-
/** The companion object of the implementing type */
18-
val `common`: TypeClass.Common
19-
}
20-
2117
trait Injector {
18+
/** The implementating type */
2219
type This
20+
21+
/** The implemented trait */
2322
type Instance
23+
24+
/** The implementation via type `T` for this trait */
2425
implicit def inject(x: This): Instance
2526
}
2627

28+
trait IdentityInjector extends Injector {
29+
def inject(x: This): Instance = x.asInstanceOf
30+
}
31+
32+
trait SubtypeInjector[T] extends Injector {
33+
type This = T
34+
type Instance = T
35+
def inject(x: T): T = x
36+
}
37+
2738
type Injectable[T, +U] = Injector { type This = T; type Instance <: U }
2839

29-
implicit def selfInject[U, T <: U]: Injectable[T, U] =
30-
new Injector{
31-
type This = T
32-
type Instance = U
33-
implicit def inject(x: This): Instance = x
34-
}
40+
def selfInject[U, T <: U]: Injectable[T, U] = new SubtypeInjector[T] {}
41+
42+
trait TypeClass {
43+
/** The companion object of the implementing type */
44+
val `common`: TypeClass.Common
45+
}
3546

3647
object TypeClass {
3748

3849
/** Base trait for companion objects of all implementations of this typeclass */
3950
trait Common extends Injector { self =>
40-
41-
/** The implementating type */
42-
type This
43-
4451
/** The implemented typeclass */
45-
type Instance <: TypeClass { val `common`: self.type }
46-
47-
/** Create instances of typeclass from instances of the implementing type */
48-
implicit def inject(x: This): Instance
52+
type Instance <: TypeClass
4953
}
5054

5155
/** Base trait for the companion objects of type classes themselves */
5256
trait Companion {
53-
5457
/** The `Common` base trait defining common (static) operations of this typeclass */
5558
type Common <: TypeClass.Common
5659

@@ -62,9 +65,8 @@ object runtime {
6265
}
6366
}
6467

65-
implicit def injectTypeClass[From, U](x: From)
66-
(implicit ev: Injector { type This = From }): ev.Instance =
67-
ev.inject(x)
68+
implicit def applyInjector[From, U](x: From)(implicit ev: Injector { type This = From }): ev.Instance =
69+
ev.inject(x)
6870
}
6971

7072
/** 0. All combinations of
@@ -235,13 +237,14 @@ object hasLength {
235237
def length: Int
236238
}
237239

238-
trait HasBoundedLength extends HasLength {
240+
trait HasBoundedLength extends HasLength with TypeClass {
239241
val `common`: HasBoundedLength.Common
240242
import `common`._
241243
}
242244

243-
object HasBoundedLength {
244-
trait Common {
245+
object HasBoundedLength extends TypeClass.Companion {
246+
trait Common extends TypeClass.Common {
247+
type Instance <: HasBoundedLength
245248
def limit: Int
246249
}
247250
}
@@ -252,7 +255,7 @@ object hasLength {
252255
}
253256

254257
object HasBoundedLengthX extends TypeClass.Companion {
255-
trait Common extends HasBoundedLength.Common with TypeClass.Common { self =>
258+
trait Common extends HasBoundedLength.Common with TypeClass.Common { self =>
256259
type Instance <: HasBoundedLengthX { val `common`: self.type }
257260
def limit: Int
258261
def longest: This
@@ -271,50 +274,46 @@ object hasLength {
271274
val `common`: C2Common = C2
272275
import `common`._
273276
}
274-
class C2Common extends HasBoundedLength.Common {
277+
abstract class C2Common extends HasBoundedLength.Common {
275278
def limit = 100
276279
}
277-
object C2 extends C2Common
280+
object C2 extends C2Common with SubtypeInjector[C2]
278281

279282
class CG2[T](xs: Array[T]) extends CG1(xs) with HasBoundedLength {
280283
val `common`: CG2Common[T] = CG2[T]
281284
import `common`._
282285
}
283-
class CG2Common[T] extends HasBoundedLength.Common {
286+
abstract class CG2Common[T] extends HasBoundedLength.Common {
284287
def limit = 100
285288
}
286289
object CG2 {
287-
def apply[T] = new CG2Common[T]
290+
def apply[T] = new CG2Common[T] with SubtypeInjector[CG2[T]]
288291
}
289292

290293
class C3(xs: Array[Int]) extends C2(xs) with HasBoundedLengthX {
291294
override val `common`: C3Common = C3
292295
import `common`._
293296
}
294-
class C3Common extends C2Common with HasBoundedLengthX.Common { self =>
297+
abstract class C3Common extends C2Common with HasBoundedLengthX.Common { self =>
295298
type This = C3
296299
type Instance = C3 { val `common`: self.type }
297-
def inject(x: This): Instance = x.asInstanceOf
298300

299301
def longest = new C3(new Array[Int](limit))
300302
}
301-
implicit object C3 extends C3Common
303+
object C3 extends C3Common with IdentityInjector
302304

303305
class CG3[T](xs: Array[T])(implicit tag: ClassTag[T]) extends CG2(xs) with HasBoundedLengthX {
304306
override val `common`: CG3Common[T] = CG3[T]
305307
import `common`._
306308
}
307-
class CG3Common[T](implicit tag: ClassTag[T]) extends CG2Common[T] with HasBoundedLengthX.Common { self =>
309+
abstract class CG3Common[T](implicit tag: ClassTag[T]) extends CG2Common[T] with HasBoundedLengthX.Common { self =>
308310
type This = CG3[T]
309311
type Instance = CG3[T] { val `common`: self.type }
310-
def inject(x: This): Instance = x.asInstanceOf
311-
312312
def longest = new CG3(new Array[T](limit))
313313
}
314314
object CG3 {
315-
def apply[T](implicit tag: ClassTag[T]) = new CG3Common[T]
315+
def apply[T](implicit tag: ClassTag[T]) = new CG3Common[T] with IdentityInjector
316316
}
317-
implicit def CG3Common[T](implicit tag: ClassTag[T]): CG3Common[T] = CG3[T]
318317

319318
class D1(val xs: Array[Int])
320319
class DG1[T](val xs: Array[T])
@@ -342,7 +341,7 @@ object hasLength {
342341
}
343342
implicit def DGHasLength[T]: DGHasLength[T] = new DGHasLength
344343

345-
implicit object DHasBoundedLength extends Injector with HasBoundedLength.Common { self =>
344+
object DHasBoundedLength extends HasBoundedLength.Common { self =>
346345
type This = D2
347346
type Instance = HasBoundedLength
348347
def inject(x: D2) = new HasBoundedLength {
@@ -353,7 +352,7 @@ object hasLength {
353352
def limit = 100
354353
}
355354

356-
class DGHasBoundedLength[T] extends Injector with HasBoundedLength.Common { self =>
355+
class DGHasBoundedLength[T] extends HasBoundedLength.Common { self =>
357356
type This = DG2[T]
358357
type Instance = HasBoundedLength
359358
def inject(x: DG2[T]) = new HasBoundedLength {
@@ -395,8 +394,8 @@ object hasLength {
395394
def lengthOK[T](x: T)(implicit ev: Injectable[T, HasBoundedLength]) =
396395
x.length < x.common.limit
397396

398-
def lengthOKX[T](x: T)(implicit ev: HasBoundedLengthX.Impl[T]) =
399-
x.length < HasBoundedLengthX.impl[T].limit
397+
def lengthOKX[T](x: T)(implicit ev: HasBoundedLength.Impl[T]) =
398+
x.length < HasBoundedLength.impl[T].limit
400399

401400
def longestLengthOK[T](implicit ev: HasBoundedLengthX.Impl[T], tag: ClassTag[T]) = {
402401
val impl = HasBoundedLengthX.impl[T]
@@ -406,7 +405,11 @@ object hasLength {
406405
def length1(x: HasLength) = x.length
407406
def lengthOK1(x: HasBoundedLength) = x.length < x.common.limit
408407

408+
def ctag[T](implicit tag: ClassTag[T]) = tag
409+
409410
val xs = Array(1, 2, 3)
411+
val intTag = implicitly[ClassTag[Int]]
412+
410413
val c1 = new C1(xs)
411414
val cg1 = new CG1(xs)
412415
val c2 = new C2(xs)
@@ -421,38 +424,38 @@ object hasLength {
421424
val d3 = new D3(xs)
422425
val dg3 = new DG3(xs)
423426

424-
length(c1)
425-
length(cg1)
426-
length(c2)
427-
length(cg2)
428-
length(c3)(selfInject)
429-
length(cg3)(selfInject)
430-
431-
length(d1)
432-
length(dg1)
433-
length(d2)
434-
length(dg2)
435-
length(d3)
436-
length(dg3)
437-
438-
lengthOK(c2)
439-
lengthOK(cg2)
440-
lengthOK(c3)(selfInject)
441-
lengthOK(cg3)(selfInject)
442-
443-
lengthOK(d2)
444-
lengthOK(dg2)
445-
lengthOK(d3)
446-
lengthOK(dg3)
447-
448-
lengthOKX(c3)
449-
lengthOKX(cg3)
450-
451-
lengthOKX(d3)
452-
lengthOKX(dg3)
453-
454-
longestLengthOK[C3]
455-
longestLengthOK[CG3[Int]]
427+
length(c1)(selfInject)
428+
length(cg1)(selfInject)
429+
length(c2)(C2)
430+
length(cg2)(CG2[Int])
431+
length(c3)(C3)
432+
length(cg3)(CG3[Int])
433+
434+
length(d1)(DHasLength)
435+
length(dg1)(DGHasLength[Int])
436+
length(d2)(DHasBoundedLength)
437+
length(dg2)(DGHasBoundedLength[Int])
438+
length(d3)(DHasBoundedLengthX)
439+
length(dg3)(DGHasBoundedLengthX[Int])
440+
441+
lengthOK(c2)(C2)
442+
lengthOK(cg2)(CG2[Int])
443+
lengthOK(c3)(C3)
444+
lengthOK(cg3)(CG3[Int])
445+
446+
lengthOK(d2)(DHasBoundedLength)
447+
lengthOK(dg2)(DGHasBoundedLength[Int])
448+
lengthOK(d3)(DHasBoundedLengthX)
449+
lengthOK(dg3)(DGHasBoundedLengthX[Int])
450+
451+
lengthOKX(c3)(C3)
452+
lengthOKX(cg3)(CG3[Int])
453+
454+
lengthOKX(d3)(DHasBoundedLengthX)
455+
lengthOKX(dg3)(DGHasBoundedLengthX[Int])
456+
457+
longestLengthOK[C3](C3, ctag[C3])
458+
longestLengthOK[CG3[Int]](CG3[Int], ctag[CG3[Int]])
456459
longestLengthOK[D3]
457460
longestLengthOK[DG3[Int]]
458461

@@ -716,7 +719,7 @@ object runtime1 {
716719
object TypeClass1 {
717720
trait Common { self =>
718721
type This[X]
719-
type Instance[X] <: TypeClass1[X] { val `common`: self.type }
722+
type Instance[X] <: TypeClass1[X]
720723
def inject[A](x: This[A]): Instance[A]
721724
}
722725

@@ -727,7 +730,7 @@ object runtime1 {
727730
}
728731
}
729732

730-
implicit def decorateTypeClass1[A, From[_]](x: From[A])
733+
implicit def applyInjector1[A, From[_]](x: From[A])
731734
(implicit ev: TypeClass1.Common { type This = From }): ev.Instance[A] =
732735
ev.inject(x)
733736
}

0 commit comments

Comments
 (0)