aboutsummaryrefslogtreecommitdiff
path: root/compiler/src
diff options
context:
space:
mode:
authorliu fengyun <liufengyunchina@gmail.com>2016-11-07 23:57:06 +0100
committerliu fengyun <liu@fengy.me>2016-11-24 13:36:05 +0100
commitabb9aa802789e6b43ff07c45281eedbb09512585 (patch)
treef0c74d053602dd64f0489780726ee9ef9a5fe4c2 /compiler/src
parent8592af1c815c34078d89c08536addbe757550179 (diff)
downloaddotty-abb9aa802789e6b43ff07c45281eedbb09512585.tar.gz
dotty-abb9aa802789e6b43ff07c45281eedbb09512585.tar.bz2
dotty-abb9aa802789e6b43ff07c45281eedbb09512585.zip
fix #1642: disallow value classe wrapping value class
Diffstat (limited to 'compiler/src')
-rw-r--r--compiler/src/dotty/tools/dotc/core/TypeErasure.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala8
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ValueClasses.scala10
-rw-r--r--compiler/src/dotty/tools/dotc/typer/RefChecks.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala1
5 files changed, 16 insertions, 12 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index abbacee49..28dbed8f6 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -427,7 +427,7 @@ class TypeErasure(isJava: Boolean, semiEraseVCs: Boolean, isConstructor: Boolean
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type = {
val cls = tref.symbol.asClass
val underlying = underlyingOfValueClass(cls)
- if (underlying.exists) ErasedValueType(tref, valueErasure(underlying))
+ if (underlying.exists && !isCyclic(cls)) ErasedValueType(tref, valueErasure(underlying))
else NoType
}
diff --git a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala
index 5ae4e8a54..925ec08b2 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExtensionMethods.scala
@@ -135,14 +135,6 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful
// TODO: this is state and should be per-run
// todo: check that when transformation finished map is empty
- private def checkNonCyclic(pos: Position, seen: Set[Symbol], clazz: ClassSymbol)(implicit ctx: Context): Unit =
- if (seen contains clazz)
- ctx.error("value class may not unbox to itself", pos)
- else {
- val unboxed = underlyingOfValueClass(clazz).typeSymbol
- if (isDerivedValueClass(unboxed)) checkNonCyclic(pos, seen + clazz, unboxed.asClass)
- }
-
override def transformTemplate(tree: tpd.Template)(implicit ctx: Context, info: TransformerInfo): tpd.Tree = {
if (isDerivedValueClass(ctx.owner)) {
/* This is currently redundant since value classes may not
diff --git a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala
index 93005c57a..b16d05644 100644
--- a/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ValueClasses.scala
@@ -53,4 +53,14 @@ object ValueClasses {
def underlyingOfValueClass(d: ClassDenotation)(implicit ctx: Context): Type =
valueClassUnbox(d).info.resultType
+ /** Whether a value class wraps itself */
+ def isCyclic(cls: ClassSymbol)(implicit ctx: Context): Boolean = {
+ def recur(seen: Set[Symbol], clazz: ClassSymbol)(implicit ctx: Context): Boolean =
+ (seen contains clazz) || {
+ val unboxed = underlyingOfValueClass(clazz).typeSymbol
+ (isDerivedValueClass(unboxed)) && recur(seen + clazz, unboxed.asClass)
+ }
+
+ recur(Set[Symbol](), cls)
+ }
}
diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
index feeb80547..f9c9ddee4 100644
--- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -18,7 +18,7 @@ import config.{ScalaVersion, NoScalaVersion}
import Decorators._
import typer.ErrorReporting._
import DenotTransformers._
-import ValueClasses.isDerivedValueClass
+import ValueClasses.{isDerivedValueClass, isCyclic}
object RefChecks {
import tpd._
@@ -707,12 +707,15 @@ object RefChecks {
ctx.error("`abstract' modifier cannot be used with value classes", clazz.pos)
if (!clazz.isStatic)
ctx.error(s"value class may not be a ${if (clazz.owner.isTerm) "local class" else "member of another class"}", clazz.pos)
+ if (isCyclic(clazz.asClass))
+ ctx.error("value class cannot wrap itself", clazz.pos)
else {
- val clParamAccessors = clazz.asClass.paramAccessors.filter(sym => sym.isTerm && !sym.is(Method))
+ val clParamAccessors = clazz.asClass.paramAccessors.filter(_.isTerm)
clParamAccessors match {
case List(param) =>
if (param.is(Mutable))
ctx.error("value class parameter must not be a var", param.pos)
+
case _ =>
ctx.error("value class needs to have exactly one val parameter", clazz.pos)
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 34300a5e3..9d29c3a4e 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1270,7 +1270,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
cls, isRequired, cdef.pos)
}
-
// check value class constraints
RefChecks.checkDerivedValueClass(cls, body1)