alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Scala example source code file (ExistentialsAndSkolems.scala)

This example Scala source code file (ExistentialsAndSkolems.scala) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Scala source code examples by using tags.

All credit for the original source code belongs to scala-lang.org; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Scala tags/keywords

collection, lazytype, list, map, nosymbol, refinedtype, symbol, symboltable, t, type, typebounds

The ExistentialsAndSkolems.scala Scala example source code

/* NSC -- new scala compiler
 * Copyright 2005-2013 LAMP/EPFL
 * @author  Martin Odersky
 */

package scala
package reflect
package internal

import scala.collection.{ mutable, immutable }

/** The name of this trait defines the eventual intent better than
 *  it does the initial contents.
 */
trait ExistentialsAndSkolems {
  self: SymbolTable =>

  /** Map a list of type parameter symbols to skolemized symbols, which
   *  can be deskolemized to the original type parameter. (A skolem is a
   *  representation of a bound variable when viewed inside its scope.)
   *  !!!Adriaan: this does not work for hk types.
   *
   *  Skolems will be created at level 0, rather than the current value
   *  of `skolemizationLevel`. (See SI-7782)
   */
  def deriveFreshSkolems(tparams: List[Symbol]): List[Symbol] = {
    class Deskolemizer extends LazyType {
      override val typeParams = tparams
      val typeSkolems  = typeParams map (_.newTypeSkolem setInfo this)
      override def complete(sym: Symbol) {
        // The info of a skolem is the skolemized info of the
        // actual type parameter of the skolem
        sym setInfo sym.deSkolemize.info.substSym(typeParams, typeSkolems)
      }
    }

    val saved = skolemizationLevel
    skolemizationLevel = 0
    try new Deskolemizer().typeSkolems
    finally skolemizationLevel = saved
  }

  def isRawParameter(sym: Symbol) = // is it a type parameter leaked by a raw type?
    sym.isTypeParameter && sym.owner.isJavaDefined

  /** If we map a set of hidden symbols to their existential bounds, we
   *  have a problem: the bounds may themselves contain references to the
   *  hidden symbols.  So this recursively calls existentialBound until
   *  the typeSymbol is not amongst the symbols being hidden.
   */
  private def existentialBoundsExcludingHidden(hidden: List[Symbol]): Map[Symbol, Type] = {
    def safeBound(t: Type): Type =
      if (hidden contains t.typeSymbol) safeBound(t.typeSymbol.existentialBound.bounds.hi) else t

    def hiBound(s: Symbol): Type = safeBound(s.existentialBound.bounds.hi) match {
      case tp @ RefinedType(parents, decls) =>
        val parents1 = parents mapConserve safeBound
        if (parents eq parents1) tp
        else copyRefinedType(tp, parents1, decls)
      case tp => tp
    }

    // Hanging onto lower bound in case anything interesting
    // happens with it.
    mapFrom(hidden)(s => s.existentialBound match {
      case TypeBounds(lo, hi) => TypeBounds(lo, hiBound(s))
      case _                  => hiBound(s)
    })
  }

  /** Given a set `rawSyms` of term- and type-symbols, and a type
   *  `tp`, produce a set of fresh type parameters and a type so that
   *  it can be abstracted to an existential type. Every type symbol
   *  `T` in `rawSyms` is mapped to a clone. Every term symbol `x` of
   *  type `T` in `rawSyms` is given an associated type symbol of the
   *  following form:
   *
   *    type x.type <: T with Singleton
   *
   *  The name of the type parameter is `x.type`, to produce nice
   *  diagnostics. The Singleton parent ensures that the type
   *  parameter is still seen as a stable type. Type symbols in
   *  rawSyms are fully replaced by the new symbols. Term symbols are
   *  also replaced, except for term symbols of an Ident tree, where
   *  only the type of the Ident is changed.
   */
  final def existentialTransform[T](rawSyms: List[Symbol], tp: Type, rawOwner: Symbol = NoSymbol)(creator: (List[Symbol], Type) => T): T = {
    val allBounds = existentialBoundsExcludingHidden(rawSyms)
    val typeParams: List[Symbol] = rawSyms map { sym =>
      val name = sym.name match {
        case x: TypeName  => x
        case x            => tpnme.singletonName(x)
      }
      def rawOwner0  = rawOwner orElse abort(s"no owner provided for existential transform over raw parameter: $sym")
      val bound      = allBounds(sym)
      val sowner     = if (isRawParameter(sym)) rawOwner0 else sym.owner
      val quantified = sowner.newExistential(name, sym.pos)

      quantified setInfo bound.cloneInfo(quantified)
    }
    // Higher-kinded existentials are not yet supported, but this is
    // tpeHK for when they are: "if a type constructor is expected/allowed,
    // tpeHK must be called instead of tpe."
    val typeParamTypes = typeParams map (_.tpeHK)
    def doSubst(info: Type) = info.subst(rawSyms, typeParamTypes)

    creator(typeParams map (_ modifyInfo doSubst), doSubst(tp))
  }

  /**
   * Compute an existential type from hidden symbols `hidden` and type `tp`.
   * @param hidden   The symbols that will be existentially abstracted
   * @param hidden   The original type
   * @param rawOwner The owner for Java raw types.
   */
  final def packSymbols(hidden: List[Symbol], tp: Type, rawOwner: Symbol = NoSymbol): Type =
    if (hidden.isEmpty) tp
    else existentialTransform(hidden, tp, rawOwner)(existentialAbstraction)
}

Other Scala source code examples

Here is a short list of links related to this Scala ExistentialsAndSkolems.scala source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.