diff options
42 files changed, 1277 insertions, 1151 deletions
diff --git a/sources/meta/scalac/ast/Tree.java b/sources/meta/scalac/ast/Tree.java index d3f9847f37..6efdfea707 100644 --- a/sources/meta/scalac/ast/Tree.java +++ b/sources/meta/scalac/ast/Tree.java @@ -35,6 +35,7 @@ public class Tree { t_Global = TreeType.Reference("scalac", "Global"), t_Unit = TreeType.Reference("scalac", "Unit"), t_TreeGen = TreeType.Reference("scalac.ast", "TreeGen"), + t_AConstant = TreeType.Reference("scalac.atree", "AConstant"), t_Symbol = TreeType.Reference("scalac.symtab", "Symbol"), t_Type = TreeType.Reference("scalac.symtab", "Type"), t_Name = TreeType.Name(Any), @@ -335,7 +336,7 @@ public class Tree { n_Literal. setDescription("Literal"). setRange(Phase.PARSER, Phase.END). - addField(t_Object, "value"); + addField(t_AConstant, "value"); n_TypeTerm. setDescription("TypeTerm"). diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala index 6cd6effa88..bd22ef19f2 100644 --- a/sources/scala/tools/scalac/ast/parser/Parser.scala +++ b/sources/scala/tools/scalac/ast/parser/Parser.scala @@ -37,6 +37,10 @@ class Parser(unit: Unit) { */ val make: TreeFactory = unit.global.make; + /** the tree generator + */ + val gen: TreeGen = unit.global.treeGen; + /** pattern checker and normalizer */ val pN = new PatternNormalizer(unit); @@ -571,23 +575,23 @@ class Parser(unit: Unit) { def literal(isPattern: boolean): Tree = { def litToTree() = s.token match { case CHARLIT => - make.Literal(s.pos, new Character(s.intVal.asInstanceOf[char])) + gen.mkCharLit(s.pos, s.intVal.asInstanceOf[char]) case INTLIT => - make.Literal(s.pos, new Integer(s.intVal.asInstanceOf[int])) + gen.mkIntLit(s.pos, s.intVal.asInstanceOf[int]) case LONGLIT => - make.Literal(s.pos, new Long(s.intVal)) + gen.mkLongLit(s.pos, s.intVal) case FLOATLIT => - make.Literal(s.pos, new Float(s.floatVal.asInstanceOf[float])) + gen.mkFloatLit(s.pos, s.floatVal.asInstanceOf[float]) case DOUBLELIT => - make.Literal(s.pos, new Double(s.floatVal)) + gen.mkDoubleLit(s.pos, s.floatVal) case STRINGLIT | SYMBOLLIT => - make.Literal(s.pos, s.name.toString()) + gen.mkStringLit(s.pos, s.name.toString()) case TRUE => - make.Literal(s.pos, java.lang.Boolean.TRUE) + gen.mkBooleanLit(s.pos, true) case FALSE => - make.Literal(s.pos, java.lang.Boolean.FALSE) + gen.mkBooleanLit(s.pos, false) case NULL => - make.Ident(s.pos, Names.null_) + gen.mkNullLit(s.pos) case _ => syntaxError("illegal literal", true) } @@ -1083,10 +1087,10 @@ class Parser(unit: Unit) { NewArray.CaseDef( make.CaseDef( rhs.pos, pat.duplicate(), - Tree.Empty, make.Literal(s.pos, java.lang.Boolean.TRUE)), + Tree.Empty, gen.mkBooleanLit(s.pos, true)), make.CaseDef( rhs.pos, make.Ident(rhs.pos, Names.PATTERN_WILDCARD), - Tree.Empty, make.Literal(s.pos, java.lang.Boolean.FALSE)))))); + Tree.Empty, gen.mkBooleanLit(s.pos, false)))))); make.PatDef(pos, 0, pat, rhs) } diff --git a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala index d073ec135a..f7a43f3ee7 100644 --- a/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala +++ b/sources/scala/tools/scalac/ast/printer/TextTreePrinter.scala @@ -471,12 +471,7 @@ class TextTreePrinter(writer: PrintWriter) with TreePrinter { printType(tree); case Tree$Literal(obj) => - val str = obj match { - case s: String => "\"" + s + "\""; - case c: Character => "\'" + c + "\'"; - case _ => String.valueOf(obj); - } - print(Literal(str)); + print(Literal(obj.toString())); printType(tree); case Tree$TypeTerm() => diff --git a/sources/scala/tools/scalac/backend/GenJVMFromICode.scala b/sources/scala/tools/scalac/backend/GenJVMFromICode.scala index a7b5627452..a3f81e9bfd 100644 --- a/sources/scala/tools/scalac/backend/GenJVMFromICode.scala +++ b/sources/scala/tools/scalac/backend/GenJVMFromICode.scala @@ -32,7 +32,7 @@ class GenJVMFromICode(global: scalac_Global) { private val fjbgContext = new FJBGContext(); - private val typer = new ATreeTyper(global); + private val typer = defs.atyper; // ################################################## // Private fields - Data diff --git a/sources/scala/tools/scalac/icode/ICTypeStack.scala b/sources/scala/tools/scalac/icode/ICTypeStack.scala index 4bb93c9b1f..750821db13 100644 --- a/sources/scala/tools/scalac/icode/ICTypeStack.scala +++ b/sources/scala/tools/scalac/icode/ICTypeStack.scala @@ -22,10 +22,10 @@ class ICTypeStack() { private val global = Global.instance; - private val typer = new ATreeTyper(global); // !!! Using atree typer ! - private val definitions = global.definitions; + private val typer = definitions.atyper; // !!! Using atree typer ! + // ################################################## // Private constructor diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala index 49533273a5..da8e2d5c65 100644 --- a/sources/scala/tools/scalac/typechecker/Analyzer.scala +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -19,6 +19,9 @@ import scalac._; import scalac.util._; import scalac.ast._; import scalac.ast.printer._; +import scalac.atree.AConstant; +import scalac.atree.AConstant$CHAR; +import scalac.atree.AConstant$INT; import scalac.symtab._; import scalac.symtab.classfile._; import Tree._; @@ -39,7 +42,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( val definitions = global.definitions; val infer = new scala.tools.scalac.typechecker.Infer(this); val desugarize = new DeSugarize(make, copy, gen, infer, global); - val constfold = new ConstantFolder(this); + val constfold = new ConstantFolder(global); var unit: Unit = _; @@ -1400,22 +1403,22 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( } if (!(owntype.isInstanceOf[Type$PolyType] || owntype.isSubType(pt))) { tree match { - case Tree$Literal(value) => - var n: int = Integer.MAX_VALUE; - if (value.isInstanceOf[Integer]) - n = value.asInstanceOf[Integer].intValue(); - else if (value.isInstanceOf[Character]) - n = value.asInstanceOf[Character].charValue(); - val value1: Object = + case Tree$Literal(constant) => + var n: int = constant match { + case AConstant$INT(value) => value + case AConstant$CHAR(value) => value + case _ => Integer.MAX_VALUE + } + val value1: AConstant = if (pt.symbol() == definitions.BYTE_CLASS && -128 <= n && n <= 127) - new Byte(n.asInstanceOf[byte]) + AConstant.BYTE(n.asInstanceOf[byte]) else if (pt.symbol() == definitions.SHORT_CLASS && -32768 <= n && n <= 32767) - new Short(n.asInstanceOf[short]) + AConstant.SHORT(n.asInstanceOf[short]) else if (pt.symbol() == definitions.CHAR_CLASS && 0 <= n && n <= 65535) - new Character(n.asInstanceOf[char]) + AConstant.CHAR(n.asInstanceOf[char]) else null; if (value1 != null) - return make.Literal(tree.pos, value1).setType(new Type$ConstantType(pt, value1)); + return gen.Literal(tree.pos, value1); case _ => } if ((mode & EXPRmode) != 0) { diff --git a/sources/scala/tools/scalac/typechecker/ConstantFolder.scala b/sources/scala/tools/scalac/typechecker/ConstantFolder.scala index 22950466ca..07909efc70 100644 --- a/sources/scala/tools/scalac/typechecker/ConstantFolder.scala +++ b/sources/scala/tools/scalac/typechecker/ConstantFolder.scala @@ -10,327 +10,13 @@ * if this copyright notice stays attached. *************************************************************************/ -import scalac.util._; -import scalac.ast._; -import scalac.symtab._; -import java.lang.{Byte,Character,Short,Integer,Long,Float,Double,Boolean,Object,Number} +import scalac.{Global => scalac_Global} +import scalac.typechecker.{ConstantFolder => scalac_typechecker_ConstantFolder} package scala.tools.scalac.typechecker { -class ConstantFolder(ana: Analyzer) { - - import TypeTags._; - - /** fold binary operation. - */ - def foldBinary(pos: int, left: Type$ConstantType, right: Type$ConstantType, op: Name): Type = { - try { - var ltype: Type = left.deconst(); - var lsymbol: Symbol = left.symbol(); - if (lsymbol == ana.definitions.BYTE_CLASS || - lsymbol == ana.definitions.CHAR_CLASS || - lsymbol == ana.definitions.SHORT_CLASS) { - ltype = ana.definitions.INT_TYPE(); - lsymbol = ana.definitions.INT_CLASS; - } - var rtype: Type = right.deconst(); - var rsymbol: Symbol = right.symbol(); - if (rsymbol == ana.definitions.BYTE_CLASS || - rsymbol == ana.definitions.CHAR_CLASS || - rsymbol == ana.definitions.SHORT_CLASS) { - rtype = ana.definitions.INT_TYPE(); - rsymbol = ana.definitions.INT_CLASS; - } - val optype: Type = - if (ltype.isSameAs(rtype)) - ltype; - else if (lsymbol == ana.definitions.JAVA_STRING_CLASS) - ltype; - else if (rsymbol == ana.definitions.JAVA_STRING_CLASS) - rtype; - else if (lsymbol == ana.definitions.INT_CLASS) - rtype; - else if (rsymbol == ana.definitions.INT_CLASS) - ltype; - else if (lsymbol == ana.definitions.LONG_CLASS) - rtype; - else if (rsymbol == ana.definitions.LONG_CLASS) - ltype; - else if (lsymbol == ana.definitions.FLOAT_CLASS) - rtype; - else if (rsymbol == ana.definitions.FLOAT_CLASS) - ltype; - else - throw Debug.abort("illegal case", ltype.toString() +" - "+ rtype); - var value: Object = null; - optype.unbox() match { - case Type$UnboxedType(INT) => - if (op == Names.ADD) - value = new Integer(left.intValue() + right.intValue()); - else if (op == Names.SUB) - value = new Integer(left.intValue() - right.intValue()); - else if (op == Names.MUL) - value = new Integer(left.intValue() * right.intValue()); - else if (op == Names.DIV) - value = new Integer(left.intValue() / right.intValue()); - else if (op == Names.MOD) - value = new Integer(left.intValue() % right.intValue()); - else if (op == Names.EQ) - value = new Boolean(left.intValue() == right.intValue()); - else if (op == Names.NE) - value = new Boolean(left.intValue() != right.intValue()); - else if (op == Names.LT) - value = new Boolean(left.intValue() < right.intValue()); - else if (op == Names.GT) - value = new Boolean(left.intValue() > right.intValue()); - else if (op == Names.LE) - value = new Boolean(left.intValue() <= right.intValue()); - else if (op == Names.GE) - value = new Boolean(left.intValue() >= right.intValue()); - else if (op == Names.OR) - value = new Integer(left.intValue() | right.intValue()); - else if (op == Names.AND) - value = new Integer(left.intValue() & right.intValue()); - else if (op == Names.XOR) - value = new Integer(left.intValue() ^ right.intValue()); - else if (op == Names.LSL) - value = new Integer(left.intValue() << right.intValue()); - else if (op == Names.LSR) - value = new Integer(left.intValue() >>> right.intValue()); - else if (op == Names.ASR) - value = new Integer(left.intValue() >> right.intValue()); - - case Type$UnboxedType(LONG) => - if (op == Names.ADD) - value = new Long(left.longValue() + right.longValue()); - else if (op == Names.SUB) - value = new Long(left.longValue() - right.longValue()); - else if (op == Names.MUL) - value = new Long(left.longValue() * right.longValue()); - else if (op == Names.DIV) - value = new Long(left.longValue() / right.longValue()); - else if (op == Names.MOD) - value = new Long(left.longValue() % right.longValue()); - else if (op == Names.EQ) - value = new Boolean(left.longValue() == right.longValue()); - else if (op == Names.NE) - value = new Boolean(left.longValue() != right.longValue()); - else if (op == Names.LT) - value = new Boolean(left.longValue() < right.longValue()); - else if (op == Names.GT) - value = new Boolean(left.longValue() > right.longValue()); - else if (op == Names.LE) - value = new Boolean(left.longValue() <= right.longValue()); - else if (op == Names.GE) - value = new Boolean(left.longValue() >= right.longValue()); - else if (op == Names.OR) - value = new Long(left.longValue() | right.longValue()); - else if (op == Names.AND) - value = new Long(left.longValue() & right.longValue()); - else if (op == Names.XOR) - value = new Long(left.longValue() ^ right.longValue()); - else if (op == Names.LSL) - value = new Long(left.longValue() << right.intValue()); - else if (op == Names.LSR) - value = new Long(left.longValue() >>> right.intValue()); - else if (op == Names.ASR) - value = new Long(left.longValue() >> right.intValue()); - - case Type$UnboxedType(FLOAT) => - if (op == Names.ADD) - value = new Float(left.floatValue() + right.floatValue()); - else if (op == Names.SUB) - value = new Float(left.floatValue() - right.floatValue()); - else if (op == Names.MUL) - value = new Float(left.floatValue() * right.floatValue()); - else if (op == Names.DIV) - value = new Float(left.floatValue() / right.floatValue()); - else if (op == Names.MOD) - value = new Float(left.floatValue() % right.floatValue()); - else if (op == Names.EQ) - value = new Boolean(left.floatValue() == right.floatValue()); - else if (op == Names.NE) - value = new Boolean(left.floatValue() != right.floatValue()); - else if (op == Names.LT) - value = new Boolean(left.floatValue() < right.floatValue()); - else if (op == Names.GT) - value = new Boolean(left.floatValue() > right.floatValue()); - else if (op == Names.LE) - value = new Boolean(left.floatValue() <= right.floatValue()); - else if (op == Names.GE) - value = new Boolean(left.floatValue() >= right.floatValue()); - - case Type$UnboxedType(DOUBLE) => - if (op == Names.ADD) - value = new Double(left.doubleValue() + right.doubleValue()); - else if (op == Names.SUB) - value = new Double(left.doubleValue() - right.doubleValue()); - else if (op == Names.MUL) - value = new Double(left.doubleValue() * right.doubleValue()); - else if (op == Names.DIV) - value = new Double(left.doubleValue() / right.doubleValue()); - else if (op == Names.MOD) - value = new Double(left.doubleValue() % right.doubleValue()); - else if (op == Names.EQ) - value = new Boolean(left.doubleValue() == right.doubleValue()); - else if (op == Names.NE) - value = new Boolean(left.doubleValue() != right.doubleValue()); - else if (op == Names.LT) - value = new Boolean(left.doubleValue() < right.doubleValue()); - else if (op == Names.GT) - value = new Boolean(left.doubleValue() > right.doubleValue()); - else if (op == Names.LE) - value = new Boolean(left.doubleValue() <= right.doubleValue()); - else if (op == Names.GE) - value = new Boolean(left.doubleValue() >= right.doubleValue()); - - case Type$UnboxedType(BOOLEAN) => - if (op == Names.EQ) - value = new Boolean(left.booleanValue() == right.booleanValue()); - else if (op == Names.NE) - value = new Boolean(left.booleanValue() != right.booleanValue()); - else if (op == Names.OR || op == Names.ZOR) - value = new Boolean(left.booleanValue() | right.booleanValue()); - else if (op == Names.AND || op == Names.ZAND) - value = new Boolean(left.booleanValue() & right.booleanValue()); - else if (op == Names.XOR) - value = new Boolean(left.booleanValue() ^ right.booleanValue()); - - case _ => - if (optype.symbol() == ana.definitions.JAVA_STRING_CLASS && - op == Names.ADD) - value = left.stringValue() + right.stringValue(); - } - if (value != null) Type.constantType(value) else Type.NoType; - } catch { - case e: ArithmeticException => - ana.unit.warning(pos, e.toString()); - Type.NoType - } - } - - /** fold unary operation. - */ - def foldUnary(pos: int, od: Type$ConstantType, op: Name): Type = { - try { - var value: Object = null; - od.deconst().unbox() match { - case Type$UnboxedType(INT) => - if (op == Names.ADD) - value = new Integer(od.intValue()); - else if (op == Names.SUB) - value = new Integer(-od.intValue()); - else if (op == Names.NOT) - value = new Integer(~od.intValue()); - - case Type$UnboxedType(LONG) => - if (op == Names.ADD) - value = new Long(od.longValue()); - else if (op == Names.SUB) - value = new Long(-od.longValue()); - else if (op == Names.NOT) - value = new Long(~od.longValue()); - - case Type$UnboxedType(FLOAT) => - if (op == Names.ADD) - value = new Float(od.floatValue()); - else if (op == Names.SUB) - value = new Float(-od.floatValue()); - - case Type$UnboxedType(DOUBLE) => - if (op == Names.ADD) - value = new Double(od.doubleValue()); - else if (op == Names.SUB) - value = new Double(-od.doubleValue()); - - case Type$UnboxedType(BOOLEAN) => - if (op == Names.ZNOT) - value = new Boolean(!od.booleanValue()); - - case _ => - } - if (value != null) Type.constantType(value) else Type.NoType; - } catch { - case e: ArithmeticException => - ana.unit.warning(pos, e.toString()); - Type.NoType - } - } - - /** fold cast operation - */ - def foldAsInstanceOf(pos: int, od: Type$ConstantType, argtype: Type): Type = { - try { - var value: Object = null; - argtype.unbox() match { - case Type$UnboxedType(BYTE) => - value = new Byte(od.intValue().asInstanceOf[byte]); - - case Type$UnboxedType(CHAR) => - value = new Character(od.intValue().asInstanceOf[char]); - - case Type$UnboxedType(SHORT) => - value = new Short(od.intValue().asInstanceOf[short]); - - case Type$UnboxedType(INT) => - value = new Integer(od.intValue()); - - case Type$UnboxedType(LONG) => - value = new Long(od.longValue()); - - case Type$UnboxedType(FLOAT) => - value = new Float(od.longValue()); - - case Type$UnboxedType(DOUBLE) => - value = new Double(od.doubleValue()); - - case Type$UnboxedType(BOOLEAN) => - value = new Boolean(od.booleanValue()); - - case _ => - } - if (value != null) new Type$ConstantType(argtype, value) else Type.NoType; - } catch { - case e: ClassCastException => - ana.unit.warning(pos, e.toString()); - Type.NoType - } - } - - /** attempt to constant fold tree. - */ - def tryToFold(tree: Tree): Tree = { - var ctp: Type = Type.NoType; - tree match { - case Tree$Apply(Tree$Select(qual, op), args) => - if (qual.getType().isInstanceOf[Type$ConstantType]) { - if (args.length == 0) - ctp = foldUnary( - tree.pos, qual.getType().asInstanceOf[Type$ConstantType], op); - else if (args.length == 1 && - args(0).getType().isInstanceOf[Type$ConstantType]) - ctp = foldBinary( - tree.pos, - qual.getType().asInstanceOf[Type$ConstantType], - args(0).getType().asInstanceOf[Type$ConstantType], - op); - } - - case Tree$TypeApply(Tree$Select(qual, op), targs) => - qual.getType() match { - case ct: Type$ConstantType if (op == Names.asInstanceOf) => - ctp = foldAsInstanceOf(tree.pos, ct, targs(0).getType()); - case _ => - } - - case _ => - } - ctp match { - case Type$ConstantType(base, value) => - ana.make.Literal(tree.pos, value).setType(ctp); - case _ => - tree - } - } +class ConstantFolder(g: scalac_Global) extends scalac_typechecker_ConstantFolder(g) { + // !!! rewrite } + } diff --git a/sources/scala/tools/scaladoc/SymbolTablePrinter.java b/sources/scala/tools/scaladoc/SymbolTablePrinter.java index 25ea8e8bc7..b5a1db9dab 100644 --- a/sources/scala/tools/scaladoc/SymbolTablePrinter.java +++ b/sources/scala/tools/scaladoc/SymbolTablePrinter.java @@ -14,6 +14,7 @@ import ch.epfl.lamp.util.CodePrinter; import ch.epfl.lamp.util.HTMLPrinter; import scalac.Global; +import scalac.atree.AConstant; import scalac.symtab.*; import scalac.symtab.Scope.SymbolIterator; import scalac.symtab.Type.Constraint; @@ -401,7 +402,7 @@ public abstract class SymbolTablePrinter extends scalac.symtab.SymbolTablePrinte printUsedSymbolName(sym); return this; - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): printType(base); // print("("); // print(value.toString()); diff --git a/sources/scala/tools/scalai/ExpressionCompiler.java b/sources/scala/tools/scalai/ExpressionCompiler.java index 8f76849ccd..35eb5edbca 100644 --- a/sources/scala/tools/scalai/ExpressionCompiler.java +++ b/sources/scala/tools/scalai/ExpressionCompiler.java @@ -13,6 +13,7 @@ import java.lang.reflect.Constructor; import java.util.ArrayList; import scalac.ast.Tree; +import scalac.atree.AConstant; import scalac.symtab.Symbol; import scalac.symtab.Definitions; import scalac.util.Debug; @@ -166,8 +167,33 @@ public class ExpressionCompiler { case This(_): return Code.Self; - case Literal(Object value): - return Code.Literal(value); + case Literal(AConstant constant): + switch (constant) { + case UNIT: + return Code.Literal(constants.literal()); + case BOOLEAN(boolean value): + return Code.Literal(new Boolean(value)); + case BYTE(byte value): + return Code.Literal(new Byte(value)); + case SHORT(short value): + return Code.Literal(new Short(value)); + case CHAR(char value): + return Code.Literal(new Character(value)); + case INT(int value): + return Code.Literal(new Integer(value)); + case LONG(long value): + return Code.Literal(new Long(value)); + case FLOAT(float value): + return Code.Literal(new Float(value)); + case DOUBLE(double value): + return Code.Literal(new Double(value)); + case STRING(String value): + return Code.Literal(new String(value)); + case NULL: + return Code.Null; + default: + throw Debug.abort("illegal case", constant); + } default: return load(tree, tree.symbol()); diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index 37e2ed95d9..3c24f16468 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -452,9 +452,8 @@ public class Global { SET_EVALUATION_RESULT()), new Tree[] { last, - make.Literal(last.pos, - show(last.getType())).setType( - definitions.JAVA_STRING_TYPE())}); + treeGen.mkStringLit( + last.pos, show(last.getType()))}); } TreeList body = new TreeList(); for (int j = 0; j < impl.body.length; j++) @@ -484,8 +483,7 @@ public class Global { treeGen.mkRef(tree.pos, INTERPRETER()), SHOW_DEFINITION()), new Tree[] { - make.Literal(tree.pos, show(tree.symbol())).setType( - definitions.JAVA_STRING_TYPE())})); + treeGen.mkStringLit(tree.pos, show(tree.symbol()))})); return; case ValDef(_, _, _, _): if (!mustShow(tree.symbol())) return; @@ -495,8 +493,7 @@ public class Global { treeGen.mkRef(tree.pos, INTERPRETER()), SHOW_VALUE_DEFINITION()), new Tree[] { - make.Literal(tree.pos, show(tree.symbol())).setType( - definitions.JAVA_STRING_TYPE()), + treeGen.mkStringLit(tree.pos, show(tree.symbol())), treeGen.Ident(tree.pos, tree.symbol())})); return; default: diff --git a/sources/scalac/ast/Transformer.java.tmpl b/sources/scalac/ast/Transformer.java.tmpl index 32f69eb3b5..69aef7dfca 100644 --- a/sources/scalac/ast/Transformer.java.tmpl +++ b/sources/scalac/ast/Transformer.java.tmpl @@ -265,8 +265,8 @@ public class GenTransformer { Symbol symbol = getSymbolFor(tree); return gen.Ident(tree.pos, symbol); - case Literal(Object value): - return gen.mkLit(tree.pos, value); + case Literal(AConstant value): + return gen.Literal(tree.pos, value); case TypeTerm(): return gen.mkType(tree.pos, transform(tree.type())); diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java index 2718287946..669f513c78 100644 --- a/sources/scalac/ast/TreeGen.java +++ b/sources/scalac/ast/TreeGen.java @@ -10,6 +10,7 @@ package scalac.ast; import scalac.Global; import scalac.ast.Tree.*; +import scalac.atree.AConstant; import scalac.symtab.*; import scalac.typechecker.Infer; import scalac.util.*; @@ -94,154 +95,64 @@ public class TreeGen implements Kinds, Modifiers, TypeTags { //######################################################################## // Public Methods - Building constants - /** Builds a literal. */ - public Tree mkLit(int pos, Object value) { - if (value instanceof Boolean) return mkBooleanLit(pos, (Boolean)value); - if (value instanceof Byte) return mkByteLit(pos, (Byte)value); - if (value instanceof Short) return mkShortLit(pos, (Short)value); - if (value instanceof Character) return mkCharLit(pos,(Character)value); - if (value instanceof Integer) return mkIntLit(pos, (Integer)value); - if (value instanceof Long) return mkLongLit(pos, (Long)value); - if (value instanceof Float) return mkFloatLit(pos, (Float)value); - if (value instanceof Double) return mkDoubleLit(pos, (Double)value); - if (value instanceof String) return mkStringLit(pos, (String)value); - throw Debug.abort("unknown literal class " + value.getClass(), value); - } - /** Builds a unit literal. */ public Tree mkUnitLit(int pos) { - return Block(pos, Tree.EMPTY_ARRAY); + return Literal(pos, AConstant.UNIT); } /** Builds a boolean literal. */ public Tree mkBooleanLit(int pos, boolean value) { - return mkBooleanLit(pos, value ? Boolean.TRUE : Boolean.FALSE); - } - - /** Builds a boolean literal. */ - public Tree mkBooleanLit(int pos, Boolean value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.BOOLEAN_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.BOOLEAN(value)); } /** Builds a byte literal. */ public Tree mkByteLit(int pos, byte value) { - return mkByteLit(pos, new Byte(value)); - } - - /** Builds a byte literal. */ - public Tree mkByteLit(int pos, Byte value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.BYTE_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.BYTE(value)); } /** Builds a short literal. */ public Tree mkShortLit(int pos, short value) { - return mkShortLit(pos, new Short(value)); - } - - /** Builds a short literal. */ - public Tree mkShortLit(int pos, Short value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.SHORT_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.SHORT(value)); } /** Builds a character literal. */ public Tree mkCharLit(int pos, char value) { - return mkCharLit(pos, new Character(value)); - } - - /** Builds a character literal. */ - public Tree mkCharLit(int pos, Character value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.CHAR_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.CHAR(value)); } /** Builds an integer literal */ public Tree mkIntLit(int pos, int value) { - return mkIntLit(pos, new Integer(value)); - } - - /** Builds an integer literal */ - public Tree mkIntLit(int pos, Integer value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.INT_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.INT(value)); } /** Builds a long literal. */ public Tree mkLongLit(int pos, long value) { - return mkLongLit(pos, new Long(value)); - } - - /** Builds a long literal. */ - public Tree mkLongLit(int pos, Long value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.LONG_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.LONG(value)); } /** Builds a float literal. */ public Tree mkFloatLit(int pos, float value) { - return mkFloatLit(pos, new Float(value)); - } - - /** Builds a float literal. */ - public Tree mkFloatLit(int pos, Float value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.FLOAT_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.FLOAT(value)); } /** Builds a double literal. */ public Tree mkDoubleLit(int pos, double value) { - return mkDoubleLit(pos, new Double(value)); - } - - /** Builds a double literal. */ - public Tree mkDoubleLit(int pos, Double value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.DOUBLE_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.DOUBLE(value)); } /** Builds a string literal. */ public Tree mkStringLit(int pos, String value) { - Tree tree = make.Literal(pos, value); - global.nextPhase(); - tree.setType(definitions.STRING_TYPE()); - global.prevPhase(); - return tree; + return Literal(pos, AConstant.STRING(value)); } /** Builds a null literal. */ public Tree mkNullLit(int pos) { - return Ident(pos, definitions.NULL); + return Literal(pos, AConstant.NULL); } /** Builds a zero literal. */ public Tree mkZeroLit(int pos) { - return Ident(pos, definitions.ZERO); + return Literal(pos, AConstant.ZERO); } /** Builds a default zero value according to given type tag. */ @@ -269,6 +180,15 @@ public class TreeGen implements Kinds, Modifiers, TypeTags { return mkZeroLit(pos); } + /** Builds a Literal node of given value. */ + public Literal Literal(int pos, AConstant value) { + Literal tree = make.Literal(pos, value); + global.nextPhase(); + tree.setType(definitions.atyper.type(value)); + global.prevPhase(); + return tree; + } + //######################################################################## // Public Methods - Building references diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java index d98324c970..12226aa922 100644 --- a/sources/scalac/ast/parser/Parser.java +++ b/sources/scalac/ast/parser/Parser.java @@ -32,6 +32,10 @@ public class Parser implements Tokens { */ TreeFactory make; + /** the tree generator + */ + TreeGen gen; + /** pattern checker and normalizer */ PatternNormalizer pN; @@ -43,6 +47,7 @@ public class Parser implements Tokens { public Parser(Unit unit) { s = new Scanner(unit); make = unit.global.make; + gen = unit.global.treeGen; pN = new PatternNormalizer( unit ); mapTreeComment = unit.global.mapTreeComment; loopNestingDepth = 0; @@ -620,38 +625,38 @@ public class Parser implements Tokens { Tree t; switch (s.token) { case CHARLIT: - t = make.Literal(s.pos, new Character((char)s.intVal)); + t = gen.mkCharLit(s.pos, (char)s.intVal); break; case INTLIT: - t = make.Literal(s.pos, new Integer((int)s.intVal)); + t = gen.mkIntLit(s.pos, (int)s.intVal); break; case LONGLIT: - t = make.Literal(s.pos, new Long(s.intVal)); + t = gen.mkLongLit(s.pos, s.intVal); break; case FLOATLIT: - t = make.Literal(s.pos, new Float((float)s.floatVal)); + t = gen.mkFloatLit(s.pos, (float)s.floatVal); break; case DOUBLELIT: - t = make.Literal(s.pos, new Double(s.floatVal)); + t = gen.mkDoubleLit(s.pos, s.floatVal); break; case STRINGLIT: - t = make.Literal(s.pos, s.name.toString()); + t = gen.mkStringLit(s.pos, s.name.toString()); break; case TRUE: - t = make.Literal(s.pos, Boolean.TRUE); + t = gen.mkBooleanLit(s.pos, true); break; case FALSE: - t = make.Literal(s.pos, Boolean.FALSE); + t = gen.mkBooleanLit(s.pos, false); break; case NULL: - t = make.Ident(s.pos, Names.null_); + t = gen.mkNullLit(s.pos); break; case SYMBOLLIT: int pos = s.pos; Tree symt = scalaDot(s.pos, Names.Symbol); if (isPattern) symt = convertToTypeId(symt); TreeList ts = new TreeList(); - ts.append(make.Literal(s.pos, s.name.toString())); + ts.append(gen.mkStringLit(s.pos, s.name.toString())); s.nextToken(); if (s.token == LPAREN || s.token == LBRACE) ts.append(argumentExprs()); @@ -1171,10 +1176,10 @@ public class Parser implements Tokens { new Tree.CaseDef[]{ (CaseDef)make.CaseDef( rhs.pos, pat.duplicate(), Tree.Empty, - make.Literal(s.pos, Boolean.TRUE)), + gen.mkBooleanLit(s.pos, true)), (CaseDef)make.CaseDef( rhs.pos, make.Ident(rhs.pos, Names.PATTERN_WILDCARD), Tree.Empty, - make.Literal(s.pos, Boolean.FALSE))})}); + gen.mkBooleanLit(s.pos, false))})}); return make.PatDef(pos, 0, pat, rhs); } diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java index 730c53fe06..cbe607b3b2 100644 --- a/sources/scalac/ast/printer/TextTreePrinter.java +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -10,6 +10,7 @@ package scalac.ast.printer; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.symtab.*; import scalac.util.Debug; import scalac.Global; @@ -558,15 +559,8 @@ public class TextTreePrinter implements TreePrinter { printType(tree); break; - case Literal(Object obj): - String str; - if (obj instanceof String) - str = "\"" + obj + "\""; - else if (obj instanceof Character) - str = "\'" + obj + "\'"; - else - str = String.valueOf(obj); - print(Text.Literal(str)); + case Literal(AConstant value): + print(Text.Literal(value.toString())); printType(tree); break; diff --git a/sources/scalac/atree/AConstant.java b/sources/scalac/atree/AConstant.java index 626ab2a5da..4abd485f66 100644 --- a/sources/scalac/atree/AConstant.java +++ b/sources/scalac/atree/AConstant.java @@ -8,6 +8,8 @@ package scalac.atree; +import scalac.util.Debug; + /** This class represents a constant. */ public class AConstant { @@ -30,6 +32,347 @@ public class AConstant { //######################################################################## // Public Methods + /** Returns the type kind of this constant. */ + public ATypeKind kind() { + switch (this) { + case UNIT: + return ATypeKind.UNIT; + case BOOLEAN(_): + return ATypeKind.BOOL; + case BYTE(_): + return ATypeKind.I1; + case SHORT(_): + return ATypeKind.I2; + case CHAR(_): + return ATypeKind.U2; + case INT(_): + return ATypeKind.I4; + case LONG(_): + return ATypeKind.I8; + case FLOAT(_): + return ATypeKind.R4; + case DOUBLE(_): + return ATypeKind.R8; + case STRING(_): + return ATypeKind.STR; + case NULL: + return ATypeKind.NULL; + case ZERO: + return ATypeKind.ZERO; + default: + throw Debug.abort("unknown case", this); + } + } + + + /** Converts this constant to a boolean value. */ + public boolean booleanValue() { + switch (this) { + case BOOLEAN(boolean value): + return value; + default: + throw Debug.abort("not convertible to boolean", this); + } + } + + /** Converts this constant to a byte value. */ + public byte byteValue() { + switch (this) { + case BYTE(byte value): + return (byte)value; + case SHORT(short value): + return (byte)value; + case CHAR(char value): + return (byte)value; + case INT(int value): + return (byte)value; + case LONG(long value): + return (byte)value; + case FLOAT(float value): + return (byte)value; + case DOUBLE(double value): + return (byte)value; + default: + throw Debug.abort("not convertible to byte", this); + } + } + + /** Converts this constant to a short value. */ + public short shortValue() { + switch (this) { + case BYTE(byte value): + return (short)value; + case SHORT(short value): + return (short)value; + case CHAR(char value): + return (short)value; + case INT(int value): + return (short)value; + case LONG(long value): + return (short)value; + case FLOAT(float value): + return (short)value; + case DOUBLE(double value): + return (short)value; + default: + throw Debug.abort("not convertible to short", this); + } + } + + /** Converts this constant to a char value. */ + public char charValue() { + switch (this) { + case BYTE(byte value): + return (char)value; + case SHORT(short value): + return (char)value; + case CHAR(char value): + return (char)value; + case INT(int value): + return (char)value; + case LONG(long value): + return (char)value; + case FLOAT(float value): + return (char)value; + case DOUBLE(double value): + return (char)value; + default: + throw Debug.abort("not convertible to char", this); + } + } + + /** Converts this constant to a int value. */ + public int intValue() { + switch (this) { + case BYTE(byte value): + return (int)value; + case SHORT(short value): + return (int)value; + case CHAR(char value): + return (int)value; + case INT(int value): + return (int)value; + case LONG(long value): + return (int)value; + case FLOAT(float value): + return (int)value; + case DOUBLE(double value): + return (int)value; + default: + throw Debug.abort("not convertible to int", this); + } + } + + /** Converts this constant to a long value. */ + public long longValue() { + switch (this) { + case BYTE(byte value): + return (long)value; + case SHORT(short value): + return (long)value; + case CHAR(char value): + return (long)value; + case INT(int value): + return (long)value; + case LONG(long value): + return (long)value; + case FLOAT(float value): + return (long)value; + case DOUBLE(double value): + return (long)value; + default: + throw Debug.abort("not convertible to long", this); + } + } + + /** Converts this constant to a float value. */ + public float floatValue() { + switch (this) { + case BYTE(byte value): + return (float)value; + case SHORT(short value): + return (float)value; + case CHAR(char value): + return (float)value; + case INT(int value): + return (float)value; + case LONG(long value): + return (float)value; + case FLOAT(float value): + return (float)value; + case DOUBLE(double value): + return (float)value; + default: + throw Debug.abort("not convertible to float", this); + } + } + + /** Converts this constant to a double value. */ + public double doubleValue() { + switch (this) { + case BYTE(byte value): + return (double)value; + case SHORT(short value): + return (double)value; + case CHAR(char value): + return (double)value; + case INT(int value): + return (double)value; + case LONG(long value): + return (double)value; + case FLOAT(float value): + return (double)value; + case DOUBLE(double value): + return (double)value; + default: + throw Debug.abort("not convertible to double", this); + } + } + + /** Converts this constant to a String value. */ + public String stringValue() { + switch (this) { + case UNIT: + return "()"; + case BOOLEAN(boolean value): + return String.valueOf(value); + case BYTE(byte value): + return String.valueOf(value); + case SHORT(short value): + return String.valueOf(value); + case CHAR(char value): + return String.valueOf(value); + case INT(int value): + return String.valueOf(value); + case LONG(long value): + return String.valueOf(value); + case FLOAT(float value): + return String.valueOf(value); + case DOUBLE(double value): + return String.valueOf(value); + case STRING(String value): + return value; + case NULL: + return String.valueOf(null); + default: + throw Debug.abort("not convertible to String", this); + } + } + + /** Tests whether this constant equals given Object. */ + public boolean equals(Object that) { + if (this == that) return true; + return (that instanceof AConstant) && this.equals((AConstant)that); + } + + /** Tests whether this constant equals given one. */ + public boolean equals(AConstant that) { + if (this == that) return true; + if (null == that) return false; + switch (this) { + case BOOLEAN(boolean ivalue): + switch (that) { + case BOOLEAN(boolean avalue): + return ivalue == avalue; + default: + return false; + } + case BYTE(byte ivalue): + switch (that) { + case BYTE(byte avalue): + return ivalue == avalue; + default: + return false; + } + case SHORT(short ivalue): + switch (that) { + case SHORT(short avalue): + return ivalue == avalue; + default: + return false; + } + case CHAR(char ivalue): + switch (that) { + case CHAR(char avalue): + return ivalue == avalue; + default: + return false; + } + case INT(int ivalue): + switch (that) { + case INT(int avalue): + return ivalue == avalue; + default: + return false; + } + case LONG(long ivalue): + switch (that) { + case LONG(long avalue): + return ivalue == avalue; + default: + return false; + } + case FLOAT(float ivalue): + switch (that) { + case FLOAT(float avalue): + return ivalue == avalue; + default: + return false; + } + case DOUBLE(double ivalue): + switch (that) { + case DOUBLE(double avalue): + return ivalue == avalue; + default: + return false; + } + case STRING(String ivalue): + switch (that) { + case STRING(String avalue): + return ivalue.equals(avalue); + default: + return false; + } + default: + throw Debug.abort("unknown case", this); + } + } + + /** Returns the hash code of this constant. */ + public int hashCode() { + switch (this) { + case UNIT: + return 4041; + case BOOLEAN(boolean value): + return value ? 1231 : 1237; + case BYTE(byte value): + return value; + case SHORT(short value): + return value; + case CHAR(char value): + return value; + case INT(int value): + return value; + case LONG(long value): + long bits = value; + return (int)(bits ^ (bits >>> 32)); + case FLOAT(float value): + int bits = java.lang.Float.floatToIntBits(value); + return bits; + case DOUBLE(double value): + long bits = java.lang.Double.doubleToLongBits(value); + return (int)(bits ^ (bits >>> 32)); + case STRING(String value): + return value.hashCode(); + case NULL: + return 0; + case ZERO: + return 0; + default: + throw Debug.abort("unknown case", this); + } + } + /** Returns a string representation of this constant. */ public String toString() { return new ATreePrinter().printConstant(this).toString(); diff --git a/sources/scalac/atree/ATreeFromSTree.java b/sources/scalac/atree/ATreeFromSTree.java index 6ffeeefef2..405875c0cf 100644 --- a/sources/scalac/atree/ATreeFromSTree.java +++ b/sources/scalac/atree/ATreeFromSTree.java @@ -231,8 +231,8 @@ public class ATreeFromSTree { return make.Constant(tree, make.ZERO); return make.Load(tree, location(tree)); - case Literal(Object value): - return make.Constant(tree, constant(value)); + case Literal(AConstant value): + return make.Constant(tree, value); default: throw Debug.abort("illegal case", tree); @@ -311,21 +311,4 @@ public class ATreeFromSTree { } //######################################################################## - // Private Methods - Translating constants - - /** Translates the constant. */ - private AConstant constant(Object value) { - if (value instanceof Boolean ) return make.BOOLEAN((Boolean )value); - if (value instanceof Byte ) return make.BYTE (((Byte )value)); - if (value instanceof Short ) return make.SHORT ((Short )value); - if (value instanceof Character) return make.CHAR ((Character)value); - if (value instanceof Integer ) return make.INT ((Integer )value); - if (value instanceof Long ) return make.LONG ((Long )value); - if (value instanceof Float ) return make.FLOAT ((Float )value); - if (value instanceof Double ) return make.DOUBLE ((Double )value); - if (value instanceof String ) return make.STRING ((String )value); - throw Debug.abort("illegal constant", value +" -- "+ value.getClass()); - } - - //######################################################################## } diff --git a/sources/scalac/atree/ATreeTyper.java b/sources/scalac/atree/ATreeTyper.java index dead4e7c40..70156802d5 100644 --- a/sources/scalac/atree/ATreeTyper.java +++ b/sources/scalac/atree/ATreeTyper.java @@ -25,6 +25,9 @@ public class ATreeTyper { //######################################################################## // Private Fields + /** The global environment */ + public final Global global; + /** The global definitions */ private final Definitions definitions; @@ -32,8 +35,9 @@ public class ATreeTyper { // Public Constructors /** Initializes this instance. */ - public ATreeTyper(Global global) { - this.definitions = global.definitions; + public ATreeTyper(Global global, Definitions definitions) { + this.global = global; + this.definitions = definitions; } //######################################################################## @@ -176,8 +180,15 @@ public class ATreeTyper { /** Returns the type of the given constant. */ public Type type(AConstant constant) { + Type base = basetype(constant); + if (global.currentPhase.id > global.PHASE.ERASURE.id()) return base; + return Type.ConstantType(base, constant); + } + + /** Returns the base type of the given constant. */ + public Type basetype(AConstant constant) { switch (constant) { - case UNIT : return definitions.UNIT_CLASS.type(); + case UNIT : return definitions.UNIT_TYPE(); case BOOLEAN(_): return definitions.BOOLEAN_TYPE(); case BYTE(_) : return definitions.BYTE_TYPE(); case SHORT(_) : return definitions.SHORT_TYPE(); @@ -199,6 +210,7 @@ public class ATreeTyper { /** Returns the type of the given type kind. */ public Type type(ATypeKind kind) { switch (kind) { + case UNIT: return definitions.UNIT_TYPE(); case BOOL: return definitions.BOOLEAN_TYPE(); // !!! case U1 : return ?; case U2 : return definitions.CHAR_TYPE(); @@ -212,12 +224,15 @@ public class ATreeTyper { case R8 : return definitions.DOUBLE_TYPE(); case REF : return definitions.ANYREF_TYPE(); case STR : return definitions.STRING_TYPE(); + case NULL: return definitions.ALLREF_TYPE(); + case ZERO: return definitions.ALL_TYPE(); default : throw Debug.abort("unknown case", kind); } } //######################################################################## - // Public Methods - aliases of type() for scala + // Public Methods - Aliases for scala + public Type[] computeType(ACode[] codes) { return type(codes); } diff --git a/sources/scalac/atree/ATypeKind.java b/sources/scalac/atree/ATypeKind.java index 57b827473d..1be2eb540d 100644 --- a/sources/scalac/atree/ATypeKind.java +++ b/sources/scalac/atree/ATypeKind.java @@ -16,6 +16,9 @@ public class ATypeKind { //######################################################################## // Public Cases + /** The unit value */ + public case UNIT; + /** A boolean value */ public case BOOL; @@ -55,12 +58,19 @@ public class ATypeKind { /** A string reference */ public case STR; + /** The null reference */ + public case NULL; + + /** The zero value */ + public case ZERO; + //######################################################################## // Public Methods /** Returns a string representation of this type kind. */ public String toString() { switch (this) { + case UNIT: return "UNIT"; case BOOL: return "BOOL"; case U1 : return "U1"; case U2 : return "U2"; @@ -74,6 +84,8 @@ public class ATypeKind { case R8 : return "R8"; case REF : return "REF"; case STR : return "STR"; + case NULL: return "NULL"; + case ZERO: return "ZERO"; default : throw Debug.abort("unknown case", this); } } diff --git a/sources/scalac/backend/jvm/GenJVM.java b/sources/scalac/backend/jvm/GenJVM.java index 05e073abc5..58d9e6d55a 100644 --- a/sources/scalac/backend/jvm/GenJVM.java +++ b/sources/scalac/backend/jvm/GenJVM.java @@ -14,6 +14,7 @@ import scalac.*; import scalac.backend.*; import scalac.util.*; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.symtab.*; import scalac.symtab.classfile.ClassfileConstants; import scalac.symtab.classfile.Pickle; @@ -530,37 +531,52 @@ class GenJVM { generatedType = JAVA_LANG_OBJECT_T; break; - case Literal(Object value): - if (value instanceof Integer) { - generatedType = JType.INT; - ctx.code.emitPUSH((Integer)value); - } else if (value instanceof Short) { - generatedType = JType.SHORT; - ctx.code.emitPUSH((Short)value); - } else if (value instanceof Byte) { - generatedType = JType.BYTE; - ctx.code.emitPUSH((Byte)value); - } else if (value instanceof Long) { - generatedType = JType.LONG; - ctx.code.emitPUSH((Long)value); - } else if (value instanceof Float) { - generatedType = JType.FLOAT; - ctx.code.emitPUSH((Float)value); - } else if (value instanceof Double) { - generatedType = JType.DOUBLE; - ctx.code.emitPUSH((Double)value); - } else if (value instanceof Character) { - generatedType = JType.CHAR; - ctx.code.emitPUSH((Character)value); - } else if (value instanceof String) { - generatedType = JAVA_LANG_STRING_T; - ctx.code.emitPUSH((String)value); - } else if (value instanceof Boolean) { - generatedType = JType.BOOLEAN; - ctx.code.emitPUSH((Boolean)value); - } else - throw global.fail("unknown literal " + value); + case Literal(UNIT): + maybeGenLoadUnit(ctx, expectedType); + generatedType = expectedType; + break; + case Literal(BOOLEAN(boolean value)): + ctx.code.emitPUSH(value); + generatedType = JType.BOOLEAN; + break; + case Literal(BYTE(byte value)): + ctx.code.emitPUSH(value); + generatedType = JType.BYTE; + break; + case Literal(SHORT(short value)): + ctx.code.emitPUSH(value); + generatedType = JType.SHORT; + break; + case Literal(CHAR(char value)): + ctx.code.emitPUSH(value); + generatedType = JType.CHAR; + break; + case Literal(INT(int value)): + ctx.code.emitPUSH(value); + generatedType = JType.INT; break; + case Literal(LONG(long value)): + ctx.code.emitPUSH(value); + generatedType = JType.LONG; + break; + case Literal(FLOAT(float value)): + ctx.code.emitPUSH(value); + generatedType = JType.FLOAT; + break; + case Literal(DOUBLE(double value)): + ctx.code.emitPUSH(value); + generatedType = JType.DOUBLE; + break; + case Literal(STRING(String value)): + ctx.code.emitPUSH(value); + generatedType = JAVA_LANG_STRING_T; + break; + case Literal(NULL): + if (expectedType != JType.VOID) ctx.code.emitACONST_NULL(); + generatedType = expectedType; + break; + case Literal(AConstant value): + throw Debug.abort("unknown literal", value); case Empty: case AbsTypeDef(_, _, _, _): @@ -925,16 +941,27 @@ class GenJVM { boolean isIntZero = false; if (maxTypeIdx <= intTypeIdx) { switch (args[i]) { - case Literal(Object val): + case Literal(AConstant constant): int intVal; - if (val instanceof Number) - intVal = ((Number)val).intValue(); - else if (val instanceof Character) - intVal = ((Character)val).charValue(); - else if (val instanceof Boolean) - intVal = ((Boolean)val).booleanValue() ? 1 : 0; - else - throw Debug.abort("unknown literal", val); + switch (constant) { + case BOOLEAN(boolean value): + intVal = value ? 1 : 0; + break; + case BYTE(byte value): + intVal = value; + break; + case SHORT(short value): + intVal = value; + break; + case CHAR(char value): + intVal = value; + break; + case INT(int value): + intVal = value; + break; + default: + throw Debug.abort("unknown literal", constant); + } if (intVal == 0) { isIntZero = true; if (i == 0) prim = prim.swap(); @@ -1056,7 +1083,7 @@ class GenJVM { String className; switch (classNameLit) { - case Literal(Object name): className = (String)name; break; + case Literal(STRING(String name)): className = name; break; default: throw global.fail("invalid argument for oarray " + classNameLit); } diff --git a/sources/scalac/backend/msil/GenMSIL.java b/sources/scalac/backend/msil/GenMSIL.java index 4f86ce8c29..5450241104 100644 --- a/sources/scalac/backend/msil/GenMSIL.java +++ b/sources/scalac/backend/msil/GenMSIL.java @@ -18,6 +18,7 @@ import scalac.util.Name; import scalac.util.Names; import scalac.util.Debug; import scalac.ast.Tree; +import scalac.atree.AConstant; import Tree.*; import scalac.symtab.Symbol; import scalac.symtab.Scope; @@ -554,10 +555,12 @@ public final class GenMSIL { lastStatement = tmpLastStatement; return check(store(var)); - case Typed(Literal(Object value), Tree tpe): + // !!! all Typed nodes are removed by phase ExplicitOuter + case Typed(Literal(AConstant value), Tree tpe): log("Typed.Literal: " + Debug.show(tree)); return items.LiteralItem(type2MSILType(tpe.type), value); + // !!! all Typed nodes are removed by phase ExplicitOuter case Typed(Tree expr, Tree tpe): //log("gen.Typed: processing node: " + Debug.show(tree)); return gen(expr, type2MSILType(tpe.type)); @@ -591,7 +594,7 @@ public final class GenMSIL { //log("gen.Super: generated item: " + retItem); return retItem; - case Literal(Object value): + case Literal(AConstant value): //log("Literal: " + Debug.show(tree)); //log("\ttype = " + Debug.show(tree.type)); MSILType t = type2MSILType(tree.type); @@ -621,7 +624,7 @@ public final class GenMSIL { assert tags.length == bodies.length; for (int i = 0; i < tags.length; i++) { load(loc); - loadLiteral(MSILType.I4, new Integer(tags[i])); + loadI4(tags[i]); code.Emit(OpCodes.Bne_Un, nextCase); load(gen(bodies[i])); if (lastStatement) @@ -725,7 +728,7 @@ public final class GenMSIL { return items.StackItem(toType); } return item; - case LiteralItem(MSILType type, Object value): + case LiteralItem(MSILType type, AConstant value): //log("coercing Literal " + type + " -> " + toType); switch (type) { case REF(_): return item; @@ -1379,8 +1382,8 @@ public final class GenMSIL { case StackItem(): return (StackItem) that; - case LiteralItem(MSILType type, Object value): - return loadLiteral(type, value); + case LiteralItem(_, AConstant value): + return loadLiteral(value); case SelfItem(): emitThis(); @@ -1504,66 +1507,122 @@ public final class GenMSIL { case I2: case I4: case CHAR: - int i = (obj instanceof Character) ? + return loadI4((obj instanceof Character) ? (int)((Character) obj).charValue() : - ((Number)obj).intValue(); -// int i = (type == MSILType.CHAR) ? + ((Number)obj).intValue()); +// return loadI4((type == MSILType.CHAR) ? // (int)((Character) obj).charValue() : -// ((Number)obj).intValue(); - switch (i) { - case -1:code.Emit(OpCodes.Ldc_I4_M1); break; - case 0: code.Emit(OpCodes.Ldc_I4_0); break; - case 1: code.Emit(OpCodes.Ldc_I4_1); break; - case 2: code.Emit(OpCodes.Ldc_I4_2); break; - case 3: code.Emit(OpCodes.Ldc_I4_3); break; - case 4: code.Emit(OpCodes.Ldc_I4_4); break; - case 5: code.Emit(OpCodes.Ldc_I4_5); break; - case 6: code.Emit(OpCodes.Ldc_I4_6); break; - case 7: code.Emit(OpCodes.Ldc_I4_7); break; - case 8: code.Emit(OpCodes.Ldc_I4_8); break; - default: - if (i >= -128 && i <= 127) - code.Emit(OpCodes.Ldc_I4_S, i); - else - code.Emit(OpCodes.Ldc_I4, i); - } - break; +// ((Number)obj).intValue()); case I8: - code.Emit(OpCodes.Ldc_I8, ((Number)obj).longValue()); - break; + return loadI8(((Number)obj).longValue()); case R4: - code.Emit(OpCodes.Ldc_R4, ((Number)obj).floatValue()); - break; + return loadR4(((Number)obj).floatValue()); case R8: - code.Emit(OpCodes.Ldc_R8, ((Number)obj).doubleValue()); - break; + return loadR8(((Number)obj).doubleValue()); case BOOL: - if (((Boolean)obj).booleanValue()) - code.Emit(OpCodes.Ldc_I4_1); - else - code.Emit(OpCodes.Ldc_I4_0); - break; + return loadBool(((Boolean)obj).booleanValue()); case VOID: - code.Emit(OpCodes.Ldsfld, tc.RUNTIME_UNIT_VAL); - break; + return loadUnit(); case REF(Type refType): if (obj == null) { - code.Emit(OpCodes.Ldnull); + return loadNull(); } else if (refType == tc.STRING) { - code.Emit(OpCodes.Ldstr, obj.toString()); + return loadString(obj.toString()); } else { throw new ApplicationError ("loadLiteral(): unexpected literal type: " + refType + "; value = " + obj); } - break; default: throw new ApplicationError ("loadLiteral(): Unknown literal type: " + type); } - return items.StackItem(type); } // genLiteral() + Item.StackItem loadLiteral(AConstant constant) { + switch (constant) { + case UNIT: + return loadUnit(); + case BOOLEAN(boolean value): + return loadBool(value); + case BYTE(byte value): + return loadI4(value); + case SHORT(short value): + return loadI4(value); + case CHAR(char value): + return loadI4(value); + case INT(int value): + return loadI4(value); + case LONG(long value): + return loadI8(value); + case FLOAT(float value): + return loadR4(value); + case DOUBLE(double value): + return loadR8(value); + case STRING(String value): + return loadString(value); + case NULL: + return loadNull(); + default: + throw Debug.abort("illegal case", constant); + } + } + + Item.StackItem loadUnit() { + code.Emit(OpCodes.Ldsfld, tc.RUNTIME_UNIT_VAL); + return items.StackItem(MSILType.VOID); + } + + Item.StackItem loadBool(boolean value) { + code.Emit(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + return items.StackItem(MSILType.BOOL); + } + + Item.StackItem loadI4(int value) { + switch (value) { + case -1:code.Emit(OpCodes.Ldc_I4_M1); break; + case 0: code.Emit(OpCodes.Ldc_I4_0); break; + case 1: code.Emit(OpCodes.Ldc_I4_1); break; + case 2: code.Emit(OpCodes.Ldc_I4_2); break; + case 3: code.Emit(OpCodes.Ldc_I4_3); break; + case 4: code.Emit(OpCodes.Ldc_I4_4); break; + case 5: code.Emit(OpCodes.Ldc_I4_5); break; + case 6: code.Emit(OpCodes.Ldc_I4_6); break; + case 7: code.Emit(OpCodes.Ldc_I4_7); break; + case 8: code.Emit(OpCodes.Ldc_I4_8); break; + default: + if (value >= -128 && value <= 127) + code.Emit(OpCodes.Ldc_I4_S, value); + else + code.Emit(OpCodes.Ldc_I4, value); + } + return items.StackItem(MSILType.I4); + } + + Item.StackItem loadI8(long value) { + code.Emit(OpCodes.Ldc_I8, value); + return items.StackItem(MSILType.I8); + } + + Item.StackItem loadR4(float value) { + code.Emit(OpCodes.Ldc_R4, value); + return items.StackItem(MSILType.R4); + } + + Item.StackItem loadR8(double value) { + code.Emit(OpCodes.Ldc_R8, value); + return items.StackItem(MSILType.R8); + } + + Item.StackItem loadString(String value) { + code.Emit(OpCodes.Ldstr, value); + return items.StackItem(MSILType.STRING_REF); + } + + Item.StackItem loadNull() { + code.Emit(OpCodes.Ldnull); + return items.StackItem(MSILType.NULL_REF); + } /** */ @@ -1969,7 +2028,7 @@ class Item { public case VoidItem(); public case StackItem(); public case SelfItem(); - public case LiteralItem(MSILType typ, Object value); + public case LiteralItem(MSILType typ, AConstant value); public case ArgItem(int slot); public case LocalItem(LocalBuilder local); public case StaticItem(FieldInfo field); @@ -1981,7 +2040,7 @@ class Item { case VoidItem(): return "VoidItem: " + type; case StackItem(): return "StackItem: " + type ; case SelfItem(): return "this: " + type; - case LiteralItem(_, Object value): return "LiteralItem(" + value + "): " + type; + case LiteralItem(_, AConstant value): return "LiteralItem(" + value + "): " + type; case ArgItem( int slot): return "ArgItem(" + slot + "): " + type; case LocalItem( LocalBuilder local): return "LocalItem(" + local + "): " + type; case StaticItem( FieldInfo field): return "StaticItem(" + field + "): " + type; @@ -2024,7 +2083,7 @@ class ItemFactory { item.type = MSILType.REF(t); return item; } - public Item.LiteralItem LiteralItem(MSILType type, Object value) { + public Item.LiteralItem LiteralItem(MSILType type, AConstant value) { Item.LiteralItem item = Item.LiteralItem(type, value); item.type = type; return item; diff --git a/sources/scalac/checkers/TreeChecker.java b/sources/scalac/checkers/TreeChecker.java index e523df6238..9cb683595b 100644 --- a/sources/scalac/checkers/TreeChecker.java +++ b/sources/scalac/checkers/TreeChecker.java @@ -308,18 +308,7 @@ public class TreeChecker { if (symbol == definitions.ZERO) return true; return location(tree); - case Literal(Object value): - assert value != null: show(tree); - if (value instanceof Boolean ) return true; - if (value instanceof Byte ) return true; - if (value instanceof Short ) return true; - if (value instanceof Character) return true; - if (value instanceof Integer ) return true; - if (value instanceof Long ) return true; - if (value instanceof Float ) return true; - if (value instanceof Double ) return true; - if (value instanceof String ) return true; - assert false: show(tree) + format("value.class", value.getClass()); + case Literal(_): return true; default: diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java index aaac2ee960..1cfc8995f8 100644 --- a/sources/scalac/symtab/Definitions.java +++ b/sources/scalac/symtab/Definitions.java @@ -11,6 +11,7 @@ package scalac.symtab; import ch.epfl.lamp.util.Position; import scalac.Global; +import scalac.atree.ATreeTyper; import scalac.symtab.classfile.PackageParser; import scalac.util.Debug; import scalac.util.Name; @@ -19,6 +20,12 @@ import scalac.util.Names; public class Definitions { //######################################################################## + // Public Fields - Root module + + /** The attributed tree typer */ + public final ATreeTyper atyper; + + //######################################################################## // Public Fields & Methods - Root module /** The root module */ @@ -461,6 +468,8 @@ public class Definitions { global.definitions = this; // force initialization of class Type Type.localThisType.symbol(); + // create attributed tree typer + atyper = new ATreeTyper(global, this); // the root module ROOT = TermSymbol.newJavaPackageModule( @@ -520,7 +529,6 @@ public class Definitions { initAlias(ANYREF_CLASS, JAVA_OBJECT_TYPE()); initClass(ALLREF_CLASS, new Type[]{ANYREF_TYPE()}); initClass(ALL_CLASS, new Type[]{ANY_TYPE()}); - initAlias(STRING_CLASS, JAVA_STRING_TYPE()); // create type symbols UNIT_TYPE = newTypeSymbol(Names.Unit , UNIT_CLASS.type ()); @@ -535,6 +543,9 @@ public class Definitions { ARRAY_TYPE = newTypeSymbol(Names.Array , Type.appliedType(ARRAY_CLASS.type(), new Type[]{ANYREF_TYPE()})); + // initialize generated classes and aliases + initAlias(STRING_CLASS, JAVA_STRING_TYPE()); + // add members to scala.Any ANY_EQ = newTerm(ANY_CLASS, Names.eq , 0); ANY_EQEQ = newTerm(ANY_CLASS, Names.EQEQ , Modifiers.FINAL); diff --git a/sources/scalac/symtab/EntryTags.java b/sources/scalac/symtab/EntryTags.java index ade0cb60bd..04cdcdc704 100644 --- a/sources/scalac/symtab/EntryTags.java +++ b/sources/scalac/symtab/EntryTags.java @@ -26,13 +26,25 @@ public interface EntryTags { * | 11 NOtpe len_Nat * | 12 THIStpe len_Nat sym_Ref * | 13 SINGLEtpe len_Nat type_Ref sym_Ref - * | 14 CONSTANTtpe len_Nat type_Ref value_Ref + * | 14 CONSTANTtpe len_Nat type_Ref constant_Ref * | 15 TYPEREFtpe len_Nat type_Ref sym_Ref {targ_Ref} * | 16 COMPOUNDtpe len_Nat classsym_Ref {tpe_Ref} * | 17 METHODtpe len_Nat tpe_Ref {tpe_Ref} * | 18 POLYTtpe len_Nat tpe_Ref {sym_Ref} * | 19 OVERLOADEDtpe len_Nat {sym_Ref} {tpe_Ref} * | 22 FLAGGEDtpe len_Nat flags_Nat tpe_Ref + * | 24 LITERALunit len_Nat + * | 25 LITERALboolean len_Nat value_Byte + * | 26 LITERALbyte len_Nat value_Long + * | 27 LITERALshort len_Nat value_Long + * | 28 LITERALchar len_Nat value_Long + * | 29 LITERALint len_Nat value_Long + * | 30 LITERALlong len_Nat value_Long + * | 31 LITERALfloat len_Nat value_Long + * | 32 LITERALdouble len_Nat value_Long + * | 33 LITERALstring len_Nat name_Ref + * | 34 LITERALnull len_Nat + * | 35 LITERALzero len_Nat * SymbolInfo = name_Ref owner_Ref flags_Nat info_Ref * NameInfo = <character sequence of length len_Nat in Utf8 format> * NumInfo = <len_Nat-byte signed number in big endian format> @@ -43,7 +55,6 @@ public interface EntryTags { int TERMname = 1, TYPEname = 2, - NUMBER = 3, NONEsym = 4, TYPEsym = 5, ALIASsym = 6, @@ -63,7 +74,19 @@ public interface EntryTags { UNBOXEDtpe = 20, UNBOXEDARRAYtpe = 21, FLAGGEDtpe = 22, - ERRORtpe = 23; + ERRORtpe = 23, + LITERALunit = 24, + LITERALboolean = 25, + LITERALbyte = 26, + LITERALshort = 27, + LITERALchar = 28, + LITERALint = 29, + LITERALlong = 30, + LITERALfloat = 31, + LITERALdouble = 32, + LITERALstring = 33, + LITERALnull = 34, + LITERALzero = 35; int firstSymTag = NONEsym, lastSymTag = VALsym; int firstTypeTag = NOtpe, lastTypeTag = FLAGGEDtpe; diff --git a/sources/scalac/symtab/SymbolTablePrinter.java b/sources/scalac/symtab/SymbolTablePrinter.java index c23a6107eb..8cf3ce3608 100644 --- a/sources/scalac/symtab/SymbolTablePrinter.java +++ b/sources/scalac/symtab/SymbolTablePrinter.java @@ -13,6 +13,7 @@ import java.io.StringWriter; import ch.epfl.lamp.util.CodePrinter; import scalac.Global; +import scalac.atree.AConstant; import scalac.symtab.Type.Constraint; import scalac.symtab.Scope.SymbolIterator; import scalac.util.Name; @@ -526,7 +527,7 @@ public class SymbolTablePrinter { return this; case SingleType(Type pre, Symbol sym): return printPrefix(pre).printSymbolName(sym); - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): return printType(base) .print("(").print(value.toString()).print(")"); case CompoundType(Type[] parts, Scope members): diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index 7abd0133ff..d21cbba3ba 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -13,6 +13,7 @@ import java.util.HashMap; import ch.epfl.lamp.util.Position; import scalac.ApplicationError; +import scalac.atree.AConstant; import scalac.util.*; import scalac.Global; @@ -38,14 +39,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { /** Type for a numeric or string constant. */ - public case ConstantType(Type base, Object value) { - if (base.symbol() == Global.instance.definitions.BYTE_CLASS) - assert value instanceof Byte; - if (base.symbol() == Global.instance.definitions.CHAR_CLASS) - assert value instanceof Character; - if (base.symbol() == Global.instance.definitions.SHORT_CLASS) - assert value instanceof Short; - } + public case ConstantType(Type base, AConstant value); /** pre.sym[args] * sym represents a type @@ -168,26 +162,8 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } } - public static ConstantType constantType(Object value) { - return new ConstantType(value2type(value), value); - } - - private static Type value2type(Object value) { - if (value instanceof Character) - return Global.instance.definitions.CHAR_CLASS.typeConstructor(); - else if (value instanceof Integer) - return Global.instance.definitions.INT_CLASS.typeConstructor(); - else if (value instanceof Long) - return Global.instance.definitions.LONG_CLASS.typeConstructor(); - else if (value instanceof Float) - return Global.instance.definitions.FLOAT_CLASS.typeConstructor(); - else if (value instanceof Double) - return Global.instance.definitions.DOUBLE_CLASS.typeConstructor(); - else if (value instanceof String) - return Global.instance.definitions.JAVA_STRING_CLASS.typeConstructor(); - else if (value instanceof Boolean) - return Global.instance.definitions.BOOLEAN_CLASS.typeConstructor(); - else throw new ApplicationError(); + public static Type constantType(AConstant value) { + return Global.instance.definitions.atyper.type(value); } public static Type singleTypeMethod(Type pre, Symbol sym) { @@ -690,62 +666,6 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { return this; } - /** Numeric values - */ - public int intValue() { - switch (this) { - case ConstantType(_, Object value): - return toNumber(value).intValue(); - default: - throw new ApplicationError(); - } - } - public long longValue() { - switch (this) { - case ConstantType(_, Object value): - return toNumber(value).longValue(); - default: - throw new ApplicationError(); - } - } - public float floatValue() { - switch (this) { - case ConstantType(_, Object value): - return toNumber(value).floatValue(); - default: - throw new ApplicationError(); - } - } - public double doubleValue() { - switch (this) { - case ConstantType(_, Object value): - return toNumber(value).doubleValue(); - default: - throw new ApplicationError(); - } - } - public boolean booleanValue() { - switch (this) { - case ConstantType(_, Object value): - return ((Boolean)value).booleanValue(); - default: - throw new ApplicationError(); - } - } - public String stringValue() { - switch (this) { - case ConstantType(_, Object value): - return value.toString(); - default: - throw new ApplicationError(); - } - } - private static Number toNumber(Object value) { - return (value instanceof Character) - ? new Integer(((Character)value).charValue()) - : (Number)value; - } - // Tests -------------------------------------------------------------------- /** Is this type a this type or singleton type? @@ -1098,7 +1018,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { Type pre1 = apply(pre); if (pre1 == pre) return tp; else return singleType(pre1, sym); - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): Type base1 = apply(base); if (base1 == base) return tp; else return new ConstantType(base1, value); @@ -1961,15 +1881,20 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { case ThisType(_): case SingleType(_, _): - case ConstantType(_, _): switch (this) { case ThisType(_): case SingleType(_, _): - case ConstantType(_, _): return this.isSameAs(that); } break; + case ConstantType(_, _): + switch (this) { + case ConstantType(Type base, _): + return this.isSameAs(that) || base.isSubType(that); + } + break; + case TypeRef(Type pre1, Symbol sym1, Type[] args1): switch (this) { case TypeRef(Type pre, Symbol sym, Type[] args): @@ -2062,7 +1987,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { case SingleType(_, _): if (this.singleDeref().isSubType(that)) return true; break; - case ConstantType(_, Object value): + case ConstantType(_, _): if (this.singleDeref().isSubType(that)) return true; break; case TypeVar(Type origin, Constraint constr): @@ -2251,9 +2176,9 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } break; - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): switch (that) { - case ConstantType(Type base1, Object value1): + case ConstantType(Type base1, AConstant value1): return base.isSameAs(base1) && value.equals(value1); } break; @@ -3278,7 +3203,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { return SINGLEtpe ^ (pre.hashCode() * 41) ^ (sym.hashCode() * (41*41)); - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): return CONSTANTtpe ^ (base.hashCode() * 41) ^ (value.hashCode() * (41*41)); @@ -3350,9 +3275,9 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { return pre.equals(pre1) && sym == sym1; default: return false; } - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): switch (that) { - case ConstantType(Type base1, Object value1): + case ConstantType(Type base1, AConstant value1): return base.equals(base1) && value.equals(value1); default: return false; } diff --git a/sources/scalac/symtab/classfile/AttributeParser.java b/sources/scalac/symtab/classfile/AttributeParser.java index dc982c23af..83bc52e94d 100644 --- a/sources/scalac/symtab/classfile/AttributeParser.java +++ b/sources/scalac/symtab/classfile/AttributeParser.java @@ -10,6 +10,7 @@ package scalac.symtab.classfile; import ch.epfl.lamp.util.Position; import scalac.*; +import scalac.atree.AConstant; import scalac.symtab.*; import scalac.util.*; import java.util.*; @@ -169,13 +170,28 @@ public class AttributeParser implements ClassfileConstants { /** return the constant type for the given constant. */ Type constantType(Type base, Object value) { + return Type.constantType(constantValue(base, value)); + } + AConstant constantValue(Type base, Object value) { + if (base.symbol() == parser.global.definitions.BOOLEAN_CLASS) + return AConstant.BOOLEAN(((Number)value).intValue() != 0); if (base.symbol() == parser.global.definitions.BYTE_CLASS) - value = new Byte(((Number)value).byteValue()); - if (base.symbol() == parser.global.definitions.CHAR_CLASS) - value = new Character((char)((Number)value).intValue()); + return AConstant.BYTE(((Number)value).byteValue()); if (base.symbol() == parser.global.definitions.SHORT_CLASS) - value = new Short(((Number)value).shortValue()); - return Type.ConstantType(base, value); + return AConstant.SHORT(((Number)value).shortValue()); + if (base.symbol() == parser.global.definitions.CHAR_CLASS) + return AConstant.CHAR((char)((Number)value).intValue()); + if (base.symbol() == parser.global.definitions.INT_CLASS) + return AConstant.INT(((Number)value).intValue()); + if (base.symbol() == parser.global.definitions.LONG_CLASS) + return AConstant.LONG(((Number)value).longValue()); + if (base.symbol() == parser.global.definitions.FLOAT_CLASS) + return AConstant.FLOAT(((Number)value).floatValue()); + if (base.symbol() == parser.global.definitions.DOUBLE_CLASS) + return AConstant.DOUBLE(((Number)value).doubleValue()); + if (base.symbol() == parser.global.definitions.JAVA_STRING_CLASS) + return AConstant.STRING((String)value); + throw Debug.abort("illegal value", value + " - " + base); } /** return the type of a given constant. diff --git a/sources/scalac/symtab/classfile/Pickle.java b/sources/scalac/symtab/classfile/Pickle.java index 7309f4d8d7..c43b56fef0 100644 --- a/sources/scalac/symtab/classfile/Pickle.java +++ b/sources/scalac/symtab/classfile/Pickle.java @@ -13,6 +13,7 @@ import java.util.HashMap; import java.io.*; import scalac.Global; import scalac.ApplicationError; +import scalac.atree.AConstant; import scalac.util.*; import scalac.symtab.*; import Symbol.*; @@ -169,9 +170,9 @@ public class Pickle implements Kinds, Modifiers, EntryTags { putType(pre); putSymbol(sym); break; - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): putType(base); - putEntry(value); + putConstant(value); break; case TypeRef(Type pre, Symbol sym, Type[] args): putType(pre); @@ -212,6 +213,16 @@ public class Pickle implements Kinds, Modifiers, EntryTags { putType(tps[i]); } + private void putConstant(AConstant constant) { + if (putEntry(constant)) { + switch (constant) { + case STRING(String value): + putEntry(Name.fromString(value)); + return; + } + } + } + /* ************************************************** * Phase 2: Write byte array ************************************************* */ @@ -294,15 +305,6 @@ public class Pickle implements Kinds, Modifiers, EntryTags { bp = bp + name.length(); } - /** Write a long number in big endian format, base 128. - * All but the last digits have bit 0x80 set. - */ - private void writeNumber(long x) { - writeByte(NUMBER); - writeByte(0); // space for length - writeLong(x); - } - /** Write a symbol entry. */ private void writeSymbol(Symbol sym) { @@ -390,7 +392,7 @@ public class Pickle implements Kinds, Modifiers, EntryTags { writeRef(sym); break; - case ConstantType(Type base, Object value): + case ConstantType(Type base, AConstant value): writeByte(CONSTANTtpe); writeByte(0); // space for length writeRef(base); @@ -452,6 +454,72 @@ public class Pickle implements Kinds, Modifiers, EntryTags { writeRef(ft.type); } + /** Write a constant entry. + */ + private void writeConstant(AConstant constant) { + switch (constant) { + case UNIT: + writeByte(LITERALunit); + writeByte(0); // space for length + return; + case BOOLEAN(boolean value): + writeByte(LITERALboolean); + writeByte(0); // space for length + writeByte(value ? 1 : 0); + return; + case BYTE(byte value): + writeByte(LITERALbyte); + writeByte(0); // space for length + writeLong(value); + return; + case SHORT(short value): + writeByte(LITERALshort); + writeByte(0); // space for length + writeLong(value); + return; + case CHAR(char value): + writeByte(LITERALchar); + writeByte(0); // space for length + writeLong(value); + return; + case INT(int value): + writeByte(LITERALint); + writeByte(0); // space for length + writeLong(value); + return; + case LONG(long value): + writeByte(LITERALlong); + writeByte(0); // space for length + writeLong(value); + return; + case FLOAT(float value): + writeByte(LITERALfloat); + writeByte(0); // space for length + writeLong(Float.floatToIntBits(value)); + return; + case DOUBLE(double value): + writeByte(LITERALdouble); + writeByte(0); // space for length + writeLong(Double.doubleToLongBits(value)); + return; + case STRING(String value): + writeByte(LITERALstring); + writeByte(0); // space for length + writeRef(Name.fromString(value)); + return; + case NULL: + writeByte(LITERALnull); + writeByte(0); // space for length + return; + case ZERO: + writeByte(LITERALzero); + writeByte(0); // space for length + return; + default: + throw Debug.abort("unknown case", constant); + } + } + private void writeEntry(Object e) { int startpos = bp; if (e instanceof Symbol) @@ -462,24 +530,8 @@ public class Pickle implements Kinds, Modifiers, EntryTags { writeName((Name) e); else if (e instanceof FlagsAndType) writeFlagsAndType((FlagsAndType) e); - else if (e instanceof String) - writeName(Name.fromString((String)e)); - else if (e instanceof Double) - writeNumber(Double.doubleToLongBits(((Double)e).doubleValue())); - else if (e instanceof Float) - writeNumber(Float.floatToIntBits(((Float)e).floatValue())); - else if (e instanceof Long) - writeNumber(((Long)e).longValue()); - else if (e instanceof Integer) - writeNumber(((Integer)e).intValue()); - else if (e instanceof Short) - writeNumber(((Short)e).intValue()); - else if (e instanceof Byte) - writeNumber(((Byte)e).intValue()); - else if (e instanceof Character) - writeNumber(((Character)e).charValue()); - else if (e instanceof Boolean) - writeNumber(((Boolean)e).booleanValue() ? 1 : 0); + else if (e instanceof AConstant) + writeConstant((AConstant)e); else throw new ApplicationError(e); patchNat(startpos + 1, bp - (startpos + 2)); diff --git a/sources/scalac/symtab/classfile/UnPickle.java b/sources/scalac/symtab/classfile/UnPickle.java index 9e2f687d5f..5939455f30 100644 --- a/sources/scalac/symtab/classfile/UnPickle.java +++ b/sources/scalac/symtab/classfile/UnPickle.java @@ -11,6 +11,7 @@ package scalac.symtab.classfile; import java.util.HashMap; import java.io.PrintStream; import scalac.*; +import scalac.atree.AConstant; import scalac.util.*; import ch.epfl.lamp.util.Position; import scalac.symtab.*; @@ -338,7 +339,7 @@ public class UnPickle implements Kinds, Modifiers, EntryTags, TypeTags { break; case CONSTANTtpe: Type base = readTypeRef(); - Object value = readValueRef(base); + AConstant value = readConstantRef(); tpe = new Type.ConstantType(base, value); break; case TYPEREFtpe: @@ -445,43 +446,46 @@ public class UnPickle implements Kinds, Modifiers, EntryTags, TypeTags { return flags; } - long getNumber(int n) { - int savedBp = bp; - bp = index[n]; + AConstant readConstant() { int tag = bytes[bp++]; - long x = readLong(readNat()); - bp = savedBp; - return x; + int len = readNat(); + switch (tag) { + case LITERALunit: + return AConstant.UNIT; + case LITERALboolean: + return AConstant.BOOLEAN(readByte() == 0 ? false : true); + case LITERALbyte: + return AConstant.BYTE((byte)readLong(len)); + case LITERALshort: + return AConstant.SHORT((short)readLong(len)); + case LITERALchar: + return AConstant.CHAR((char)readLong(len)); + case LITERALint: + return AConstant.INT((int)readLong(len)); + case LITERALlong: + return AConstant.LONG(readLong(len)); + case LITERALfloat: + return AConstant.FLOAT(Float.intBitsToFloat((int)readLong(len))); + case LITERALdouble: + return AConstant.DOUBLE(Double.longBitsToDouble(readLong(len))); + case LITERALstring: + return AConstant.STRING(readNameRef().toString()); + case LITERALnull: + return AConstant.NULL; + case LITERALzero: + return AConstant.ZERO; + default: + throw Debug.abort("illegal tag: " + tag); + } } - long readNumberRef() { - return getNumber(readNat()); - } - - Object readValueRef(Type base) { - switch (base.unbox()) { - case UnboxedType(BYTE): - return new Byte((byte)readNumberRef()); - case UnboxedType(SHORT): - return new Short((short)readNumberRef()); - case UnboxedType(INT): - return new Integer((int)readNumberRef()); - case UnboxedType(CHAR): - return new Character((char)readNumberRef()); - case UnboxedType(LONG): - return new Long(readNumberRef()); - case UnboxedType(FLOAT): - return new Float(Float.intBitsToFloat((int)readNumberRef())); - case UnboxedType(DOUBLE): - return new Float(Double.longBitsToDouble(readNumberRef())); - case UnboxedType(BOOLEAN): - return new Boolean(readNumberRef() == 0 ? false : true); - default: - if (base.symbol() == Global.instance.definitions.JAVA_STRING_CLASS) - return readNameRef().toString(); - else - throw new ApplicationError("bad constant base type: " + base); - } + AConstant readConstantRef() { + int n = readNat(); + int savedBp = bp; + bp = index[n]; + AConstant constant = readConstant(); + bp = savedBp; + return constant; } public static class BadSignature extends java.lang.Error { @@ -519,6 +523,18 @@ public class UnPickle implements Kinds, Modifiers, EntryTags, TypeTags { case UNBOXEDARRAYtpe: return "UNBOXEDARRAYtpe"; case FLAGGEDtpe: return "FLAGGEDtpe"; case ERRORtpe: return "ERRORtpe"; + case LITERALunit: return "LITERALunit"; + case LITERALboolean: return "LITERALboolean"; + case LITERALbyte: return "LITERALbyte"; + case LITERALshort: return "LITERALshort"; + case LITERALchar: return "LITERALchar"; + case LITERALint: return "LITERALint"; + case LITERALlong: return "LITERALlong"; + case LITERALfloat: return "LITERALfloat"; + case LITERALdouble: return "LITERALdouble"; + case LITERALstring: return "LITERALstring"; + case LITERALnull: return "LITERALnull"; + case LITERALzero: return "LITERALzero"; default: return "***BAD TAG***(" + tag + ")"; } } diff --git a/sources/scalac/transformer/Erasure.java b/sources/scalac/transformer/Erasure.java index acb14659cb..7d7a4c2659 100644 --- a/sources/scalac/transformer/Erasure.java +++ b/sources/scalac/transformer/Erasure.java @@ -26,6 +26,7 @@ import scalac.ast.Tree.AliasTypeDef; import scalac.ast.Tree.ValDef; import scalac.ast.TreeList; import scalac.ast.GenTransformer; +import scalac.atree.AConstant; import scalac.symtab.Definitions; import scalac.symtab.Kinds; import scalac.symtab.Type; @@ -221,6 +222,9 @@ public class Erasure extends GenTransformer implements Modifiers { if (symbol == definitions.ZERO) return gen.mkNullLit(tree.pos); return gen.Ident(tree.pos, symbol); + case Literal(AConstant.ZERO): + return gen.mkNullLit(tree.pos); + case Block(_): case If(_, _, _): case Switch(_, _, _, _): @@ -276,9 +280,6 @@ public class Erasure extends GenTransformer implements Modifiers { Tree value = transform(gen.mkDefaultValue(tree.pos, pt), pt); return gen.mkBlock(new Tree[] {transform(tree), value}); - case Typed(Tree expr, _): // !!! - return transform(expr, pt); - case LabelDef(_, _, _): case Assign(_, _): case New(_): diff --git a/sources/scalac/transformer/matching/AlgebraicMatcher.java b/sources/scalac/transformer/matching/AlgebraicMatcher.java index 7c564882b3..681ced6c8c 100644 --- a/sources/scalac/transformer/matching/AlgebraicMatcher.java +++ b/sources/scalac/transformer/matching/AlgebraicMatcher.java @@ -10,6 +10,7 @@ package scalac.transformer.matching; import scalac.*; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.symtab.*; import PatternNode.*; @@ -86,9 +87,9 @@ public class AlgebraicMatcher extends PatternMatcher { return q.type.isSubType(p.type); } return false; - case ConstantPat( Object pval ): + case ConstantPat( AConstant pval ): switch (q) { - case ConstantPat( Object qval ): + case ConstantPat( AConstant qval ): return pval.equals(qval); } return false; diff --git a/sources/scalac/transformer/matching/BerrySethi.java b/sources/scalac/transformer/matching/BerrySethi.java index dd50fac722..2a1aecf29e 100644 --- a/sources/scalac/transformer/matching/BerrySethi.java +++ b/sources/scalac/transformer/matching/BerrySethi.java @@ -379,7 +379,7 @@ class BerrySethi { return ; - case Literal( Object val ): + case Literal( _ ): Label label = new Label.SimpleLabel( (Literal) pat ); seenLabel( pat, label ) ; @@ -624,7 +624,7 @@ class BerrySethi { it.hasNext(); ) { Tree t = (Tree) it.next(); switch(t) { - case Literal( Object value ): + case Literal( _ ): System.out.print( "(" + t.toString() + " -> "); String s2 = ((Integer) posMap.get(t)).toString(); System.out.print( s2 +") "); diff --git a/sources/scalac/transformer/matching/CodeFactory.java b/sources/scalac/transformer/matching/CodeFactory.java index fb80e66ae7..36c4a29683 100644 --- a/sources/scalac/transformer/matching/CodeFactory.java +++ b/sources/scalac/transformer/matching/CodeFactory.java @@ -150,32 +150,32 @@ class CodeFactory extends PatternTool { // unused public Tree Negate(Tree tree) { switch (tree) { - case Literal(Object value): - return gen.mkBooleanLit(tree.pos, !((Boolean)value).booleanValue()); + case Literal(BOOLEAN(boolean value)): + return gen.mkBooleanLit(tree.pos, !value); } return gen.mkApply__(gen.Select(tree, defs.BOOLEAN_NOT())); } protected Tree And(Tree left, Tree right) { switch (left) { - case Literal(Object value): - return ((Boolean)value).booleanValue() ? right : left; + case Literal(BOOLEAN(boolean value)): + return value ? right : left; } switch (right) { - case Literal(Object value): - if (((Boolean)value).booleanValue()) return left; + case Literal(BOOLEAN(boolean value)): + if (value) return left; } return gen.mkApply_V(gen.Select(left, defs.BOOLEAN_AND()), new Tree[]{right}); } protected Tree Or(Tree left, Tree right) { switch (left) { - case Literal(Object value): - return ((Boolean)value).booleanValue() ? left : right; + case Literal(BOOLEAN(boolean value)): + return value ? left : right; } switch (right) { - case Literal(Object value): - if (!((Boolean)value).booleanValue()) return left; + case Literal(BOOLEAN(boolean value)): + if (!value) return left; } return gen.mkApply_V(gen.Select(left, defs.BOOLEAN_OR()), new Tree[]{right}); } diff --git a/sources/scalac/transformer/matching/LeftTracerInScala.java b/sources/scalac/transformer/matching/LeftTracerInScala.java index 6bdd4c95dd..4c02ce28dc 100644 --- a/sources/scalac/transformer/matching/LeftTracerInScala.java +++ b/sources/scalac/transformer/matching/LeftTracerInScala.java @@ -134,7 +134,7 @@ public class LeftTracerInScala extends TracerInScala { gen.Ident( cf.pos, accumSym )); //return callFun( new Tree[] { newAcc , _iter(), gen.mkIntLit( cf.pos, target )} ); - return callFun( new Tree[] { gen.mkIntLit( cf.pos, target ), newAcc } ); + return callFun( new Tree[] { gen.mkIntLit( cf.pos, target.intValue() ), newAcc } ); } diff --git a/sources/scalac/transformer/matching/PatternMatcher.java b/sources/scalac/transformer/matching/PatternMatcher.java index 2db3b81164..b2c45278ef 100644 --- a/sources/scalac/transformer/matching/PatternMatcher.java +++ b/sources/scalac/transformer/matching/PatternMatcher.java @@ -11,6 +11,7 @@ package scalac.transformer.matching; import ch.epfl.lamp.util.Position; import scalac.*; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.util.*; import scalac.symtab.*; import PatternNode.*; @@ -134,7 +135,7 @@ public class PatternMatcher extends PatternTool { if (patNode.or != null) print(patNode.or, indent); break; - case ConstantPat(Object value): + case ConstantPat(AConstant value): String s = "-- CONST(" + value + ") -> "; String ind = indent; indent = (patNode.or != null) ? @@ -376,7 +377,7 @@ public class PatternMatcher extends PatternTool { return mk.ConstrPat(tree.pos, tree.type); else return mk.VariablePat(tree.pos, tree); - case Literal(Object value): + case Literal(AConstant value): return mk.ConstantPat(tree.pos, tree.type, value); case Sequence(Tree[] ts): if ( !delegateSequenceMatching ) { @@ -691,10 +692,10 @@ public class PatternMatcher extends PatternTool { // for one case we use a normal if-then-else instruction else if (ncases == 1) { switch (root.and.or) { - case ConstantPat(Object value): + case ConstantPat(AConstant value): return gen.If( cf.Equals(selector, - gen.mkLit(root.and.or.pos, value)), + gen.Literal(root.and.or.pos, value)), bodyToTree(root.and.or.and), defaultBody(root.and, matchError)); default: @@ -717,9 +718,9 @@ public class PatternMatcher extends PatternTool { defaultBody = bodyToTree(node.and); node = node.or; break; - case ConstantPat(Object value): + case ConstantPat(INT(int value)): mappings = insert( - ((Integer)value).intValue(), + value, bodyToTree(node.and), mappings); node = node.or; @@ -943,10 +944,10 @@ public class PatternMatcher extends PatternTool { gen.mkAsInstanceOf(selector.duplicate(), node.type)), toTree(node.and)}), toTree(node.or, selector.duplicate())); - case ConstantPat(Object value): + case ConstantPat(AConstant value): return gen.If( cf.Equals(selector.duplicate(), - gen.mkLit(selector.pos, value)), + gen.Literal(selector.pos, value)), toTree(node.and), toTree(node.or, selector.duplicate())); case VariablePat(Tree tree): diff --git a/sources/scalac/transformer/matching/PatternNode.java b/sources/scalac/transformer/matching/PatternNode.java index 89cc6c5d5f..b1d871b9b5 100644 --- a/sources/scalac/transformer/matching/PatternNode.java +++ b/sources/scalac/transformer/matching/PatternNode.java @@ -11,6 +11,7 @@ package scalac.transformer.matching; import ch.epfl.lamp.util.Position; import scalac.*; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.symtab.*; import scalac.typechecker.*; @@ -27,7 +28,7 @@ public class PatternNode { public case Body(Tree.ValDef[][] bound, Tree[] guard, Tree[] body); public case DefaultPat(); public case ConstrPat(Symbol casted); - public case ConstantPat(Object value); + public case ConstantPat(AConstant value); public case VariablePat(Tree tree); public case AltPat(Header subheader); public case SequencePat(Symbol casted, int len); // only used in PatternMatcher @@ -54,7 +55,7 @@ public class PatternNode { case SeqContainerPat(Symbol casted, Tree seqpat): res = SeqContainerPat(casted, seqpat); break; - case ConstantPat(Object value): + case ConstantPat(AConstant value): res = ConstantPat(value); break; case VariablePat(Tree tree): @@ -149,9 +150,9 @@ public class PatternNode { return (plen == qlen) && q.type.isSubType(this.type); } return false; - case ConstantPat(Object pval): + case ConstantPat(AConstant pval): switch (q) { - case ConstantPat(Object qval): + case ConstantPat(AConstant qval): return pval.equals(qval); } return false; @@ -182,7 +183,7 @@ public class PatternNode { return "SequencePat(" + casted + ", " + len + "...)"; case SeqContainerPat(Symbol casted, Tree seqpat): return "SeqContainerPat(" + casted + ", " + seqpat + ")"; - case ConstantPat(Object value): + case ConstantPat(AConstant value): return "ConstantPat(" + value + ")"; case VariablePat(Tree tree): return "VariablePat"; diff --git a/sources/scalac/transformer/matching/PatternNodeCreator.java b/sources/scalac/transformer/matching/PatternNodeCreator.java index d0a2cddef1..dedae105d0 100644 --- a/sources/scalac/transformer/matching/PatternNodeCreator.java +++ b/sources/scalac/transformer/matching/PatternNodeCreator.java @@ -4,6 +4,7 @@ import ch.epfl.lamp.util.Position; import scalac.*; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.util.*; import scalac.symtab.*; import PatternNode.*; @@ -56,7 +57,7 @@ public class PatternNodeCreator extends PatternTool { return node; } - public static ConstantPat ConstantPat(int pos, Type type, Object value) { + public static ConstantPat ConstantPat(int pos, Type type, AConstant value) { ConstantPat node = new ConstantPat( value ); node.pos = pos; node.type = type; diff --git a/sources/scalac/transformer/matching/RightTracerInScala.java b/sources/scalac/transformer/matching/RightTracerInScala.java index c0265370c1..028b7e2bd2 100644 --- a/sources/scalac/transformer/matching/RightTracerInScala.java +++ b/sources/scalac/transformer/matching/RightTracerInScala.java @@ -213,7 +213,7 @@ public class RightTracerInScala extends TracerInScala { tmapTag.put( targetL, I ); tmapBody.put( I, callFun( new Tree[] { cf.SeqTrace_tail( _iter() ), - gen.mkIntLit( cf.pos, targetR ) })); + gen.mkIntLit( cf.pos, targetR.intValue() ) })); } i = 0; int[] tags = new int[ n ]; @@ -234,7 +234,7 @@ public class RightTracerInScala extends TracerInScala { Tree currentMatches( Label label ) { switch( label ) { case Pair( Integer target, Label theLab ): - return cf.Equals( gen.mkIntLit( cf.pos, target ), + return cf.Equals( gen.mkIntLit( cf.pos, target.intValue() ), current() ); } throw new ApplicationError("expected Pair label"); @@ -431,7 +431,7 @@ System.out.println("RightTracerInScala - the seqVars"+seqVars); stms[ j++ ] = algMatchTree ; stms[ j ] = callFun( new Tree[] { cf.SeqTrace_tail( _iter() ), - gen.mkIntLit( cf.pos, ntarget ) } ); + gen.mkIntLit( cf.pos, ntarget.intValue() ) } ); return gen.mkBlock( pos, stms ); } diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index 9c7b5fbaf0..7099163995 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -20,6 +20,7 @@ import ch.epfl.lamp.util.Pair; import scalac.*; import scalac.util.*; import scalac.ast.*; +import scalac.atree.AConstant; import scalac.ast.printer.*; import scalac.symtab.*; import scalac.symtab.classfile.*; @@ -41,7 +42,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { this.definitions = global.definitions; this.descr = descr; this.infer = new Infer(this); - this.constfold = new ConstantFolder(this); + this.constfold = new ConstantFolder(global); this.desugarize = new DeSugarize(this, global); } @@ -1209,13 +1210,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { */ Tree mkStable(Tree tree, Type pre, int mode, Type pt) { switch (tree.type) { - case ConstantType(_, Object value): - return make.Literal(tree.pos, value).setType(tree.type); + case ConstantType(_, AConstant value): + return gen.Literal(tree.pos, value); case PolyType(Symbol[] tparams, Type restp): if (tparams.length == 0) { switch (restp) { - case ConstantType(_, Object value): - return make.Literal(tree.pos, value).setType(tree.type); + case ConstantType(_, AConstant value): + return gen.Literal(tree.pos, value); } } } @@ -1386,25 +1387,24 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } if (!(owntype instanceof Type.PolyType || owntype.isSubType(pt))) { switch (tree) { - case Literal(Object value): + case Literal(AConstant constant): int n = Integer.MAX_VALUE; - if (value instanceof Integer) - n = ((Integer) value).intValue(); - else if (value instanceof Character) - n = ((Character) value).charValue(); - Object value1 = null; + switch (constant) { + case INT(int value): n = value; break; + case CHAR(char value): n = value; break; + } + AConstant value1 = null; if (pt.symbol() == definitions.BYTE_CLASS && -128 <= n && n <= 127) - value1 = new Byte((byte) n); + value1 = AConstant.BYTE((byte) n); else if (pt.symbol() == definitions.SHORT_CLASS && -32768 <= n && n <= 32767) - value1 = new Short((short) n); + value1 = AConstant.SHORT((short) n); else if (pt.symbol() == definitions.CHAR_CLASS && 0 <= n && n <= 65535) - value1 = new Character((char) n); + value1 = AConstant.CHAR((char) n); if (value1 != null) - return make.Literal(tree.pos, value1) - .setType(Type.ConstantType(pt, value1)); + return gen.Literal(tree.pos, value1); break; } if ((mode & EXPRmode) != 0) { @@ -2286,17 +2286,13 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { // constant fold asInstanceOf calls. switch (fn1) { case Select(Tree qual, Name name): - if (fn1.symbol() == definitions.ANY_AS && - qual.type instanceof Type.ConstantType) { - Type restp1 = constfold.foldAsInstanceOf( - tree.pos, - (Type.ConstantType)qual.type, - argtypes[0]); - switch (restp1) { - case ConstantType(_, Object value): - return make.Literal(tree.pos, value) - .setType(restp1); - } + if (fn1.symbol() == definitions.ANY_AS) { + switch (qual.type()) { + case ConstantType(_, AConstant value): + value = constfold.cast(value, argtypes[0]); + if (value != null) + return gen.Literal(tree.pos, value); + } } } return constfold.tryToFold( @@ -2592,7 +2588,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return transformIdent(tree, name); } - case Literal(Object value): + case Literal(AConstant value): return tree.setType(Type.constantType(value)); case LabelDef(Name name, Ident[] params, Tree body): diff --git a/sources/scalac/typechecker/ConstantFolder.java b/sources/scalac/typechecker/ConstantFolder.java index 46d33b702f..20b37323eb 100644 --- a/sources/scalac/typechecker/ConstantFolder.java +++ b/sources/scalac/typechecker/ConstantFolder.java @@ -12,331 +12,352 @@ package scalac.typechecker; -import scalac.util.*; -import scalac.ast.*; -import scalac.symtab.*; -import scalac.symtab.Type.*; +import scalac.Global; +import scalac.ast.Tree; +import scalac.ast.TreeGen; +import scalac.atree.AConstant; +import scalac.atree.ATypeKind; +import scalac.symtab.Definitions; +import scalac.symtab.Type; +import scalac.util.Name; +import scalac.util.Names; -class ConstantFolder implements /*imports*/ TypeTags { +public class ConstantFolder { - private final Analyzer ana; + //######################################################################## + // Private Fields - ConstantFolder(Analyzer ana) { - this.ana = ana; + /** The global definitions */ + private final Definitions definitions; + + /** The tree generator */ + private final TreeGen gen; + + //######################################################################## + // Public Constructors + + /** Initializes this instance. */ + public ConstantFolder(Global global) { + this.definitions = global.definitions; + this.gen = global.treeGen; } - /** fold binary operation. + //######################################################################## + // Public Methods + + /** + * Attempts to constant fold given tree. Returns the input tree if + * constant folding fails. */ - Type foldBinary(int pos, ConstantType left, ConstantType right, Name op) { - try { - Type ltype = left.deconst(); - Symbol lsymbol = left.symbol(); - if (lsymbol == ana.definitions.BYTE_CLASS || - lsymbol == ana.definitions.CHAR_CLASS || - lsymbol == ana.definitions.SHORT_CLASS) { - ltype = ana.definitions.INT_TYPE(); - lsymbol = ana.definitions.INT_CLASS; - } - Type rtype = right.deconst(); - Symbol rsymbol = right.symbol(); - if (rsymbol == ana.definitions.BYTE_CLASS || - rsymbol == ana.definitions.CHAR_CLASS || - rsymbol == ana.definitions.SHORT_CLASS) { - rtype = ana.definitions.INT_TYPE(); - rsymbol = ana.definitions.INT_CLASS; - } - Type optype; - if (ltype.isSameAs(rtype)) - optype = ltype; - else if (lsymbol == ana.definitions.JAVA_STRING_CLASS) - optype = ltype; - else if (rsymbol == ana.definitions.JAVA_STRING_CLASS) - optype = rtype; - else if (lsymbol == ana.definitions.INT_CLASS) - optype = rtype; - else if (rsymbol == ana.definitions.INT_CLASS) - optype = ltype; - else if (lsymbol == ana.definitions.LONG_CLASS) - optype = rtype; - else if (rsymbol == ana.definitions.LONG_CLASS) - optype = ltype; - else if (lsymbol == ana.definitions.FLOAT_CLASS) - optype = rtype; - else if (rsymbol == ana.definitions.FLOAT_CLASS) - optype = ltype; - else - throw Debug.abort("illegal case", ltype + " - " + rtype); - Object value = null; - switch (optype.unbox()) { - case UnboxedType(INT): - if (op == Names.ADD) - value = new Integer(left.intValue() + right.intValue()); - else if (op == Names.SUB) - value = new Integer(left.intValue() - right.intValue()); - else if (op == Names.MUL) - value = new Integer(left.intValue() * right.intValue()); - else if (op == Names.DIV) - value = new Integer(left.intValue() / right.intValue()); - else if (op == Names.MOD) - value = new Integer(left.intValue() % right.intValue()); - else if (op == Names.EQ) - value = new Boolean(left.intValue() == right.intValue()); - else if (op == Names.NE) - value = new Boolean(left.intValue() != right.intValue()); - else if (op == Names.LT) - value = new Boolean(left.intValue() < right.intValue()); - else if (op == Names.GT) - value = new Boolean(left.intValue() > right.intValue()); - else if (op == Names.LE) - value = new Boolean(left.intValue() <= right.intValue()); - else if (op == Names.GE) - value = new Boolean(left.intValue() >= right.intValue()); - else if (op == Names.OR) - value = new Integer(left.intValue() | right.intValue()); - else if (op == Names.AND) - value = new Integer(left.intValue() & right.intValue()); - else if (op == Names.XOR) - value = new Integer(left.intValue() ^ right.intValue()); - else if (op == Names.LSL) - value = new Integer(left.intValue() << right.intValue()); - else if (op == Names.LSR) - value = new Integer(left.intValue() >>> right.intValue()); - else if (op == Names.ASR) - value = new Integer(left.intValue() >> right.intValue()); - break; - case UnboxedType(LONG): - if (op == Names.ADD) - value = new Long(left.longValue() + right.longValue()); - else if (op == Names.SUB) - value = new Long(left.longValue() - right.longValue()); - else if (op == Names.MUL) - value = new Long(left.longValue() * right.longValue()); - else if (op == Names.DIV) - value = new Long(left.longValue() / right.longValue()); - else if (op == Names.MOD) - value = new Long(left.longValue() % right.longValue()); - else if (op == Names.EQ) - value = new Boolean(left.longValue() == right.longValue()); - else if (op == Names.NE) - value = new Boolean(left.longValue() != right.longValue()); - else if (op == Names.LT) - value = new Boolean(left.longValue() < right.longValue()); - else if (op == Names.GT) - value = new Boolean(left.longValue() > right.longValue()); - else if (op == Names.LE) - value = new Boolean(left.longValue() <= right.longValue()); - else if (op == Names.GE) - value = new Boolean(left.longValue() >= right.longValue()); - else if (op == Names.OR) - value = new Long(left.longValue() | right.longValue()); - else if (op == Names.AND) - value = new Long(left.longValue() & right.longValue()); - else if (op == Names.XOR) - value = new Long(left.longValue() ^ right.longValue()); - else if (op == Names.LSL) - value = new Long(left.longValue() << right.intValue()); - else if (op == Names.LSR) - value = new Long(left.longValue() >>> right.intValue()); - else if (op == Names.ASR) - value = new Long(left.longValue() >> right.intValue()); - break; - case UnboxedType(FLOAT): - if (op == Names.ADD) - value = new Float(left.floatValue() + right.floatValue()); - else if (op == Names.SUB) - value = new Float(left.floatValue() - right.floatValue()); - else if (op == Names.MUL) - value = new Float(left.floatValue() * right.floatValue()); - else if (op == Names.DIV) - value = new Float(left.floatValue() / right.floatValue()); - else if (op == Names.MOD) - value = new Float(left.floatValue() % right.floatValue()); - else if (op == Names.EQ) - value = new Boolean(left.floatValue() == right.floatValue()); - else if (op == Names.NE) - value = new Boolean(left.floatValue() != right.floatValue()); - else if (op == Names.LT) - value = new Boolean(left.floatValue() < right.floatValue()); - else if (op == Names.GT) - value = new Boolean(left.floatValue() > right.floatValue()); - else if (op == Names.LE) - value = new Boolean(left.floatValue() <= right.floatValue()); - else if (op == Names.GE) - value = new Boolean(left.floatValue() >= right.floatValue()); - break; - case UnboxedType(DOUBLE): - if (op == Names.ADD) - value = new Double(left.doubleValue() + right.doubleValue()); - else if (op == Names.SUB) - value = new Double(left.doubleValue() - right.doubleValue()); - else if (op == Names.MUL) - value = new Double(left.doubleValue() * right.doubleValue()); - else if (op == Names.DIV) - value = new Double(left.doubleValue() / right.doubleValue()); - else if (op == Names.MOD) - value = new Double(left.doubleValue() % right.doubleValue()); - else if (op == Names.EQ) - value = new Boolean(left.doubleValue() == right.doubleValue()); - else if (op == Names.NE) - value = new Boolean(left.doubleValue() != right.doubleValue()); - else if (op == Names.LT) - value = new Boolean(left.doubleValue() < right.doubleValue()); - else if (op == Names.GT) - value = new Boolean(left.doubleValue() > right.doubleValue()); - else if (op == Names.LE) - value = new Boolean(left.doubleValue() <= right.doubleValue()); - else if (op == Names.GE) - value = new Boolean(left.doubleValue() >= right.doubleValue()); - break; - case UnboxedType(BOOLEAN): - if (op == Names.EQ) - value = new Boolean(left.booleanValue() == right.booleanValue()); - else if (op == Names.NE) - value = new Boolean(left.booleanValue() != right.booleanValue()); - else if (op == Names.OR || op == Names.ZOR) - value = new Boolean(left.booleanValue() | right.booleanValue()); - else if (op == Names.AND || op == Names.ZAND) - value = new Boolean(left.booleanValue() & right.booleanValue()); - else if (op == Names.XOR) - value = new Boolean(left.booleanValue() ^ right.booleanValue()); - break; - default: - if (optype.symbol() == ana.definitions.JAVA_STRING_CLASS && - op == Names.ADD) - value = left.stringValue() + right.stringValue(); - } - return (value != null) ? Type.constantType(value) : Type.NoType; - } catch (ArithmeticException e) { - ana.unit.warning(pos, e.toString()); - return Type.NoType; - } + public Tree tryToFold(Tree tree) { + AConstant value = evaluate(tree); + return value != null ? gen.Literal(tree.pos, value) : tree; } - /** fold unary operation. + /** + * Evaluates the expression represented by the tree and returns + * the resulting value. Returns null if the evaluation can't be + * performed. */ - Type foldUnary(int pos, ConstantType od, Name op) { - try { - Object value = null; - switch (od.deconst().unbox()) { - case UnboxedType(INT): - if (op == Names.ADD) - value = new Integer(od.intValue()); - else if (op == Names.SUB) - value = new Integer(-od.intValue()); - else if (op == Names.NOT) - value = new Integer(~od.intValue()); - break; - case UnboxedType(LONG): - if (op == Names.ADD) - value = new Long(od.longValue()); - else if (op == Names.SUB) - value = new Long(-od.longValue()); - else if (op == Names.NOT) - value = new Long(~od.longValue()); - break; - case UnboxedType(FLOAT): - if (op == Names.ADD) - value = new Float(od.floatValue()); - else if (op == Names.SUB) - value = new Float(-od.floatValue()); - break; - case UnboxedType(DOUBLE): - if (op == Names.ADD) - value = new Double(od.doubleValue()); - else if (op == Names.SUB) - value = new Double(-od.doubleValue()); - break; - case UnboxedType(BOOLEAN): - if (op == Names.ZNOT) - value = new Boolean(!od.booleanValue()); - break; - } - return (value != null) ? Type.constantType(value) : Type.NoType; - } catch (ArithmeticException e) { - ana.unit.warning(pos, e.toString()); - return Type.NoType; + public AConstant evaluate(Tree tree) { + switch (tree) { + case TypeApply(Select(Tree qualifier, Name op), Tree[] args): + switch (qualifier.type()) { + case ConstantType(_, AConstant lvalue): + if (args.length == 1 && op == Names.asInstanceOf) + return cast(lvalue, args[0].type()); + return null; + default: + return null; + } + case Apply(Select(Tree qualifier, Name op), Tree[] args): + switch (qualifier.type()) { + case ConstantType(_, AConstant lvalue): + switch (args.length) { + case 0: + return evaluate(op, lvalue); + case 1: + switch (args[0].type()) { + case ConstantType(_, AConstant rvalue): + return evaluate(op, lvalue, rvalue); + default: + return null; + } + default: + return null; + } + default: + return null; + } + default: + return null; } } - /** fold cast operation + /** + * Evaluates the unary operation and returns the resulting value. + * Returns null if the evaluation can't be performed. */ - Type foldAsInstanceOf(int pos, ConstantType od, Type argtype) { - try { - Object value = null; - switch (argtype.unbox()) { - case UnboxedType(BYTE): - value = new Byte((byte)od.intValue()); - break; - case UnboxedType(CHAR): - value = new Character((char)od.intValue()); - break; - case UnboxedType(SHORT): - value = new Short((short)od.intValue()); - break; - case UnboxedType(INT): - value = new Integer(od.intValue()); - break; - case UnboxedType(LONG): - value = new Long(od.longValue()); - break; - case UnboxedType(FLOAT): - value = new Float(od.longValue()); - break; - case UnboxedType(DOUBLE): - value = new Double(od.doubleValue()); - break; - case UnboxedType(BOOLEAN): - value = new Boolean(od.booleanValue()); - break; - } - return (value != null) ? new ConstantType(argtype, value) - : Type.NoType; - } catch (ClassCastException e) { - ana.unit.warning(pos, e.toString()); - return Type.NoType; - } + public AConstant evaluate(Name op, AConstant value) { + switch (kind(value)) { + case ATypeKind.BOOL: + boolean v = value.booleanValue(); + if (op == Names.ZNOT) return AConstant.BOOLEAN(!v); + return null; + case ATypeKind.I4: + int v = value.intValue(); + if (op == Names.ADD) return AConstant.INT(+v); + if (op == Names.SUB) return AConstant.INT(-v); + if (op == Names.NOT) return AConstant.INT(~v); + return null; + case ATypeKind.I8: + long v = value.longValue(); + if (op == Names.ADD) return AConstant.LONG(+v); + if (op == Names.SUB) return AConstant.LONG(-v); + if (op == Names.NOT) return AConstant.LONG(~v); + return null; + case ATypeKind.R4: + float v = value.floatValue(); + if (op == Names.ADD) return AConstant.FLOAT(+v); + if (op == Names.SUB) return AConstant.FLOAT(-v); + return null; + case ATypeKind.R8: + double v = value.doubleValue(); + if (op == Names.ADD) return AConstant.DOUBLE(+v); + if (op == Names.SUB) return AConstant.DOUBLE(-v); + return null; + default: + return null; + } } - /** attempt to constant fold tree. + /** + * Evaluates the binary operation and returns the resulting value. + * Returns null if the evaluation can't be performed. */ - Tree tryToFold(Tree tree) { - Type ctp = Type.NoType; - switch (tree) { - case Apply(Select(Tree qual, Name op), Tree[] args): - if (qual.type instanceof ConstantType) { - if (args.length == 0) - ctp = foldUnary( - tree.pos, (ConstantType)qual.type, op); - else if (args.length == 1 && - args[0].type instanceof ConstantType) - ctp = foldBinary( - tree.pos, - (ConstantType)qual.type, - (ConstantType)(args[0].type), - op); - } - break; - case TypeApply(Select(Tree qual, Name op), Tree[] targs): - if (qual.type instanceof Type.ConstantType && - op == Names.asInstanceOf) - ctp = foldAsInstanceOf( - tree.pos, - (ConstantType)qual.type, - targs[0].type); - break; - } - switch (ctp) { - case ConstantType(Type base, Object value): - return ana.make.Literal(tree.pos, value).setType(ctp); - default: - return tree; - } - } + public AConstant evaluate(Name op, AConstant lvalue, AConstant rvalue) { + ATypeKind kind = kind(lvalue, rvalue); + if (kind == null) return null; + switch (kind) { -} + case ATypeKind.I4: + int l = lvalue.intValue(); + int r = rvalue.intValue(); + if (op == Names.OR ) return AConstant.INT(l | r); + if (op == Names.AND) return AConstant.INT(l & r); + if (op == Names.XOR) return AConstant.INT(l ^ r); + if (op == Names.ADD) return AConstant.INT(l + r); + if (op == Names.SUB) return AConstant.INT(l - r); + if (op == Names.MUL) return AConstant.INT(l * r); + if (op == Names.DIV) return r == 0 ? null : AConstant.INT(l / r); + if (op == Names.MOD) return r == 0 ? null : AConstant.INT(l % r); + if (op == Names.EQ ) return AConstant.BOOLEAN(l == r); + if (op == Names.NE ) return AConstant.BOOLEAN(l != r); + if (op == Names.LT ) return AConstant.BOOLEAN(l < r); + if (op == Names.GT ) return AConstant.BOOLEAN(l > r); + if (op == Names.LE ) return AConstant.BOOLEAN(l <= r); + if (op == Names.GE ) return AConstant.BOOLEAN(l >= r); + if (op == Names.LSL) return AConstant.INT(l << r); + if (op == Names.LSR) return AConstant.INT(l >>> r); + if (op == Names.ASR) return AConstant.INT(l >> r); + return null; + case ATypeKind.I8: + long l = lvalue.longValue(); + long r = rvalue.longValue(); + if (op == Names.OR ) return AConstant.LONG(l | r); + if (op == Names.AND) return AConstant.LONG(l & r); + if (op == Names.XOR) return AConstant.LONG(l ^ r); + if (op == Names.ADD) return AConstant.LONG(l + r); + if (op == Names.SUB) return AConstant.LONG(l - r); + if (op == Names.MUL) return AConstant.LONG(l * r); + if (op == Names.DIV) return r == 0 ? null : AConstant.LONG(l / r); + if (op == Names.MOD) return r == 0 ? null : AConstant.LONG(l % r); + if (op == Names.EQ ) return AConstant.BOOLEAN(l == r); + if (op == Names.NE ) return AConstant.BOOLEAN(l != r); + if (op == Names.LT ) return AConstant.BOOLEAN(l < r); + if (op == Names.GT ) return AConstant.BOOLEAN(l > r); + if (op == Names.LE ) return AConstant.BOOLEAN(l <= r); + if (op == Names.GE ) return AConstant.BOOLEAN(l >= r); + if (kind(lvalue) == ATypeKind.I4) { + int li = lvalue.intValue(); + if (op == Names.LSL) return AConstant.INT(li << r); + if (op == Names.LSR) return AConstant.INT(li >>> r); + if (op == Names.ASR) return AConstant.INT(li >> r); + } else { + if (op == Names.LSL) return AConstant.LONG(l << r); + if (op == Names.LSR) return AConstant.LONG(l >>> r); + if (op == Names.ASR) return AConstant.LONG(l >> r); + } + return null; + case ATypeKind.R4: + float l = lvalue.floatValue(); + float r = rvalue.floatValue(); + if (op == Names.ADD) return AConstant.FLOAT(l + r); + if (op == Names.SUB) return AConstant.FLOAT(l - r); + if (op == Names.MUL) return AConstant.FLOAT(l * r); + if (op == Names.DIV) return AConstant.FLOAT(l / r); + if (op == Names.MOD) return AConstant.FLOAT(l % r); + if (op == Names.EQ ) return AConstant.BOOLEAN(l == r); + if (op == Names.NE ) return AConstant.BOOLEAN(l != r); + if (op == Names.LT ) return AConstant.BOOLEAN(l < r); + if (op == Names.GT ) return AConstant.BOOLEAN(l > r); + if (op == Names.LE ) return AConstant.BOOLEAN(l <= r); + if (op == Names.GE ) return AConstant.BOOLEAN(l >= r); + return null; + case ATypeKind.R8: + double l = lvalue.doubleValue(); + double r = rvalue.doubleValue(); + if (op == Names.ADD) return AConstant.DOUBLE(l + r); + if (op == Names.SUB) return AConstant.DOUBLE(l - r); + if (op == Names.MUL) return AConstant.DOUBLE(l * r); + if (op == Names.DIV) return AConstant.DOUBLE(l / r); + if (op == Names.MOD) return AConstant.DOUBLE(l % r); + if (op == Names.EQ ) return AConstant.BOOLEAN(l == r); + if (op == Names.NE ) return AConstant.BOOLEAN(l != r); + if (op == Names.LT ) return AConstant.BOOLEAN(l < r); + if (op == Names.GT ) return AConstant.BOOLEAN(l > r); + if (op == Names.LE ) return AConstant.BOOLEAN(l <= r); + if (op == Names.GE ) return AConstant.BOOLEAN(l >= r); + return null; + case ATypeKind.BOOL: + boolean l = lvalue.booleanValue(); + boolean r = rvalue.booleanValue(); + if (op == Names.ZOR ) return AConstant.BOOLEAN(l | r); + if (op == Names.OR ) return AConstant.BOOLEAN(l | r); + if (op == Names.ZAND) return AConstant.BOOLEAN(l & r); + if (op == Names.AND ) return AConstant.BOOLEAN(l & r); + if (op == Names.XOR ) return AConstant.BOOLEAN(l ^ r); + if (op == Names.EQ ) return AConstant.BOOLEAN(l == r); + if (op == Names.NE ) return AConstant.BOOLEAN(l != r); + return null; + case ATypeKind.STR: + if (op == Names.ADD) + return AConstant.STRING(lvalue.stringValue()+rvalue.stringValue()); + return null; + default: + return null; + } + } + + /** + * Casts the value to given type and returns the resulting value. + * Returns null if the cast can't be performed. + */ + public AConstant cast(AConstant value, Type type) { + switch (value.kind()) { + case UNIT: + if (type.isSameAs(definitions.UNIT_CLASS.type())) + return value; + return null; + case BOOL: + if (type.isSameAs(definitions.BOOLEAN_TYPE())) + return value; + return null; + case U1: + case U2: + case U4: + case U8: + case I1: + case I2: + case I4: + case I8: + case R4: + case R8: + if (type.isSameAs(definitions.BYTE_TYPE())) + return AConstant.BYTE(value.byteValue()); + if (type.isSameAs(definitions.SHORT_TYPE())) + return AConstant.SHORT(value.shortValue()); + if (type.isSameAs(definitions.CHAR_TYPE())) + return AConstant.CHAR(value.charValue()); + if (type.isSameAs(definitions.INT_TYPE())) + return AConstant.INT(value.intValue()); + if (type.isSameAs(definitions.LONG_TYPE())) + return AConstant.LONG(value.longValue()); + if (type.isSameAs(definitions.FLOAT_TYPE())) + return AConstant.FLOAT(value.floatValue()); + if (type.isSameAs(definitions.DOUBLE_TYPE())) + return AConstant.DOUBLE(value.doubleValue()); + return null; + case STR: + if (type.isSameAs(definitions.JAVA_STRING_TYPE())) + return value; + return null; + default: + return null; + } + } + + //######################################################################## + // Private Methods + + /** Returns the kind of given value. */ + private ATypeKind kind(AConstant value) { + ATypeKind kind = value.kind(); + switch (kind) { + case I1: + case I2: + case U2: + return ATypeKind.I4; + default: + return kind; + } + } + + /** + * Returns the combined kind of given values or null if the values + * can't be combined. + */ + private ATypeKind kind(AConstant lvalue, AConstant rvalue) { + ATypeKind lkind = kind(lvalue); + ATypeKind rkind = kind(rvalue); + if (lkind == rkind) return lkind; + if (lkind == ATypeKind.ZERO) return null; + if (rkind == ATypeKind.ZERO) return null; + if (lkind == ATypeKind.STR) return lkind; + if (rkind == ATypeKind.STR) return rkind; + switch (lkind) { + case I4: + switch (rkind) { + case I4: return lkind; + case I8: return rkind; + case R4: return rkind; + case R8: return rkind; + default: return null; + } + case I8: + switch (rkind) { + case I4: return lkind; + case I8: return lkind; + case R4: return rkind; + case R8: return rkind; + default: return null; + } + case R4: + switch (rkind) { + case I4: return lkind; + case I8: return lkind; + case R4: return lkind; + case R8: return rkind; + default: return null; + } + case R8: + switch (rkind) { + case I4: return lkind; + case I8: return lkind; + case R4: return lkind; + case R8: return lkind; + default: return null; + } + default: + return null; + } + } + + //######################################################################## +} diff --git a/test/files/neg/bug45.check b/test/files/neg/bug45.check index 530bd78c42..fe8d97ec16 100644 --- a/test/files/neg/bug45.check +++ b/test/files/neg/bug45.check @@ -1,5 +1,5 @@ bug45.scala:4: type mismatch; - found : scala.AllRef + found : scala.AllRef(null) required: Int def foo[Int](x: Int): Int = null; ^ diff --git a/test/files/neg/constrparams.check b/test/files/neg/constrparams.check index 6aef035af0..6e7ec7671e 100644 --- a/test/files/neg/constrparams.check +++ b/test/files/neg/constrparams.check @@ -1,5 +1,5 @@ constrparams.scala:4: type mismatch; - found : scala.AllRef + found : scala.AllRef(null) required: x.t private val z: x.t = null; //error ^ diff --git a/test/files/shl/basic.check b/test/files/shl/basic.check index bee7e5192d..2a4cd09b49 100644 --- a/test/files/shl/basic.check +++ b/test/files/shl/basic.check @@ -1,12 +1,12 @@ > > > > > > (): scala.Unit > false: scala.Boolean(false) -> 1: scala.Char(1) +> 1: scala.Char('1') > 2: scala.Int(2) > 3: scala.Long(3) > 4.0: scala.Float(4.0) > 5.0: scala.Double(5.0) -> null: scala.AllRef -> hello: java.lang.String(hello) +> null: scala.AllRef(null) +> hello: java.lang.String("hello") > List(): scala.Nil > List(1,2,3): scala.List[scala.Int] > > Exception in thread "main" java.lang.Error: error |