All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.transform.ExplicitSelf.scala Maven / Gradle / Ivy

There is a newer version: 3.6.4-RC1-bin-20241220-0bfa1af-NIGHTLY
Show newest version
package dotty.tools.dotc
package transform

import core.*
import Contexts.*, Types.*, MegaPhase.*, ast.Trees.*, Symbols.*, Decorators.*, Flags.*


/** Transform references of the form
 *
 *     C.this.m
 *
 *  where `C` is a class with explicit self type and `C` is not a
 *  subclass of the owner of `m` to
 *
 *     C.this.asInstanceOf[S & C.this.type].m
 *
 *  where `S` is the self type of `C`.
 *  See run/i789.scala for a test case why this is needed.
 *
 *  Also replaces idents referring to the self type with ThisTypes.
 */
class ExplicitSelf extends MiniPhase {
  import ast.tpd.*

  override def phaseName: String = ExplicitSelf.name

  override def description: String = ExplicitSelf.description

  private def needsCast(tree: RefTree, cls: ClassSymbol)(using Context) =
    !cls.is(Package)
    && cls.givenSelfType.exists
    && tree.symbol.exists
    && !cls.derivesFrom(tree.symbol.owner)

  private def castQualifier(tree: RefTree, cls: ClassSymbol, thiz: Tree)(using Context) =
    val selfType = cls.classInfo.selfType
    if selfType.classSymbols.exists(_.isValueClass) && !cls.isUniversalTrait then
      report.error(em"self type $selfType of $cls may not be a value class", thiz.srcPos)
    cpy.Select(tree)(thiz.cast(AndType(selfType, thiz.tpe)), tree.name)

  override def transformIdent(tree: Ident)(using Context): Tree = tree.tpe match {
    case tp: ThisType =>
      report.debuglog(s"owner = ${ctx.owner}, context = ${ctx}")
      This(tp.cls).withSpan(tree.span)
    case TermRef(thisTp: ThisType, _) =>
      val cls = thisTp.cls
      if needsCast(tree, cls) then castQualifier(tree, cls, This(cls))
      else tree
    case _ =>
      tree
  }

  override def transformSelect(tree: Select)(using Context): Tree = tree match {
    case Select(thiz: This, name) if name.isTermName =>
      val cls = thiz.symbol.asClass
      if needsCast(tree, cls) then castQualifier(tree, cls, thiz)
      else tree
    case _ => tree
  }
}

object ExplicitSelf:
  val  name: String = "explicitSelf"
  val description: String = "make references to non-trivial self types explicit as casts"




© 2015 - 2025 Weber Informatics LLC | Privacy Policy