Skip to content

Commit 68cf530

Browse files
committed
Add Constant type
Constant is s subtype of Singleton types that only allow constants for which the value is known at compile time.
1 parent 25b15bf commit 68cf530

File tree

5 files changed

+67
-0
lines changed

5 files changed

+67
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,13 @@ class Definitions {
410410
List(AnyClass.typeRef), EmptyScope)
411411
lazy val SingletonType: TypeRef = SingletonClass.typeRef
412412

413+
lazy val ConstantClass: ClassSymbol =
414+
// TODO needs to be synthetic as is SingletonClass?
415+
enterCompleteClassSymbol(
416+
ScalaPackageClass, tpnme.Constant, PureInterfaceCreationFlags | Final,
417+
List(SingletonType), EmptyScope)
418+
lazy val ConstantType: TypeRef = ConstantClass.typeRef
419+
413420
lazy val SeqType: TypeRef =
414421
if (isNewCollections) ctx.requiredClassRef("scala.collection.immutable.Seq")
415422
else ctx.requiredClassRef("scala.collection.Seq")
@@ -1209,6 +1216,7 @@ class Definitions {
12091216
NullClass,
12101217
NothingClass,
12111218
SingletonClass,
1219+
ConstantClass,
12121220
EqualsPatternClass)
12131221

12141222
lazy val syntheticCoreClasses = syntheticScalaClasses ++ List(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ class TypeComparer(initctx: Context) extends DotClass with ConstraintHandling {
393393
if (base.exists && base.ne(tp1))
394394
return isSubType(base, tp2, if (tp1.isRef(cls2)) approx else approx.addLow)
395395
if (cls2 == defn.SingletonClass && tp1.isStable) return true
396+
if (cls2 == defn.ConstantClass && tp1.isConstant) return true
396397
}
397398
else if (cls2.is(JavaDefined)) {
398399
// If `cls2` is parameterized, we are seeing a raw type, so we need to compare only the symbol

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ object Types {
158158
case _ => false
159159
}
160160

161+
/** Does this type denote a constant type */
162+
final def isConstant(implicit ctx: Context): Boolean = stripTypeVar match {
163+
case _: ConstantType => true
164+
case tp: ExprType => tp.resultType.isConstant
165+
case tp: AnnotatedType => tp.parent.isConstant
166+
case _ => false
167+
}
168+
161169
/** Is this type a (possibly refined or applied or aliased) type reference
162170
* to the given type symbol?
163171
* @sym The symbol to compare to. It must be a class symbol or abstract type.

tests/neg/constant-types.scala

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
object Constants {
2+
3+
def f[C <: Constant](c: C): Unit = ()
4+
val x = 1
5+
f(x) // error
6+
7+
def fBool(c: Boolean & Constant): Unit = ()
8+
val b = true
9+
fBool(b) // error
10+
11+
12+
def fInt(c: Int & Constant): Unit = ()
13+
val i = 3
14+
fInt(i) // error
15+
16+
def fChar(c: Char & Constant): Unit = ()
17+
val c = 'c'
18+
fChar(c) // error
19+
20+
}

tests/pos/constant-types.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
object Constants {
2+
3+
def f[C <: Constant](c: C): Unit = ()
4+
f(true)
5+
f(1)
6+
f(2L)
7+
f(1.2f)
8+
f(1.2d)
9+
f('a')
10+
f("abc")
11+
12+
def fBool(c: Boolean & Constant): Unit = ()
13+
fBool(true)
14+
fBool(false)
15+
transparent def bb: Boolean = true
16+
fBool(bb)
17+
18+
def fInt(c: Int & Constant): Unit = ()
19+
fInt(1)
20+
fInt(2)
21+
transparent def ii: Int = 4
22+
fInt(ii)
23+
24+
def fChar(c: Char & Constant): Unit = ()
25+
fChar('a')
26+
fChar('b')
27+
transparent def cc: Char = 'd'
28+
fChar(cc)
29+
30+
}

0 commit comments

Comments
 (0)