Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 1aed2bb

Browse files
author
Fulvio Valente
committed
Allocate only one Label per tag type, and only one default Label.
This comes at the cost of a self type error when attempting to use a non-case object as a tag.
1 parent d2f2d84 commit 1aed2bb

2 files changed

Lines changed: 20 additions & 13 deletions

File tree

src/main/scala/Label.scala

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,23 @@ trait Label[A] {
66
}
77

88
object Label {
9-
private[id] def default[A] = new Label[A] {
10-
def label = ""
9+
private val defaultLabel: Label[Nothing] = new Label[Nothing] {
10+
val label = ""
1111
}
1212

13+
private[id] def default[A]: Label[A] = defaultLabel.asInstanceOf[Label[A]]
14+
1315
private[id] sealed trait LabelDefinitionConflict
1416

15-
trait MakeLabel { self =>
17+
trait MakeLabel { self: Product =>
1618
// See eidos.id.Format.UUID for an explanation of this
1719
// format: off
1820
final def `"In Eidos, you can only extend one of MakeLabel or CustomLabel"`
1921
: LabelDefinitionConflict = null
2022

21-
implicit final def l(implicit ev: self.type <:< Product): Label[this.type] =
22-
new Label[this.type] {
23-
def label = self.productPrefix
24-
}
23+
implicit final val l: Label[this.type] = new Label[this.type] {
24+
val label = self.productPrefix
25+
}
2526
}
2627

2728
trait CustomLabel {
@@ -30,10 +31,10 @@ object Label {
3031
// format: on
3132
def label: String
3233

33-
private def customLabel = label
34+
private val customLabel = label
3435

35-
implicit final def l: Label[this.type] = new Label[this.type] {
36-
def label = customLabel
36+
implicit final val l: Label[this.type] = new Label[this.type] {
37+
val label = customLabel
3738
}
3839
}
3940
}

src/test/scala/EidosSpec.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,8 @@ class EidosSpec extends Specification with TypecheckMatchers with ScalaCheck {
8383
"Tag" should {
8484
"be case objects" in {
8585
trait Trait
86-
87-
// MakeLabel is the reason why "case" is required
88-
object Object extends MakeLabel
86+
class Class
87+
object Object
8988
type Object = Object.type
9089

9190
case object CaseObject
@@ -96,8 +95,15 @@ class EidosSpec extends Specification with TypecheckMatchers with ScalaCheck {
9695

9796
// format: off
9897
{ typecheck("""Id.of[Trait]("")""") must failWith(errorMessage("Trait")) }
98+
{ typecheck("""Id.of[Class]("")""") must failWith(errorMessage("Class")) }
9999
{ typecheck("""Id.of[Object]("")""") must failWith(errorMessage("Object")) }
100100
{ typecheck("""Id.of[CaseObject]("")""") must succeed }
101+
102+
// Non-case objects will fail before they are used in an Id.of call, but
103+
// with a more vague error because MakeLabel needs access to productPrefix
104+
// sooner in order to avoid allocating duplicate labels
105+
{ typecheck("""object Object extends MakeLabel""") must failWith(
106+
"self-type Object.type does not conform to eidos.MakeLabel's selftype") }
101107
// format: on
102108
}
103109
}

0 commit comments

Comments
 (0)