aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/transform/ExtensionMethods.scala
diff options
context:
space:
mode:
authorGuillaume Martres <smarter@ubuntu.com>2015-03-18 23:56:07 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2015-05-01 13:26:22 +0200
commit391c80c4dfb2489e4098af33265b22332ef3d5f1 (patch)
tree206abc627f2a4cf5404547f554cd448492351a16 /src/dotty/tools/dotc/transform/ExtensionMethods.scala
parentf168970f38df1d1ccc2b262f1a77f72cd4ec9f39 (diff)
downloaddotty-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.scala34
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))