summaryrefslogblamecommitdiff
path: root/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala
blob: 362aeb910021c9bd3bb0571f359a8f0542142be2 (plain) (tree)
1
2
3
4



                            






















                                               
                                       










































                                                                                    

                                                                

                                         
                                                    




































                                                                                         

                                                    























                                                                           
                                                                 









































































                                                                        

                                              

                                                                             
 
















                                                                     


                                      

                               

                                         











                                                            
                                                         






















                                                                     
                              

                                                                       
 



































                                                               
                                    








                                                  
                                          





















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

// $Id$

package scala.tools.nsc.backend.icode;

/* A type case

    case UNIT            =>
    case BOOL            =>
    case BYTE            =>
    case SHORT           =>
    case CHAR            =>
    case INT             =>
    case LONG            =>
    case FLOAT           =>
    case DOUBLE          =>
    case REFERENCE(cls)  =>
    case ARRAY(elem)     =>

*/

import scala.collection.mutable.{Map, HashMap};

mixin class TypeKinds requires ICodes {
  import global._;

  /** This class represents a type kind. Type kinds
   * represent the types that the VM know (or the ICode
   * view of what VMs know).
   */
  abstract class TypeKind {

    /** Returns a string representation of this type kind. */
    override def toString(): String = this match {
      case UNIT    => "UNIT";
      case BOOL    => "BOOL";
      case BYTE    => "BYTE"
      case SHORT   => "SHORT";
      case CHAR    => "CHAR";
      case INT     => "INT";
      case LONG    => "LONG";
      case FLOAT   => "FLOAT";
      case DOUBLE  => "DOUBLE";
      case REFERENCE(cls) => "REFERENCE(" + cls.fullNameString + ")" ;
      case ARRAY(elem) => "ARRAY[" + elem + "]";
      case _       => abort("Unkown type kind.");
    }

    def toType: Type = this match {
      case UNIT            => definitions.UnitClass.info;
      case BOOL            => definitions.BooleanClass.info;
      case BYTE            => definitions.ByteClass.info;
      case SHORT           => definitions.ShortClass.info;
      case CHAR            => definitions.CharClass.info;
      case INT             => definitions.IntClass.info;
      case LONG            => definitions.LongClass.info;
      case FLOAT           => definitions.FloatClass.info;
      case DOUBLE          => definitions.DoubleClass.info;
      case REFERENCE(cls)  => typeRef(cls.typeConstructor.prefix, cls, Nil);
      case ARRAY(elem)     => typeRef(definitions.ArrayClass.typeConstructor.prefix,
                                      definitions.ArrayClass,
                                      elem.toType :: Nil);
      case _ => abort("Unknown type kind.");
    }

    def isReferenceType: Boolean = false;
    def isArrayType: Boolean = false;
    def isValueType: Boolean = !isReferenceType && !isArrayType;


    def isIntType: Boolean = this match {
      case BYTE | SHORT | INT | LONG | CHAR => true;
      case _ => false;
    }

    def isRealType: Boolean = this match {
      case FLOAT | DOUBLE => true;
      case _ => false;
    }

    def isNumericType: Boolean = isIntType | isRealType;

    def maxType(other: TypeKind): TypeKind;

    /** Simple subtyping check */
    def <:<(other: TypeKind): Boolean = (this == other);

    override def equals(other: Any): Boolean =
      this eq other.asInstanceOf[AnyRef];
  }

  /**
   * The least upper bound of two typekinds. They have to be either
   * REFERENCE or ARRAY kinds.
   *
   * The lub is based on the lub of scala types.
   */
  def lub(a: TypeKind, b: TypeKind): TypeKind = {
    def lub0(t1: Type, t2: Type): Type = {
      val lubTpe = global.lub(t1 :: t2 :: Nil);
      assert(lubTpe.symbol.isClass,
             "Least upper bound of " + t1 + " and " + t2 + " is not a class: " + lubTpe);
      lubTpe;
    }

    if ((a.isReferenceType || a.isArrayType) &&
        (b.isReferenceType || b.isArrayType))
      toTypeKind(lub0(a.toType, b.toType))
    else if (a == b) a
    else if (a == REFERENCE(definitions.AllClass)) b
    else if (b == REFERENCE(definitions.AllClass)) a
    else throw new CheckerError("Incompatible types: " + a + " with " + b);
  }

  /** The unit value */
  case object UNIT extends TypeKind {
    def maxType(other: TypeKind): TypeKind = other match {
      case UNIT => UNIT;
      case _ => abort("Uncomparbale type kinds: UNIT with " + other);
    }
  }

  /** A boolean value */
  case object BOOL extends TypeKind {
    override def maxType(other: TypeKind): TypeKind = other match {
      case BOOL => BOOL;
      case _ => abort("Uncomparbale type kinds: BOOL with " + other);
    }
  }

  /** A 1-byte signed integer */
  case object BYTE extends TypeKind {
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case INT => INT;
        case BYTE | SHORT | INT | LONG | FLOAT | DOUBLE => other;
        case _ => abort("Uncomparbale type kinds: BYTE with " + other);
      }
  }

  /** A 2-byte signed integer */
  case object SHORT extends TypeKind {
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case BYTE | SHORT | CHAR => SHORT;
        case INT | LONG | FLOAT | DOUBLE => other;
        case _ => abort("Uncomparbale type kinds: SHORT with " + other);
      }
  }

  /** A 2-byte signed integer */
  case object CHAR extends TypeKind {
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case BYTE | SHORT | CHAR => CHAR;
        case INT | LONG | FLOAT | DOUBLE => other;
        case _ => abort("Uncomparbale type kinds: CHAR with " + other);
      }
  }


  /** A 4-byte signed integer */
  case object INT extends TypeKind {
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case BYTE | SHORT | CHAR | INT => INT;
        case LONG | FLOAT | DOUBLE => other;
        case _ => abort("Uncomparbale type kinds: INT with " + other);
      }
  }

  /** An 8-byte signed integer */
  case object LONG extends TypeKind {
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case BYTE | SHORT | CHAR | INT | LONG => LONG;
        case FLOAT | DOUBLE => DOUBLE;
        case _ => abort("Uncomparbale type kinds: LONG with " + other);
      }
  }

  /** A 4-byte floating point number */
  case object FLOAT extends TypeKind {
    override def maxType(other: TypeKind): TypeKind = other match {
      case BYTE | SHORT | CHAR | INT | FLOAT => FLOAT;
      case DOUBLE => DOUBLE;
      case _ => abort("Uncomparbale type kinds: FLOAT with " + other);
    }
  }

  /** An 8-byte floating point number */
  case object DOUBLE extends TypeKind {
    override def maxType(other: TypeKind): TypeKind =
      if (other.isNumericType)
        DOUBLE;
      else
        abort("Uncomparbale type kinds: DOUBLE with " + other);
  }

  /** A string reference */
  // case object STRING extends TypeKind {
  //   override def maxType(other: TypeKind): TypeKind = other match {
  //     case STRING => STRING;
  //     case _   =>
  //       abort("Uncomparbale type kinds: STRING with " + other);
  //   }
  // }

  /** A class type. */
  case class REFERENCE(cls: Symbol) extends TypeKind {
    assert(cls != null,
           "REFERENCE to null class symbol.");
    assert(cls != definitions.ArrayClass,
           "REFERENCE to Array is not allowed, should be ARRAY[..] instead");

    override def toString(): String =
      "REFERENCE(" + cls.fullNameString + ")";

    /**
     * Approximate `lub'. The common type of two references is
     * always AnyRef. For 'real' least upper bound wrt to subclassing
     * use method 'lub'.
     */
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case REFERENCE(_) => REFERENCE(definitions.AnyRefClass);
        case _ =>
          abort("Uncomparbale type kinds: REFERENCE with " + other);
      }

    /** Checks subtyping relationship. */
    override def <:<(other: TypeKind): Boolean =
      if (cls == definitions.AllClass)
        true
      else other match {
        case REFERENCE(cls2) =>
          cls.tpe <:< cls2.tpe;
        case ARRAY(_) =>
          cls == definitions.AllRefClass;
        case _ => false;
      }

    override def isReferenceType: Boolean = true;

    override def equals(other: Any): Boolean = other match {
      case REFERENCE(cls2) => cls == cls2;
      case _               => false;
    }
  }


  case class ARRAY(val elem: TypeKind) extends TypeKind {
    override def toString(): String =
      "ARRAY[" + elem + "]";

    override def isArrayType = true;

    /**
     * Approximate `lub'. The common type of two references is
     * always AnyRef. For 'real' least upper bound wrt to subclassing
     * use method 'lub'.
     */
    override def maxType(other: TypeKind): TypeKind =
      other match {
        case REFERENCE(_) => REFERENCE(definitions.AnyRefClass);
        case ARRAY(elem2) => ARRAY(elem maxType elem2);
        case _ =>
          abort("Uncomparbale type kinds: ARRAY with " + other);
      }

    /** Checks subtyping relationship. */
    override def <:<(other: TypeKind): Boolean =
      other match {
        case ARRAY(elem2) =>
          elem <:< elem2;
        case REFERENCE(sym) =>
          (sym == definitions.AnyRefClass ||
           sym == definitions.ObjectClass) // TODO: platform dependent!

        case _ => false;
      }

    override def equals(other: Any): Boolean = other match {
      case ARRAY(elem2) => elem == elem2;
      case _               => false;
    }

  }

  ////////////////// Conversions //////////////////////////////


  /** Return the TypeKind of the given type */
  def toTypeKind(t: Type): TypeKind = t match {
    case ThisType(sym) => REFERENCE(sym);

    case SingleType(pre, sym) =>
      primitiveTypeMap get sym match {
        case Some(k) => k;
        case None    => REFERENCE(sym);
      }

    case ConstantType(value) =>
      toTypeKind(value.tpe);

    case TypeRef(_, sym, args) =>
      primitiveTypeMap get sym match {
        case Some(k) => k;
        case None    =>
          if (sym == definitions.ArrayClass)
            ARRAY(toTypeKind(args.head))
          else
            REFERENCE(sym);
      }

    case ClassInfoType(_, _, sym) =>
      primitiveTypeMap get sym match {
        case Some(k) => k;
        case None    =>
          if (sym == definitions.ArrayClass)
            abort("ClassInfoType to ArrayClass!");
          else
            REFERENCE(sym);
      }

    case _ => abort("Unknown type: " + t);
  }

  /** A map from scala primitive Types to ICode TypeKinds */
  private var primitiveTypeMap: Map[Symbol, TypeKind] = null;

  /** Initialize the map from scala primitive types to ICode types */
  def initPrimitiveTypeMap = {
    log("Initializing primitive map");
    primitiveTypeMap = new HashMap();
    primitiveTypeMap += definitions.UnitClass -> UNIT;
    primitiveTypeMap += definitions.BooleanClass -> BOOL;
    primitiveTypeMap += definitions.ByteClass -> BYTE;
    primitiveTypeMap += definitions.ShortClass -> SHORT;
    primitiveTypeMap += definitions.CharClass -> CHAR;
    primitiveTypeMap += definitions.IntClass -> INT;
    primitiveTypeMap += definitions.LongClass -> LONG;
    primitiveTypeMap += definitions.FloatClass -> FLOAT;
    primitiveTypeMap += definitions.DoubleClass -> DOUBLE;
//    primitiveTypeMap += definitions.StringClass -> STRING;
  }

}