diff options
author | schinz <schinz@epfl.ch> | 2005-04-07 19:46:41 +0000 |
---|---|---|
committer | schinz <schinz@epfl.ch> | 2005-04-07 19:46:41 +0000 |
commit | 36d0dca50b187ded0a9c12e8ddd7d9332882f44f (patch) | |
tree | 201e072620dcd8b8e962d68d99e3d8e65d899929 | |
parent | 87ea8ccb1a5490efb2a7f940e4402e19a9768d15 (diff) | |
download | scala-36d0dca50b187ded0a9c12e8ddd7d9332882f44f.tar.gz scala-36d0dca50b187ded0a9c12e8ddd7d9332882f44f.tar.bz2 scala-36d0dca50b187ded0a9c12e8ddd7d9332882f44f.zip |
- fixed asInstanceOf when applied to null, so t...
- fixed asInstanceOf when applied to null, so that it works according
to the spec, - use a local variable in the "two steps" translation of
isInstanceOf, to avoid duplicated evaluation
-rw-r--r-- | sources/scala/Type.java | 28 | ||||
-rw-r--r-- | sources/scala/runtime/types/JavaClassType.java | 2 | ||||
-rw-r--r-- | sources/scalac/transformer/TypesAsValuesPhase.java | 50 |
3 files changed, 57 insertions, 23 deletions
diff --git a/sources/scala/Type.java b/sources/scala/Type.java index 86702be8f2..cc9a2b524e 100644 --- a/sources/scala/Type.java +++ b/sources/scala/Type.java @@ -12,6 +12,7 @@ package scala; import scala.runtime.RunTime; import scala.runtime.types.ScalaClassType; +import scala.runtime.types.JavaClassType; import scala.runtime.types.TypeBoolean; import scala.runtime.types.TypeByte; import scala.runtime.types.TypeChar; @@ -73,10 +74,19 @@ abstract public class Type implements java.io.Serializable { */ public Object cast(Object o) { assert Statistics.incTypeCast(); - assert (o == null) || Statistics.decInstanceOf(); - if (! (o == null || isInstance(o))) - throw new ClassCastException("\n" + ((ScalaObject)o).getType() + "\n" + this.toString()); - return o; + if (o == null) { + if (this.isSubType(JavaLangObject)) + return null; + else + throw new ClassCastException(); + } else { + assert Statistics.decInstanceOf(); + if (isInstance(o)) + return o; + else + throw new ClassCastException("\n" + ((ScalaObject)o).getType() + + "\n" + this.toString()); + } } // Value types @@ -96,6 +106,16 @@ abstract public class Type implements java.io.Serializable { public static final TypeAllRef AllRef = new TypeAllRef(); public static final TypeAll All = new TypeAll(); + private static JavaClassType JavaLangObject; + + static { + try { + JavaLangObject = new JavaClassType("java.lang.Object"); + } catch (ClassNotFoundException e) { + throw new Error(e); + } + } + public static boolean isSameType(Type[] these, Type[] those) { if (these.length != those.length) return false; diff --git a/sources/scala/runtime/types/JavaClassType.java b/sources/scala/runtime/types/JavaClassType.java index 7779162cb9..96aed1a7e2 100644 --- a/sources/scala/runtime/types/JavaClassType.java +++ b/sources/scala/runtime/types/JavaClassType.java @@ -36,7 +36,7 @@ public class JavaClassType extends ClassType { return jct; } - private JavaClassType(String fullName) throws ClassNotFoundException { + public JavaClassType(String fullName) throws ClassNotFoundException { super(Class.forName(fullName, false, loader), true); } } diff --git a/sources/scalac/transformer/TypesAsValuesPhase.java b/sources/scalac/transformer/TypesAsValuesPhase.java index 71be22e44b..3ac714b103 100644 --- a/sources/scalac/transformer/TypesAsValuesPhase.java +++ b/sources/scalac/transformer/TypesAsValuesPhase.java @@ -426,7 +426,7 @@ public class TypesAsValuesPhase extends Phase { assert targs.length == 1 && vargs.length == 0; Type type = targs[0].type; Tree expr = transform(qualifierOf(fun)); - return isTrivial(type) + return (isTrivial(type) && !isSpecial(type)) ? super.transform(tree) : genInstanceTest(tree.pos, expr, type); } else if (funSym == defs.ANY_AS) { @@ -436,11 +436,11 @@ public class TypesAsValuesPhase extends Phase { // asValue(T).cast(e).asInstanceOf[T] // unless T is a trivial type for which a Java // instance test is sufficient, in which case the - // expression is left as is. + // erased version of asInstanceOf is used. assert targs.length == 1 && vargs.length == 0; Type type = targs[0].type; Tree expr = transform(qualifierOf(fun)); - return isTrivial(type) + return (isTrivial(type) && !isSpecial(type)) ? super.transform(tree) : genTypeCast(tree.pos, expr, type); } else if (!monoPrimitive(funSym)) { @@ -739,10 +739,17 @@ public class TypesAsValuesPhase extends Phase { private Tree genInstanceTest(int pos, Tree expr, Type tp) { Tree tpVal = typeAsValue(pos, tp, currentOwner, EENV); - if (isKnowClassType(tp) && isLocalIdent(expr)) { - Symbol sym = expr.symbol(); + if (isKnowClassType(tp)) { + Symbol val = + currentOwner.newVariable(pos, + Modifiers.SYNTHETIC, + Names.LOCAL(currentOwner)); + val.setType(expr.type); + + Tree valDef = gen.ValDef(val, expr); + Tree cheapTest = - gen.mkIsInstanceOf(pos, gen.mkLocalRef(pos, sym), tp, true); + gen.mkIsInstanceOf(pos, gen.mkLocalRef(pos, val), tp, true); Symbol weakIsInst = defs.SCALACLASSTYPE_WEAKISINSTANCE(); Tree scalaTpVal = gen.mkAsInstanceOf(pos, tpVal, @@ -751,12 +758,16 @@ public class TypesAsValuesPhase extends Phase { Tree expensiveTest = gen.mkApply_V(pos, gen.Select(pos, scalaTpVal, weakIsInst), - new Tree[] { expr }); - return gen.mkApply_V(pos, - gen.Select(pos, - cheapTest, - defs.BOOLEAN_AND()), - new Tree[] { expensiveTest }); + new Tree[] { gen.mkLocalRef(pos, val) }); + + Tree bothTests = + gen.mkApply_V(pos, + gen.Select(pos, + cheapTest, + defs.BOOLEAN_AND()), + new Tree[] { expensiveTest }); + + return gen.mkBlock(pos, valDef, bothTests); } else { Tree fun = gen.Select(pos, tpVal, defs.TYPE_ISINSTANCE()); return gen.mkApply_V(pos, fun, new Tree[] { expr }); @@ -809,19 +820,22 @@ public class TypesAsValuesPhase extends Phase { return false; } - private boolean isKnowClassType(Type tp) { + private boolean isSpecial(Type tp) { switch (tp) { case TypeRef(_, Symbol sym, _): - return (sym != defs.ARRAY_CLASS) && !sym.isParameter(); + return (sym == defs.ANY_CLASS) + || (sym == defs.ANYVAL_CLASS) + || (sym == defs.ALLREF_CLASS) + || (sym == defs.ALL_CLASS); default: return false; } } - private boolean isLocalIdent(Tree tree) { - switch (tree) { - case Ident(_): - return tree.symbol().isLocal(); + private boolean isKnowClassType(Type tp) { + switch (tp) { + case TypeRef(_, Symbol sym, _): + return (sym != defs.ARRAY_CLASS) && !sym.isParameter(); default: return false; } |