From bfd7863406146aa830028ed77f7b0107fc60e5dc Mon Sep 17 00:00:00 2001 From: James Iry Date: Wed, 27 Feb 2013 04:59:47 -0800 Subject: SI-7159 Distinguish between assignability and sub typing in TypeKinds TypeKinds said SHORT <:< INT. But that's not quite true on the JVM. You can assign SHORT to INT, but you can't assign an ARRAY[SHORT] to ARRAY[INT]. Since JVM arrays are covariant it's clear that assignability and subtyping are distinct on the JVM. This commit adds an isAssignable method and moves the rules about the int sized primitives there. ICodeCheckers, ICodeReader, and GenICode are all updated to use isAssignable instead of <:<. --- .../scala/tools/nsc/backend/icode/GenICode.scala | 2 +- .../tools/nsc/backend/icode/ICodeCheckers.scala | 2 +- .../scala/tools/nsc/backend/icode/TypeKinds.scala | 32 ++++++++++++---------- .../tools/nsc/symtab/classfile/ICodeReader.scala | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 2b513a6fa3..61d0baf7b0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1051,7 +1051,7 @@ abstract class GenICode extends SubComponent { case (NothingReference, _) => ctx.bb.emit(THROW(ThrowableClass)) ctx.bb.enterIgnoreMode() - case _ if (from <:< to) => + case _ if from isAssignabledTo to => () case (_, UNIT) => ctx.bb.emit(DROP(from), pos) diff --git a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala index fb1ef311d2..49f2d9859d 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/ICodeCheckers.scala @@ -351,7 +351,7 @@ abstract class ICodeCheckers { def typeError(k1: TypeKind, k2: TypeKind) { icodeError("\n expected: " + k1 + "\n found: " + k2) } - def isSubtype(k1: TypeKind, k2: TypeKind) = (k1 <:< k2) || { + def isSubtype(k1: TypeKind, k2: TypeKind) = (k1 isAssignabledTo k2) || { import platform.isMaybeBoxed (k1, k2) match { diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 266e2b861f..1875c8c914 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -88,17 +88,20 @@ trait TypeKinds { self: ICodes => final def isNumericType: Boolean = isIntegralType | isRealType /** Simple subtyping check */ - def <:<(other: TypeKind): Boolean = other match { - // On the JVM, BOOL, BYTE, CHAR, SHORT need no coercion to INT - // TODO it's pretty suspect to call this a subtyping relationship - // for instance JVM Arrays are covariant, but Array[Char] is not - // a subtype of Array[Int] on the JVM. However, when I attempted - // to remove it I got verify errors when compiling the library - // under -optimize + def <:<(other: TypeKind): Boolean + + /** + * this is directly assignable to other if no coercion or + * casting is needed to convert this to other. It's a distinct + * relationship from <:< because on the JVM, BOOL, BYTE, CHAR, + * SHORT need no coercion to INT even though JVM arrays + * are covariant, ARRAY[SHORT] is not a subtype of ARRAY[INT] + */ + final def isAssignabledTo(other: TypeKind): Boolean = other match { case INT => this.isIntSizedType - case _ => this eq other + case _ => this <:< other } - + /** Is this type a category 2 type in JVM terms? (ie, is it LONG or DOUBLE?) */ def isWideType: Boolean = false @@ -117,6 +120,7 @@ trait TypeKinds { self: ICodes => override def toString = { this.getClass.getName stripSuffix "$" dropWhile (_ != '$') drop 1 } + def <:<(other: TypeKind): Boolean = this eq other } /** @@ -286,7 +290,7 @@ trait TypeKinds { self: ICodes => } /** Checks subtyping relationship. */ - override def <:<(other: TypeKind) = isNothingType || (other match { + def <:<(other: TypeKind) = isNothingType || (other match { case REFERENCE(cls2) => cls.tpe <:< cls2.tpe case ARRAY(_) => cls == NullClass case _ => false @@ -324,7 +328,7 @@ trait TypeKinds { self: ICodes => /** Array subtyping is covariant, as in Java. Necessary for checking * code that interacts with Java. */ - override def <:<(other: TypeKind) = other match { + def <:<(other: TypeKind) = other match { case ARRAY(elem2) => elem <:< elem2 case REFERENCE(AnyRefClass | ObjectClass) => true // TODO: platform dependent! case _ => false @@ -342,7 +346,7 @@ trait TypeKinds { self: ICodes => } /** Checks subtyping relationship. */ - override def <:<(other: TypeKind) = other match { + def <:<(other: TypeKind) = other match { case BOXED(`kind`) => true case REFERENCE(AnyRefClass | ObjectClass) => true // TODO: platform dependent! case _ => false @@ -355,6 +359,7 @@ trait TypeKinds { self: ICodes => */ case object ConcatClass extends TypeKind { override def toString = "ConcatClass" + def <:<(other: TypeKind): Boolean = this eq other /** * Approximate `lub`. The common type of two references is @@ -365,9 +370,6 @@ trait TypeKinds { self: ICodes => case REFERENCE(_) => AnyRefReference case _ => uncomparable(other) } - - /** Checks subtyping relationship. */ - override def <:<(other: TypeKind) = this eq other } ////////////////// Conversions ////////////////////////////// diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala index 6e99129ee5..703724f003 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ICodeReader.scala @@ -930,7 +930,7 @@ abstract class ICodeReader extends ClassfileParser { locals.get(idx) match { case Some(ls) => - val l = ls find { loc => loc._2 <:< kind } + val l = ls find { loc => loc._2 isAssignabledTo kind } l match { case Some((loc, _)) => loc case None => -- cgit v1.2.3