diff options
author | Guillaume Martres <smarter@ubuntu.com> | 2015-03-18 23:56:07 +0100 |
---|---|---|
committer | Dmitry Petrashko <dmitry.petrashko@gmail.com> | 2015-05-01 13:26:22 +0200 |
commit | 391c80c4dfb2489e4098af33265b22332ef3d5f1 (patch) | |
tree | 206abc627f2a4cf5404547f554cd448492351a16 /src/dotty/tools/dotc/transform/ExtensionMethods.scala | |
parent | f168970f38df1d1ccc2b262f1a77f72cd4ec9f39 (diff) | |
download | dotty-391c80c4dfb2489e4098af33265b22332ef3d5f1.tar.gz dotty-391c80c4dfb2489e4098af33265b22332ef3d5f1.tar.bz2 dotty-391c80c4dfb2489e4098af33265b22332ef3d5f1.zip |
Add synthetic casts to and from ErasedValueType
For a value class V, let U be the underlying type after
erasure. We add to the companion object of V two cast methods:
def u2evt$(x0: U): ErasedValueType(V, U)
def evt2u$(x0: ErasedValueType(V, U)): U
The casts are used in Erasure to make it typecheck, they are then removed
in ElimErasedValueType (not yet present in this commit). This is
different from the implementation of value classes in Scala 2 (see
SIP-15) which uses `asInstanceOf` which does not typecheck.
Diffstat (limited to 'src/dotty/tools/dotc/transform/ExtensionMethods.scala')
-rw-r--r-- | src/dotty/tools/dotc/transform/ExtensionMethods.scala | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/src/dotty/tools/dotc/transform/ExtensionMethods.scala b/src/dotty/tools/dotc/transform/ExtensionMethods.scala index e6260bde2..724f3fc64 100644 --- a/src/dotty/tools/dotc/transform/ExtensionMethods.scala +++ b/src/dotty/tools/dotc/transform/ExtensionMethods.scala @@ -14,13 +14,24 @@ import core._ import Phases.Phase import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._ import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._ +import TypeErasure.{ erasure, ErasedValueType } import TypeUtils._ import util.Positions._ import Decorators._ +import SymUtils._ /** * Perform Step 1 in the inline classes SIP: Creates extension methods for all * methods in a value class, except parameter or super accessors, or constructors. + * + * Additionally, for a value class V, let U be the underlying type after erasure. We add + * to the companion module of V two cast methods: + * def u2evt$(x0: U): ErasedValueType(V, U) + * def evt2u$(x0: ErasedValueType(V, U)): U + * The casts are used in [[Erasure]] to make it typecheck, they are then removed + * in [[ElimErasedValueType]]. + * This is different from the implementation of value classes in Scala 2 + * (see SIP-15) which uses `asInstanceOf` which does not typecheck. */ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with FullParameterization { thisTransformer => @@ -36,15 +47,28 @@ class ExtensionMethods extends MiniPhaseTransform with DenotTransformer with Ful override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match { case ref: ClassDenotation if ref is ModuleClass => ref.linkedClass match { - // In Scala 2, extension methods are added before pickling so we should not generate them again - case origClass: ClassSymbol if isDerivedValueClass(origClass) && !(origClass is Scala2x) => + case origClass: ClassSymbol if isDerivedValueClass(origClass) => val cinfo = ref.classInfo val decls1 = cinfo.decls.cloneScope ctx.atPhase(thisTransformer.next) { implicit ctx => - for (decl <- origClass.classInfo.decls) { - if (isMethodWithExtension(decl)) - decls1.enter(createExtensionMethod(decl, ref.symbol)) + // In Scala 2, extension methods are added before pickling so we should + // not generate them again. + if (!(origClass is Scala2x)) { + for (decl <- origClass.classInfo.decls) { + if (isMethodWithExtension(decl)) + decls1.enter(createExtensionMethod(decl, ref.symbol)) + } } + + val sym = ref.symbol + val underlying = erasure(underlyingOfValueClass(origClass)) + val evt = ErasedValueType(origClass, underlying) + val u2evtSym = ctx.newSymbol(sym, nme.U2EVT, Synthetic | Method, + MethodType(List(nme.x_0), List(underlying), evt)) + val evt2uSym = ctx.newSymbol(sym, nme.EVT2U, Synthetic | Method, + MethodType(List(nme.x_0), List(evt), underlying)) + decls1.enter(u2evtSym) + decls1.enter(evt2uSym) } if (decls1.isEmpty) ref else ref.copySymDenotation(info = cinfo.derivedClassInfo(decls = decls1)) |