aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-28 22:35:09 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-28 22:36:49 +0200
commitaae91eddee1a90dc5312ce156b772f090001721f (patch)
tree6ce2de879d48939ba1914e8e450ff77f45c5c89c
parentf7d3f3b12e0f3f69954bfb9980134968abf541f5 (diff)
downloaddotty-aae91eddee1a90dc5312ce156b772f090001721f.tar.gz
dotty-aae91eddee1a90dc5312ce156b772f090001721f.tar.bz2
dotty-aae91eddee1a90dc5312ce156b772f090001721f.zip
Fixes to erasure to make -Ycheck:all work.
Main change: Introduce JavaArrayType as a new type constructor for Java erased array. Translate all methods of Array class during erasure to primitive operations on arrays. Some other small fixes for more localized problems.
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala113
-rw-r--r--src/dotty/tools/dotc/core/Definitions.scala1
-rw-r--r--src/dotty/tools/dotc/core/NameOps.scala8
-rw-r--r--src/dotty/tools/dotc/core/StdNames.scala10
-rw-r--r--src/dotty/tools/dotc/core/SymDenotations.scala2
-rw-r--r--src/dotty/tools/dotc/core/TypeComparer.scala8
-rw-r--r--src/dotty/tools/dotc/printing/RefinedPrinter.scala2
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala72
-rw-r--r--src/dotty/tools/dotc/transform/TypeTestsCasts.scala2
-rw-r--r--src/dotty/tools/dotc/typer/TypeAssigner.scala19
-rw-r--r--test/dotc/tests.scala5
-rw-r--r--tests/neg/typetest.scala7
-rw-r--r--tests/pos/supercalls.scala3
-rw-r--r--tests/pos/typetestcast.scala12
14 files changed, 175 insertions, 89 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala
index c8c54ed03..63b4f396b 100644
--- a/src/dotty/tools/dotc/TypeErasure.scala
+++ b/src/dotty/tools/dotc/TypeErasure.scala
@@ -8,20 +8,17 @@ import util.DotClass
*
* TypeRef(NoPrefix, denot is ClassDenotation)
* TermRef(NoPrefix, denot is SymDenotation)
- * ThisType
- * SuperType
- * PolyParam, only for array types and isInstanceOf, asInstanceOf
- * RefinedType, parent* is Array class
- * TypeBounds, only for array types
+ * JavaArrayType
* AnnotatedType
* MethodType ----+-- JavaMethodType
- * PolyType, only for array types and isInstanceOf, asInstanceOf
- * RefinedThis
* ClassInfo
* NoType
* NoPrefix
* WildcardType
* ErrorType
+ *
+ * only for isInstanceOf, asInstanceOf: PolyType, PolyParam, TypeBounds
+ *
*/
object TypeErasure {
@@ -74,18 +71,19 @@ object TypeErasure {
/** The symbol's erased info. This is the type's erasure, except for the following symbols:
*
* - For $asInstanceOf : [T]T
- * - For $isInstanceOf : [T]scala#Boolean
- * - For Array[T].<init> : [T]{scala#Int)Array[T]
- * - For type members of Array : The original info
- * - For all other abstract types: = ?
+ * - For $isInstanceOf : [T]Boolean
+ * - For all abstract types : = ?
* - For all other symbols : the semi-erasure of their types, with
* isJava, isConstructor set according to symbol.
*/
def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = {
val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false)
- if ((sym eq defn.Any_asInstanceOf) ||
- (sym eq defn.Any_isInstanceOf) ||
- (sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info
+
+ def eraseParamBounds(tp: PolyType): Type =
+ tp.derivedPolyType(
+ tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType)
+
+ if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType])
else if (sym.isAbstractType) TypeAlias(WildcardType)
else erase(tp)
}
@@ -95,30 +93,56 @@ object TypeErasure {
tp.classSymbol.isPrimitiveValueClass ||
(tp.typeSymbol is JavaDefined))
- def erasedLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = {
- val cls2 = tp2.classSymbol
- def loop(bcs: List[ClassSymbol], bestSoFar: ClassSymbol): ClassSymbol = bcs match {
- case bc :: bcs1 =>
- if (cls2.derivesFrom(bc))
- if (!bc.is(Trait)) bc
- else loop(bcs1, if (bestSoFar.derivesFrom(bc)) bestSoFar else bc)
- else
- loop(bcs1, bestSoFar)
- case nil =>
- bestSoFar
- }
- loop(tp1.baseClasses, defn.ObjectClass).typeRef
+ /** The erased least upper bound is computed as follows
+ * - if both argument are arrays, an array of the lub of the element types
+ * - if one argument is an array, Object
+ * - otherwise a common superclass or trait S of the argument classes, with the
+ * following two properties:
+ * S is minimal: no other common superclass or trait derives from S]
+ * S is last : in the linearization of the first argument type `tp1`
+ * there are no minimal common superclasses or traits that
+ * come after S.
+ * (the reason to pick last is that we prefer classes over traits that way).
+ */
+ def erasedLub(tp1: Type, tp2: Type)(implicit ctx: Context): Type = tp1 match {
+ case JavaArrayType(elem1) =>
+ tp2 match {
+ case JavaArrayType(elem2) => JavaArrayType(erasedLub(elem1, elem2))
+ case _ => defn.ObjectType
+ }
+ case _ =>
+ tp2 match {
+ case JavaArrayType(_) => defn.ObjectType
+ case _ =>
+ val cls2 = tp2.classSymbol
+ def loop(bcs: List[ClassSymbol], bestSoFar: ClassSymbol): ClassSymbol = bcs match {
+ case bc :: bcs1 =>
+ if (cls2.derivesFrom(bc))
+ if (!bc.is(Trait)) bc
+ else loop(bcs1, if (bestSoFar.derivesFrom(bc)) bestSoFar else bc)
+ else
+ loop(bcs1, bestSoFar)
+ case nil =>
+ bestSoFar
+ }
+ loop(tp1.baseClasses, defn.ObjectClass).typeRef
+ }
}
+ /** The erased greatest lower bound picks one of the two argument types. It prefers, in this order:
+ * - arrays over non-arrays
+ * - subtypes over supertypes, unless isJava is set
+ * - real classes over traits
+ */
def erasedGlb(tp1: Type, tp2: Type, isJava: Boolean)(implicit ctx: Context): Type = tp1 match {
- case defn.ArrayType(elem1) =>
+ case JavaArrayType(elem1) =>
tp2 match {
- case defn.ArrayType(elem2) => defn.ArrayType(erasedGlb(elem1, elem2, isJava))
- case _ => defn.ObjectType
+ case JavaArrayType(elem2) => JavaArrayType(erasedGlb(elem1, elem2, isJava))
+ case _ => tp1
}
case _ =>
tp2 match {
- case defn.ArrayType(_) => defn.ObjectType
+ case JavaArrayType(_) => tp2
case _ =>
val tsym1 = tp1.typeSymbol
val tsym2 = tp2.typeSymbol
@@ -145,14 +169,13 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
/** The erasure |T| of a type T. This is:
*
* - For a refined type scala.Array+[T]:
- * - if T is Nothing or Null, scala.Array+[Object]
- * - otherwise, if T <: Object, scala.Array+[|T|]
- * - otherwise, if T is a type paramter coming from Java, scala.Array+[Object].
+ * - if T is Nothing or Null, []Object
+ * - otherwise, if T <: Object, []|T|
+ * - otherwise, if T is a type paramter coming from Java, []Object
* - otherwise, Object
* - For a term ref p.x, the type <noprefix> # x.
* - For a typeref scala.Any, scala.AnyVal, scala.Singleon or scala.NotNull: |java.lang.Object|
* - For a typeref scala.Unit, |scala.runtime.BoxedUnit|.
- * - For a typeref whose symbol is owned by Array: The typeref itself, with prefix = <noprefix>
* - For a typeref P.C where C refers to a class, <noprefix> # C.
* - For a typeref P.C where C refers to an alias type, the erasure of C's alias.
* - For a typeref P.C where C refers to an abstract type, the erasure of C's upper bound.
@@ -175,8 +198,7 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
def apply(tp: Type)(implicit ctx: Context): Type = tp match {
case tp: TypeRef =>
val sym = tp.symbol
- if (!sym.isClass)
- if (sym.exists && (sym.owner eq defn.ArrayClass)) tp else this(tp.info)
+ if (!sym.isClass) this(tp.info)
else if (sym.isDerivedValueClass) eraseDerivedValueClassRef(tp)
else eraseNormalClassRef(tp)
case tp: RefinedType =>
@@ -214,22 +236,25 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
def eraseTypeRef(p: TypeRef) = this(p).asInstanceOf[TypeRef]
val parents: List[TypeRef] =
if ((cls eq defn.ObjectClass) || cls.isPrimitiveValueClass) Nil
- else if (cls eq defn.ArrayClass) defn.ObjectClass.typeRef :: Nil
else removeLaterObjects(classParents.mapConserve(eraseTypeRef))
tp.derivedClassInfo(NoPrefix, parents, decls, this(tp.selfType))
// can't replace selftype by NoType because this would lose the sourceModule link
}
- case NoType | NoPrefix | ErrorType =>
+ case NoType | NoPrefix | ErrorType | JavaArrayType(_) =>
tp
case tp: WildcardType if wildcardOK =>
tp
}
- private def eraseArray(tp: RefinedType)(implicit ctx: Context) = {
+ def eraseArray(tp: RefinedType)(implicit ctx: Context) = {
val defn.ArrayType(elemtp) = tp
- if (elemtp derivesFrom defn.NullClass) defn.ObjectArrayType
- else if (isUnboundedGeneric(elemtp)) defn.ObjectType
- else defn.ArrayType(this(elemtp))
+ if (elemtp derivesFrom defn.NullClass) JavaArrayType(defn.ObjectType)
+ else if (isUnboundedGeneric(elemtp))
+ elemtp match {
+ case elemtp: TypeRef if elemtp.symbol.is(JavaDefined) => JavaArrayType(defn.ObjectType)
+ case _ => defn.ObjectType
+ }
+ else JavaArrayType(this(elemtp))
}
private def eraseDerivedValueClassRef(tref: TypeRef)(implicit ctx: Context): Type =
@@ -277,6 +302,8 @@ class TypeErasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wild
else if (sym.isDerivedValueClass) sigName(eraseDerivedValueClassRef(tp))
else normalizeClass(sym.asClass).fullName.asTypeName
case defn.ArrayType(elem) =>
+ sigName(this(tp))
+ case JavaArrayType(elem) =>
sigName(elem) ++ "[]"
case tp: TypeBounds =>
sigName(tp.hi)
diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala
index 304d9853c..c53e00152 100644
--- a/src/dotty/tools/dotc/core/Definitions.scala
+++ b/src/dotty/tools/dotc/core/Definitions.scala
@@ -330,7 +330,6 @@ class Definitions {
def NothingType: Type = NothingClass.typeRef
def NullType: Type = NullClass.typeRef
def SeqType: Type = SeqClass.typeRef
- def ObjectArrayType = ArrayType(ObjectType)
def UnitType: Type = UnitClass.typeRef
def BooleanType: Type = BooleanClass.typeRef
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala
index e7283c827..74673235a 100644
--- a/src/dotty/tools/dotc/core/NameOps.scala
+++ b/src/dotty/tools/dotc/core/NameOps.scala
@@ -196,6 +196,14 @@ object NameOps {
case nme.clone_ => nme.array_clone
}
+ /** The name of the primitive runtime operation corresponding to an array operation */
+ def primitiveArrayOp: TermName = name match {
+ case nme.apply => nme.primitive.arrayApply
+ case nme.length => nme.primitive.arrayLength
+ case nme.update => nme.primitive.arrayUpdate
+ case nme.CONSTRUCTOR => nme.primitive.arrayConstructor
+ }
+
/** If name length exceeds allowable limit, replace part of it by hash */
def compactified(implicit ctx: Context): TermName = termName(compactify(name.toString))
}
diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala
index 91a77a2a8..af4e810de 100644
--- a/src/dotty/tools/dotc/core/StdNames.scala
+++ b/src/dotty/tools/dotc/core/StdNames.scala
@@ -635,6 +635,16 @@ object StdNames {
def newBitmapName(bitmapPrefix: TermName, n: Int): TermName = bitmapPrefix ++ n.toString
def selectorName(n: Int): TermName = "_" + (n + 1)
+
+ object primitive {
+ val arrayApply: TermName = "[]apply"
+ val arrayUpdate: TermName = "[]update"
+ val arrayLength: TermName = "[]length"
+ val arrayConstructor: TermName = "[]<init>"
+ val names: Set[Name] = Set(arrayApply, arrayUpdate, arrayLength, arrayConstructor)
+ }
+
+ def isPrimitiveName(name: Name) = primitive.names.contains(name)
}
class ScalaTypeNames extends ScalaNames[TypeName] {
diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala
index 660287089..63f998c10 100644
--- a/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -924,7 +924,7 @@ object SymDenotations {
/** The type parameters of this class */
override final def typeParams(implicit ctx: Context): List[TypeSymbol] = {
def computeTypeParams = {
- if (ctx.phase.erasedTypes && (symbol ne defn.ArrayClass)) Nil
+ if (ctx.erasedTypes && (symbol ne defn.ArrayClass)) Nil
else if (this ne initial) initial.asSymDenotation.typeParams
else decls.filter(sym =>
(sym is TypeParam) && sym.owner == symbol).asInstanceOf[List[TypeSymbol]]
diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala
index fda9667e9..c9c4595ca 100644
--- a/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -735,6 +735,12 @@ class TypeComparer(initctx: Context) extends DotClass {
false
}
compareClassInfo
+ case JavaArrayType(elem2) =>
+ def compareJavaArray = tp1 match {
+ case JavaArrayType(elem1) => isSubType(elem1, elem2)
+ case _ => fourthTry(tp1, tp2)
+ }
+ compareJavaArray
case _ =>
fourthTry(tp1, tp2)
}
@@ -773,6 +779,8 @@ class TypeComparer(initctx: Context) extends DotClass {
} || needsEtaLift(tp2, tp1) && tp2.testLifted(tp1.typeParams, isSubType(tp1, _))
case AndType(tp11, tp12) =>
isNewSubType(tp11, tp2) || isNewSubType(tp12, tp2)
+ case JavaArrayType(elem1) =>
+ tp2 isRef ObjectClass
case _ =>
false
}
diff --git a/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
index 7669b1a3a..0da9b6d54 100644
--- a/src/dotty/tools/dotc/printing/RefinedPrinter.scala
+++ b/src/dotty/tools/dotc/printing/RefinedPrinter.scala
@@ -122,6 +122,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
return "=> " ~ toText(result)
case tp: ClassInfo =>
return toTextParents(tp.instantiatedParents) ~ "{...}"
+ case JavaArrayType(elemtp) =>
+ return toText(elemtp) ~ "[]"
case tp: SelectionProto =>
return toText(RefinedType(WildcardType, tp.name, tp.memberProto))
case tp: ViewProto =>
diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala
index 1efc6b53c..86151fae2 100644
--- a/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/src/dotty/tools/dotc/transform/Erasure.scala
@@ -24,7 +24,7 @@ import scala.collection.mutable.ListBuffer
import dotty.tools.dotc.core.Flags
import ValueClasses._
import TypeUtils._
-import com.sun.j3d.utils.behaviors.picking.Intersect
+import typer.Mode
class Erasure extends Phase with DenotTransformer { thisTransformer =>
@@ -51,10 +51,13 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
val newOwner = if (oldOwner eq defn.AnyClass) defn.ObjectClass else oldOwner
val oldInfo = ref.info
val newInfo = transformInfo(ref.symbol, oldInfo)
- if ((oldOwner eq newOwner) && (oldInfo eq newInfo)) ref
+ val oldFlags = ref.flags
+ val newFlags = ref.flags &~ Flags.HasDefaultParams // HasDefaultParams needs to be dropped because overriding might become overloading
+ // TODO: define derivedSymDenotation?
+ if ((oldOwner eq newOwner) && (oldInfo eq newInfo) && (oldFlags == newFlags)) ref
else {
assert(!ref.is(Flags.PackageClass), s"trans $ref @ ${ctx.phase} oldOwner = $oldOwner, newOwner = $newOwner, oldInfo = $oldInfo, newInfo = $newInfo ${oldOwner eq newOwner} ${oldInfo eq newInfo}")
- ref.copySymDenotation(owner = newOwner, info = newInfo)
+ ref.copySymDenotation(owner = newOwner, initFlags = newFlags, info = newInfo)
}
}
case ref =>
@@ -155,7 +158,7 @@ object Erasure {
// assert(!pt.isInstanceOf[SingletonType], pt)
if (pt isRef defn.UnitClass) unbox(tree, pt)
else (tree.tpe, pt) match {
- case (defn.ArrayType(treeElem), defn.ArrayType(ptElem))
+ case (JavaArrayType(treeElem), JavaArrayType(ptElem))
if treeElem.widen.isPrimitiveValueType && !ptElem.isPrimitiveValueType =>
// See SI-2386 for one example of when this might be necessary.
cast(ref(defn.runtimeMethod(nme.toObjectArray)).appliedTo(tree), pt)
@@ -209,22 +212,24 @@ object Erasure {
}
/** Type check select nodes, applying the following rewritings exhaustively
- * on selections `e.m`.
+ * on selections `e.m`, where `OT` is the type of the owner of `m` and `ET`
+ * is the erased type of the selection's original qualifier expression.
*
- * e.m1 -> e.m2 if `m1` is a member of Any or AnyVal and `m2` is
- * the same-named member in Object.
- * e.m -> box(e).m if `e` is primitive and `m` is a member or a reference class
- * or `e` has an erased value class type.
- * e.m -> unbox(e).m if `e` is not primitive and `m` is a member of a primtive type.
+ * e.m1 -> e.m2 if `m1` is a member of Any or AnyVal and `m2` is
+ * the same-named member in Object.
+ * e.m -> box(e).m if `e` is primitive and `m` is a member or a reference class
+ * or `e` has an erased value class type.
+ * e.m -> unbox(e).m if `e` is not primitive and `m` is a member of a primtive type.
+ * e.m -> cast(e, OT).m if the type of `e` does not conform to OT and `m`
+ * is not an array operation.
*
- * Additionally, if the type of `e` does not derive from the type `OT` of the owner of `m`,
- * the following rewritings are performed, where `ET` is the erased type of the selection's
- * original qualifier expression.
+ * If `m` is an array operation, i.e. one of the members apply, update, length, clone, and
+ * <init> of class Array, we additionally try the following rewritings:
*
- * e.m -> cast(OT).m if `m` is not an array operation
- * e.m -> cast(ET).m if `m` is an array operation and `ET` is an array type
- * e.m -> runtime.array_m(e)
- * if `m` is an array operation and `ET` is Object
+ * e.m -> runtime.array_m(e) if ET is Object
+ * e.m -> cast(e, ET).m if the type of `e` does not conform to ET
+ * e.clone -> e.clone' where clone' is Object's clone method
+ * e.m -> e.[]m if `m` is an array operation other than `clone`.
*/
override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = {
val sym = tree.symbol
@@ -233,10 +238,15 @@ object Erasure {
def select(qual: Tree, sym: Symbol): Tree =
untpd.cpy.Select(tree)(qual, sym.name) withType qual.tpe.select(sym)
- def selectArrayMember(qual: Tree, erasedPre: Type) = {
- if (erasedPre isRef defn.ObjectClass) runtimeCallWithProtoArgs(tree.name.genericArrayOp, pt, qual)
- else recur(cast(qual, erasedPre))
- }
+ def selectArrayMember(qual: Tree, erasedPre: Type): Tree =
+ if (erasedPre isRef defn.ObjectClass)
+ runtimeCallWithProtoArgs(tree.name.genericArrayOp, pt, qual)
+ else if (!(qual.tpe <:< erasedPre))
+ selectArrayMember(cast(qual, erasedPre), erasedPre)
+ else if (sym == defn.Array_clone)
+ untpd.cpy.Select(tree)(qual, tree.name).withType(defn.Object_clone.termRef)
+ else
+ assignType(untpd.cpy.Select(tree)(qual, tree.name.primitiveArrayOp), qual)
def recur(qual: Tree): Tree = {
val qualIsPrimitive = qual.tpe.widen.isPrimitiveValueType
@@ -249,10 +259,10 @@ object Erasure {
recur(box(qual))
else if (!qualIsPrimitive && symIsPrimitive)
recur(unbox(qual, sym.owner.typeRef))
- else if (qual.tpe.derivesFrom(sym.owner) || qual.isInstanceOf[Super])
- select(qual, sym)
else if (sym.owner eq defn.ArrayClass)
selectArrayMember(qual, erasure(tree.qualifier.typeOpt.widen.finalResultType))
+ else if (qual.tpe.derivesFrom(sym.owner) || qual.isInstanceOf[Super])
+ select(qual, sym)
else
recur(cast(qual, sym.owner.typeRef))
}
@@ -274,7 +284,7 @@ object Erasure {
override def typedTypeApply(tree: untpd.TypeApply, pt: Type)(implicit ctx: Context) = {
val TypeApply(fun, args) = tree
- val fun1 = typedExpr(fun, pt)
+ val fun1 = typedExpr(fun, WildcardType)
fun1.tpe.widen match {
case funTpe: PolyType =>
val args1 = args.mapconserve(typedType(_))
@@ -283,19 +293,6 @@ object Erasure {
}
}
-/*
- private def contextArgs(tree: untpd.Tree)(implicit ctx: Context): List[untpd.Tree] = {
- def nextOuter(ctx: Context): Context =
- if (ctx.outer.tree eq tree) nextOuter(ctx.outer) else ctx.outer
- ctx.tree match {
- case enclApp @ Apply(enclFun, enclArgs) if enclFun eq tree =>
- enclArgs ++ contextArgs(enclApp)(nextOuter(ctx))
- case _ =>
- Nil
- }
- }
-*/
-
override def typedApply(tree: untpd.Apply, pt: Type)(implicit ctx: Context): Tree = {
val Apply(fun, args) = tree
typedExpr(fun, FunProto(args, pt, this)) match {
@@ -425,6 +422,7 @@ object Erasure {
ctx.traceIndented(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) {
assert(ctx.phase == ctx.erasurePhase.next, ctx.phase)
if (tree.isEmpty) tree
+ else if (ctx.mode is Mode.Pattern) tree // TODO: replace with assertion once pattern matcher is active
else {
val tree1 = adaptToType(tree, pt)
tree1.tpe match {
diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
index f74f4f208..8c9ffb1fb 100644
--- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
+++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala
@@ -86,7 +86,7 @@ class TypeTestsCasts extends MiniPhaseTransform {
else derivedTree(box(qual), defn.Any_asInstanceOf, argType)
}
else if (argCls.isPrimitiveValueClass)
- unbox(qual, argType)
+ unbox(qual.ensureConforms(defn.ObjectType), argType)
else
derivedTree(qual, defn.Any_asInstanceOf, argType)
}
diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala
index 4d996fd61..153e0d242 100644
--- a/src/dotty/tools/dotc/typer/TypeAssigner.scala
+++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala
@@ -5,7 +5,7 @@ package typer
import core._
import ast._
import Scopes._, Contexts._, Constants._, Types._, Symbols._, Names._, Flags._, Decorators._
-import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._
+import ErrorReporting._, Annotations._, Denotations._, SymDenotations._, StdNames._, TypeErasure._
import util.Positions._
import config.Printers._
@@ -183,8 +183,21 @@ trait TypeAssigner {
def assignType(tree: untpd.Ident, tp: Type)(implicit ctx: Context) =
tree.withType(tp)
- def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) =
- tree.withType(accessibleSelectionType(tree, qual))
+ def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context): Select = {
+ def arrayElemType = {
+ val JavaArrayType(elemtp) = qual.tpe.widen
+ elemtp
+ }
+ val p = nme.primitive
+ val tp = tree.name match {
+ case p.arrayApply => MethodType(defn.IntType :: Nil, arrayElemType)
+ case p.arrayUpdate => MethodType(defn.IntType :: arrayElemType :: Nil, defn.UnitType)
+ case p.arrayLength => MethodType(Nil, defn.IntType)
+ case p.arrayConstructor => MethodType(defn.IntType :: Nil, qual.tpe)
+ case _ => accessibleSelectionType(tree, qual)
+ }
+ tree.withType(tp)
+ }
def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) =
tree.withType(accessibleSelectionType(tree, qual))
diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala
index 35f85c4d8..89dd42bc2 100644
--- a/test/dotc/tests.scala
+++ b/test/dotc/tests.scala
@@ -13,9 +13,7 @@ class tests extends CompilerTest {
// "-Yshow-suppressed-errors",
"-pagewidth", "160")
- implicit val defaultOptions = noCheckOptions ++ List(
- "-Ycheck:literalize"
- )
+ implicit val defaultOptions = noCheckOptions ++ List("-Ycheck:all")
val twice = List("#runs", "2", "-YnoDoubleBindings", "-Ystop-before:terminal")
val doErase = List("-Ystop-before:terminal")
@@ -91,6 +89,7 @@ class tests extends CompilerTest {
@Test def neg_t2994 = compileFile(negDir, "t2994", xerrors = 2)
@Test def neg_variances = compileFile(negDir, "variances", xerrors = 2)
@Test def neg_badAuxConstr = compileFile(negDir, "badAuxConstr", xerrors = 2)
+ @Test def neg_typetest = compileFile(negDir, "typetest", xerrors = 1)
@Test def dotc = compileDir(dotcDir + "tools/dotc", twice)
@Test def dotc_ast = compileDir(dotcDir + "tools/dotc/ast", twice)
diff --git a/tests/neg/typetest.scala b/tests/neg/typetest.scala
new file mode 100644
index 000000000..27ecd25b2
--- /dev/null
+++ b/tests/neg/typetest.scala
@@ -0,0 +1,7 @@
+object Test {
+
+ val i: Int = 1
+
+ println(i.isInstanceOf[Object])
+}
+
diff --git a/tests/pos/supercalls.scala b/tests/pos/supercalls.scala
new file mode 100644
index 000000000..79b0e585d
--- /dev/null
+++ b/tests/pos/supercalls.scala
@@ -0,0 +1,3 @@
+abstract class A(x: Int)
+
+abstract class B(y: Int) extends A({ def f(x: Int) = x * x; f(y)})
diff --git a/tests/pos/typetestcast.scala b/tests/pos/typetestcast.scala
new file mode 100644
index 000000000..fd0883669
--- /dev/null
+++ b/tests/pos/typetestcast.scala
@@ -0,0 +1,12 @@
+object Test {
+
+ val o: Object = "A"
+
+ println(o.isInstanceOf[Int])
+
+ val i: Int = o.asInstanceOf[Int]
+
+ val o2 = i.asInstanceOf[Object]
+
+}
+