diff options
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)) |