diff options
author | liu fengyun <liufengyunchina@gmail.com> | 2016-11-07 23:57:06 +0100 |
---|---|---|
committer | liu fengyun <liu@fengy.me> | 2016-11-24 13:36:05 +0100 |
commit | abb9aa802789e6b43ff07c45281eedbb09512585 (patch) | |
tree | f0c74d053602dd64f0489780726ee9ef9a5fe4c2 /compiler | |
parent | 8592af1c815c34078d89c08536addbe757550179 (diff) | |
download | dotty-abb9aa802789e6b43ff07c45281eedbb09512585.tar.gz dotty-abb9aa802789e6b43ff07c45281eedbb09512585.tar.bz2 dotty-abb9aa802789e6b43ff07c45281eedbb09512585.zip |
fix #1642: disallow value classe wrapping value class
Diffstat (limited to 'compiler')
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) |