aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala
blob: 48be02fa167db107b0515c5549362a7c1fc148e6 (plain) (tree)













































                                                                                               
                                                         
                                          
                                                              








                                                                                                  



                                                                                      
                                               





                          


                                                                                                    











                                                                                                      
package dotty.tools.dotc
package transform

import ast.{Trees, tpd}
import core._, core.Decorators._
import TreeTransforms._, Phases.Phase
import Types._, Contexts._, Constants._, Names._, NameOps._, Flags._, DenotTransformers._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._, Scopes._, Denotations._
import TypeErasure.ErasedValueType, ValueClasses._

/** This phase erases ErasedValueType to their underlying type.
 *  It also removes the synthetic cast methods u2evt$ and evt2u$ which are
 *  no longer needed afterwards.
 */
class ElimErasedValueType extends MiniPhaseTransform with InfoTransformer {

  import tpd._

  override def phaseName: String = "elimErasedValueType"

  override def runsAfter: Set[Class[_ <: Phase]] = Set(classOf[Erasure])

  def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type = sym match {
    case sym: ClassSymbol if sym is ModuleClass =>
      sym.companionClass match {
        case origClass: ClassSymbol if isDerivedValueClass(origClass) =>
          val cinfo = tp.asInstanceOf[ClassInfo]
          val decls1 = cinfo.decls.cloneScope
          ctx.atPhase(this.next) { implicit ctx =>
            // Remove synthetic cast methods introduced by ExtensionMethods,
            // they are no longer needed after this phase.
            decls1.unlink(cinfo.decl(nme.U2EVT).symbol)
            decls1.unlink(cinfo.decl(nme.EVT2U).symbol)
          }
          cinfo.derivedClassInfo(decls = decls1)
        case _ =>
          tp
      }
    case _ =>
      elimEVT(tp)
  }

  def elimEVT(tp: Type)(implicit ctx: Context): Type = tp match {
    case ErasedValueType(_, underlying) =>
      elimEVT(underlying)
    case tp: MethodType =>
      val paramTypes = tp.paramInfos.mapConserve(elimEVT)
      val retType = elimEVT(tp.resultType)
      tp.derivedLambdaType(tp.paramNames, paramTypes, retType)
    case _ =>
      tp
  }

  def transformTypeOfTree(tree: Tree)(implicit ctx: Context): Tree =
    tree.withType(elimEVT(tree.tpe))

  override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = {
    val Apply(fun, args) = tree

    // The casts to and from ErasedValueType are no longer needed once ErasedValueType
    // has been eliminated.
    val t =
      if (fun.symbol.isValueClassConvertMethod)
        args.head
      else
        tree
    transformTypeOfTree(t)
  }

  override def transformInlined(tree: Inlined)(implicit ctx: Context, info: TransformerInfo): Tree =
    transformTypeOfTree(tree)

  // FIXME: transformIf and transformBlock won't be required anymore once #444 is fixed.
  override def transformIdent(tree: Ident)(implicit ctx: Context, info: TransformerInfo): Tree =
    transformTypeOfTree(tree)
  override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree =
    transformTypeOfTree(tree)
  override def transformBlock(tree: Block)(implicit ctx: Context, info: TransformerInfo): Tree =
    transformTypeOfTree(tree)
  override def transformIf(tree: If)(implicit ctx: Context, info: TransformerInfo): Tree =
    transformTypeOfTree(tree)
  override def transformTypeTree(tree: TypeTree)(implicit ctx: Context, info: TransformerInfo): Tree =
    transformTypeOfTree(tree)
}