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

scala.scalanative.nscplugin.NirGenUtil.scala Maven / Gradle / Ivy

There is a newer version: 0.5.6
Show newest version
package scala.scalanative
package nscplugin

import dotty.tools.dotc.ast.tpd
import tpd._
import dotty.tools.dotc.core
import core.Contexts._
import core.Types._
import scala.scalanative.util.ScopedVar
import scala.collection.mutable
import dotty.tools.dotc.core.Names.Name
import dotty.tools.dotc.report
import scala.scalanative.nir
import scala.compiletime.uninitialized

trait NirGenUtil(using Context) { self: NirCodeGen =>

  protected def desugarTree(tree: Tree): Tree = {
    tree match {
      case ident: Ident => tpd.desugarIdent(ident)
      case _            => tree
    }
  }

  protected def qualifierOf(fun: Tree): Tree = {
    fun match {
      case fun: Ident =>
        fun.tpe match {
          case TermRef(prefix: TermRef, _)  => tpd.ref(prefix)
          case TermRef(prefix: ThisType, _) => tpd.This(prefix.cls)
        }
      case Select(qualifier, _) => qualifier
      case TypeApply(fun, _)    => qualifierOf(fun)
    }
  }

  protected def withFreshExprBuffer[R](f: ExprBuffer ?=> R): R = {
    ScopedVar.scoped(
      curFresh := nir.Fresh(),
      curScopeId := nir.ScopeId.TopLevel
    ) {
      val buffer = new ExprBuffer(using curFresh)
      f(using buffer)
    }
  }

  protected def withFreshBlockScope[R](
      srcPosition: nir.SourcePosition
  )(f: nir.ScopeId => R): R = {
    val blockScope = nir.ScopeId.of(curFreshScope.get())
    // Parent of top level points to itself
    val parentScope =
      if (blockScope.isTopLevel) blockScope
      else curScopeId.get

    curScopes.get += nir.Defn.Define.DebugInfo.LexicalScope(
      id = blockScope,
      parent = parentScope,
      srcPosition = srcPosition
    )

    ScopedVar.scoped(
      curScopeId := blockScope
    )(f(parentScope))
  }

  protected def localNamesBuilder(): mutable.Map[nir.Local, nir.LocalName] =
    mutable.Map.empty[nir.Local, nir.LocalName]

  extension (fresh: nir.Fresh)
    def namedId(name: nir.LocalName): nir.Local = {
      val id = fresh()
      curMethodLocalNames.get.update(id, name)
      id
    }

  // Backend utils ported from Dotty JVM backend
  // https://github.com/lampepfl/dotty/blob/938d405f05e3b47eb18183a6d6330b6324505cdf/compiler/src/dotty/tools/backend/jvm/DottyBackendInterface.scala
  private val desugared = new java.util.IdentityHashMap[Type, tpd.Select]

  private def cachedDesugarIdent(i: Ident): Option[tpd.Select] = {
    var found = desugared.get(i.tpe)
    if (found == null) {
      tpd.desugarIdent(i) match {
        case sel: tpd.Select =>
          desugared.put(i.tpe, sel)
          found = sel
        case _ =>
      }
    }
    if (found == null) None else Some(found)
  }

  object DesugaredSelect extends DeconstructorCommon[tpd.Tree] {
    var desugared: tpd.Select = null

    override def isEmpty: Boolean =
      desugared eq null

    def _1: Tree = desugared.qualifier
    def _2: Name = desugared.name

    override def unapply(s: tpd.Tree): this.type = {
      s match {
        case t: tpd.Select => desugared = t
        case t: Ident =>
          cachedDesugarIdent(t) match {
            case Some(t) => desugared = t
            case None    => desugared = null
          }
        case _ => desugared = null
      }

      this
    }
  }

  abstract class DeconstructorCommon[T >: Null <: AnyRef] {
    var field: T = null
    def get: this.type = this
    def isEmpty: Boolean = field eq null
    def isDefined = !isEmpty
    def unapply(s: T): this.type = {
      field = s
      this
    }
  }
}

object NirGenUtil {
  class ContextCached[T](init: Context ?=> T) {
    private var lastContext: Context = uninitialized
    private var cached: T = uninitialized

    def get(using Context): T = {
      if (lastContext != ctx) {
        cached = init
        lastContext = ctx
      }
      cached
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy