From a1c99ffc7b0c53f4a95bd8fe934e65f4a03002d6 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 21 Jan 2012 10:40:46 +0100 Subject: wip --- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 354b8caaa3..86c014a181 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -828,8 +828,14 @@ trait Namers extends MethodSynthesis { if (inheritsSelf || tp.isError) AnyRefClass.tpe else tp } - - val parents = typer.parentTypes(templ) map checkParent + + var parents = typer.parentTypes(templ) map checkParent + if (clazz.hasAnnotation(ScalaInlineClass)) { + if (!(parents exists (_.typeSymbol == NotNullClass))) + parents = parents :+ NotNullClass.tpe + clazz setFlag FINAL + } + enterSelf(templ.self) val decls = new Scope -- cgit v1.2.3 From 09544b756a1274c7cc2bdd302fd9bd1d33a16b70 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 26 Jan 2012 12:28:05 +0100 Subject: Dropping what looks like debug output from error message. Before the change, writing `class C extends AnyVal` in the REPL produced a compiler crash due to a NPE. --- src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index a762e44bda..177da9fcf9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -530,7 +530,7 @@ trait ContextErrors { NormalTypeError(parent, "illegal inheritance from final "+mixin) def ParentSealedInheritanceError(parent: Tree, psym: Symbol) = - NormalTypeError(parent, "illegal inheritance from sealed " + psym + ": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath) + NormalTypeError(parent, "illegal inheritance from sealed " + psym ) def ParentSelfTypeConformanceError(parent: Tree, selfType: Type) = NormalTypeError(parent, -- cgit v1.2.3 From e61eff23df977eeed19bfe253b01b69cce47dfa3 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 27 Jan 2012 16:30:01 -0800 Subject: Unsealed AnyVal. Hacks here and there to allow them to survive at least to erasure. Since nothing is done with them there yet, they inevitably crash and burn a little ways beyond that. --- src/compiler/scala/reflect/internal/TreeInfo.scala | 11 +- .../scala/reflect/internal/TreePrinters.scala | 23 +++-- src/compiler/scala/reflect/internal/Trees.scala | 12 +++ src/compiler/scala/tools/cmd/gen/AnyVals.scala | 6 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 20 ++-- .../tools/nsc/interpreter/MemberHandlers.scala | 2 +- .../tools/nsc/typechecker/ContextErrors.scala | 2 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 10 +- .../scala/tools/nsc/typechecker/Typers.scala | 10 +- src/library/scala/AnyVal.scala | 4 +- src/library/scala/Boolean.scala | 2 +- src/library/scala/Byte.scala | 114 ++++++++++----------- src/library/scala/Char.scala | 114 ++++++++++----------- src/library/scala/Double.scala | 2 +- src/library/scala/Float.scala | 2 +- src/library/scala/Int.scala | 114 ++++++++++----------- src/library/scala/Long.scala | 114 ++++++++++----------- src/library/scala/Short.scala | 114 ++++++++++----------- src/library/scala/Unit.scala | 2 +- test/files/pos/anyval-children.scala | 1 + 20 files changed, 347 insertions(+), 332 deletions(-) create mode 100644 test/files/pos/anyval-children.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index e3ee39d2a0..4380487555 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -440,15 +440,6 @@ abstract class TreeInfo { EmptyTree } - /** Is the tree Predef, scala.Predef, or _root_.scala.Predef? - */ - def isPredefExpr(t: Tree) = t match { - case Ident(nme.Predef) => true - case Select(Ident(nme.scala_), nme.Predef) => true - case Select(Select(Ident(nme.ROOTPKG), nme.scala_), nme.Predef) => true - case _ => false - } - /** Does list of trees start with a definition of * a class of module with given name (ignoring imports) */ @@ -468,7 +459,7 @@ abstract class TreeInfo { // Top-level definition whose leading imports include Predef. def containsLeadingPredefImport(defs: List[Tree]): Boolean = defs match { case PackageDef(_, defs1) :: _ => containsLeadingPredefImport(defs1) - case Import(expr, _) :: rest => isPredefExpr(expr) || containsLeadingPredefImport(rest) + case Import(expr, _) :: rest => isReferenceToPredef(expr) || containsLeadingPredefImport(rest) case _ => false } diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala index 3a0717d344..00c20535ba 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -235,16 +235,21 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => case Template(parents, self, body) => val currentOwner1 = currentOwner if (tree.symbol != NoSymbol) currentOwner = tree.symbol.owner - printRow(parents, " with ") - if (!body.isEmpty) { - if (self.name != nme.WILDCARD) { - print(" { ", self.name); printOpt(": ", self.tpt); print(" => ") - } else if (!self.tpt.isEmpty) { - print(" { _ : ", self.tpt, " => ") - } else { - print(" {") + if (parents exists isReferenceToAnyVal) { + print("AnyVal") + } + else { + printRow(parents, " with ") + if (!body.isEmpty) { + if (self.name != nme.WILDCARD) { + print(" { ", self.name); printOpt(": ", self.tpt); print(" => ") + } else if (!self.tpt.isEmpty) { + print(" { _ : ", self.tpt, " => ") + } else { + print(" {") + } + printColumn(body, "", ";", "}") } - printColumn(body, "", ";", "}") } currentOwner = currentOwner1 diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 5bb0c98bfb..7ce087df2f 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -10,6 +10,18 @@ import Flags._ import api.Modifier trait Trees extends api.Trees { self: SymbolTable => + + // Belongs in TreeInfo but then I can't reach it from TreePrinters. + def isReferenceToScalaMember(t: Tree, Id: Name) = t match { + case Ident(Id) => true + case Select(Ident(nme.scala_), Id) => true + case Select(Select(Ident(nme.ROOTPKG), nme.scala_), Id) => true + case _ => false + } + /** Is the tree Predef, scala.Predef, or _root_.scala.Predef? + */ + def isReferenceToPredef(t: Tree) = isReferenceToScalaMember(t, nme.Predef) + def isReferenceToAnyVal(t: Tree) = isReferenceToScalaMember(t, tpnme.AnyVal) // --- modifiers implementation --------------------------------------- diff --git a/src/compiler/scala/tools/cmd/gen/AnyVals.scala b/src/compiler/scala/tools/cmd/gen/AnyVals.scala index 8f82c997db..ab4a4a4402 100644 --- a/src/compiler/scala/tools/cmd/gen/AnyVals.scala +++ b/src/compiler/scala/tools/cmd/gen/AnyVals.scala @@ -182,7 +182,7 @@ trait AnyValReps { def classLines: List[String] def objectLines: List[String] def commonClassLines = List( - "def getClass(): Class[@name@]" + "override def getClass(): Class[@name@]" ) def lcname = name.toLowerCase @@ -429,7 +429,7 @@ def &(x: Boolean): Boolean = sys.error("stub") */ def ^(x: Boolean): Boolean = sys.error("stub") -def getClass(): Class[Boolean] = sys.error("stub") +override def getClass(): Class[Boolean] = sys.error("stub") """.trim.lines.toList def objectLines = interpolate(allCompanions).lines.toList @@ -443,7 +443,7 @@ def getClass(): Class[Boolean] = sys.error("stub") */ """ def classLines = List( - """def getClass(): Class[Unit] = sys.error("stub")""" + """override def getClass(): Class[Unit] = sys.error("stub")""" ) def objectLines = interpolate(allCompanions).lines.toList diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index fe6dcc9138..c3e156104f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -290,11 +290,11 @@ self => inScalaPackage = false currentPackage = "" } - private lazy val anyValNames: Set[Name] = tpnme.ScalaValueNames.toSet + tpnme.AnyVal + private lazy val primitiveNames: Set[Name] = tpnme.ScalaValueNames.toSet - private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" - private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array - private def isAnyValType(name: Name) = inScalaRootPackage && anyValNames(name) + private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" + private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array + private def isPrimitiveType(name: Name) = inScalaRootPackage && primitiveNames(name) def parseStartRule: () => Tree @@ -2753,9 +2753,15 @@ self => val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { - if (isAnyValType(name)) { - val parent = if (name == tpnme.AnyVal) tpnme.Any else tpnme.AnyVal - Template(List(scalaDot(parent)), self, body) + if (isPrimitiveType(name)) { + Template(List(scalaDot(tpnme.AnyVal)), self, body) + } + else if (parents0 exists isReferenceToAnyVal) { + // TODO - enforce @inline annotation, and no other parents + Template(parents0, self, body) + } + else if (name == tpnme.AnyVal) { + Template(List(scalaDot(tpnme.Any)), self, body) } else { val parents = ( diff --git a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala index c742ab89c0..37dd032135 100644 --- a/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala +++ b/src/compiler/scala/tools/nsc/interpreter/MemberHandlers.scala @@ -182,7 +182,7 @@ trait MemberHandlers { // TODO: Need to track these specially to honor Predef masking attempts, // because they must be the leading imports in the code generated for each // line. We can use the same machinery as Contexts now, anyway. - def isPredefImport = treeInfo.isPredefExpr(expr) + def isPredefImport = isReferenceToPredef(expr) // wildcard imports, e.g. import foo._ private def selectorWild = selectors filter (_.name == nme.USCOREkw) diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 6ee09d064f..ed18e2ead5 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -534,7 +534,7 @@ trait ContextErrors { NormalTypeError(parent, "illegal inheritance from final "+mixin) def ParentSealedInheritanceError(parent: Tree, psym: Symbol) = - NormalTypeError(parent, "illegal inheritance from sealed " + psym + ": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath) + NormalTypeError(parent, "illegal inheritance from sealed " + psym)// + ": " + context.unit.source.file.canonicalPath + " != " + psym.sourceFile.canonicalPath) def ParentSelfTypeConformanceError(parent: Tree, selfType: Type) = NormalTypeError(parent, diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index a99d09173e..d492ba3662 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -685,10 +685,12 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R unit.error(clazz.pos, abstractErrorMessage) } else if (clazz.isTrait) { // prevent abstract methods in interfaces that override final members in Object; see #4431 - for (decl <- clazz.info.decls.iterator) { - val overridden = decl.overriddenSymbol(ObjectClass) - if (overridden.isFinal) - unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") + if (!(clazz isSubClass AnyValClass)) { + for (decl <- clazz.info.decls.iterator) { + val overridden = decl.overriddenSymbol(ObjectClass) + if (overridden.isFinal) + unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") + } } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 770b55d6ab..f2aa1fcae4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1336,13 +1336,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (psym.isFinal) pending += ParentFinalInheritanceError(parent, psym) - if (psym.isSealed && !phase.erasedTypes) { - // AnyVal is sealed, but we have to let the value classes through manually - if (context.unit.source.file == psym.sourceFile || isValueClass(context.owner)) - psym addChild context.owner - else - pending += ParentSealedInheritanceError(parent, psym) - } + if (psym.isSealed && !phase.erasedTypes) + pending += ParentSealedInheritanceError(parent, psym) + if (!(selfType <:< parent.tpe.typeOfThis) && !phase.erasedTypes && !context.owner.isSynthetic && // don't check synthetic concrete classes for virtuals (part of DEVIRTUALIZE) diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index cd2c04dbd8..53d7288ab2 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -25,4 +25,6 @@ package scala * The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ -sealed trait AnyVal +trait AnyVal { + def getClass(): Class[_ <: AnyVal] = ??? +} diff --git a/src/library/scala/Boolean.scala b/src/library/scala/Boolean.scala index 0adcde3aba..5078e59d28 100644 --- a/src/library/scala/Boolean.scala +++ b/src/library/scala/Boolean.scala @@ -107,7 +107,7 @@ final class Boolean extends AnyVal { */ def ^(x: Boolean): Boolean = sys.error("stub") - def getClass(): Class[Boolean] = sys.error("stub") + override def getClass(): Class[Boolean] = sys.error("stub") } object Boolean extends AnyValCompanion { diff --git a/src/library/scala/Byte.scala b/src/library/scala/Byte.scala index 4923cc9786..beff5ce208 100644 --- a/src/library/scala/Byte.scala +++ b/src/library/scala/Byte.scala @@ -30,7 +30,7 @@ final class Byte extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Byte extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Byte extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Byte extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -590,7 +590,7 @@ final class Byte extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Byte] = sys.error("stub") + override def getClass(): Class[Byte] = sys.error("stub") } object Byte extends AnyValCompanion { diff --git a/src/library/scala/Char.scala b/src/library/scala/Char.scala index b4e6445899..dade572396 100644 --- a/src/library/scala/Char.scala +++ b/src/library/scala/Char.scala @@ -30,7 +30,7 @@ final class Char extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Char extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Char extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Char extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -590,7 +590,7 @@ final class Char extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Char] = sys.error("stub") + override def getClass(): Class[Char] = sys.error("stub") } object Char extends AnyValCompanion { diff --git a/src/library/scala/Double.scala b/src/library/scala/Double.scala index 68a1a01299..01414265c4 100644 --- a/src/library/scala/Double.scala +++ b/src/library/scala/Double.scala @@ -356,7 +356,7 @@ final class Double extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Double] = sys.error("stub") + override def getClass(): Class[Double] = sys.error("stub") } object Double extends AnyValCompanion { diff --git a/src/library/scala/Float.scala b/src/library/scala/Float.scala index 709d73d408..ff5b3cb112 100644 --- a/src/library/scala/Float.scala +++ b/src/library/scala/Float.scala @@ -356,7 +356,7 @@ final class Float extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Float] = sys.error("stub") + override def getClass(): Class[Float] = sys.error("stub") } object Float extends AnyValCompanion { diff --git a/src/library/scala/Int.scala b/src/library/scala/Int.scala index 519a0486ac..6b7debf2df 100644 --- a/src/library/scala/Int.scala +++ b/src/library/scala/Int.scala @@ -30,7 +30,7 @@ final class Int extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Int extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Int extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Int extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -590,7 +590,7 @@ final class Int extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Int] = sys.error("stub") + override def getClass(): Class[Int] = sys.error("stub") } object Int extends AnyValCompanion { diff --git a/src/library/scala/Long.scala b/src/library/scala/Long.scala index 9c7a803f08..e734c92112 100644 --- a/src/library/scala/Long.scala +++ b/src/library/scala/Long.scala @@ -30,7 +30,7 @@ final class Long extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Long extends AnyVal { def <<(x: Long): Long = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Long = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Long extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Long extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -590,7 +590,7 @@ final class Long extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Long] = sys.error("stub") + override def getClass(): Class[Long] = sys.error("stub") } object Long extends AnyValCompanion { diff --git a/src/library/scala/Short.scala b/src/library/scala/Short.scala index a9210d3555..98e227d992 100644 --- a/src/library/scala/Short.scala +++ b/src/library/scala/Short.scala @@ -30,7 +30,7 @@ final class Short extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Short extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Short extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Short extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -590,7 +590,7 @@ final class Short extends AnyVal { */ def %(x: Double): Double = sys.error("stub") - def getClass(): Class[Short] = sys.error("stub") + override def getClass(): Class[Short] = sys.error("stub") } object Short extends AnyValCompanion { diff --git a/src/library/scala/Unit.scala b/src/library/scala/Unit.scala index 57970b021b..f6ed0121ab 100644 --- a/src/library/scala/Unit.scala +++ b/src/library/scala/Unit.scala @@ -17,7 +17,7 @@ package scala * method which is declared `void`. */ final class Unit extends AnyVal { - def getClass(): Class[Unit] = sys.error("stub") + override def getClass(): Class[Unit] = sys.error("stub") } object Unit extends AnyValCompanion { diff --git a/test/files/pos/anyval-children.scala b/test/files/pos/anyval-children.scala new file mode 100644 index 0000000000..7a2eda8b3f --- /dev/null +++ b/test/files/pos/anyval-children.scala @@ -0,0 +1 @@ +class Bippy extends AnyVal \ No newline at end of file -- cgit v1.2.3 From a03c34c140709e95bb6ab6a8984747b83d630eea Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 29 Jan 2012 16:21:28 +0100 Subject: inline method expansion code --- .../scala/reflect/internal/Definitions.scala | 24 +-- .../scala/reflect/internal/Importers.scala | 4 +- src/compiler/scala/reflect/internal/Symbols.scala | 70 ++++----- src/compiler/scala/reflect/internal/Trees.scala | 22 ++- src/compiler/scala/reflect/internal/Types.scala | 167 +++++++++++---------- .../scala/reflect/runtime/JavaToScala.scala | 8 +- src/compiler/scala/tools/nsc/Global.scala | 61 ++++---- src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 4 + .../nsc/symtab/classfile/ClassfileParser.scala | 6 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 8 +- .../scala/tools/nsc/transform/Erasure.scala | 23 ++- .../scala/tools/nsc/transform/LiftCode.scala | 1 + .../tools/nsc/transform/SpecializeTypes.scala | 16 +- .../tools/nsc/typechecker/ContextErrors.scala | 56 +++---- .../scala/tools/nsc/typechecker/Namers.scala | 55 +++++-- .../scala/tools/nsc/typechecker/Typers.scala | 28 ++-- 16 files changed, 305 insertions(+), 248 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 1490d80d7a..e8fc1c9cc9 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -156,7 +156,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val RuntimePackage = getRequiredModule("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass - + lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum") // convenient one-argument parameter lists @@ -168,10 +168,10 @@ trait Definitions extends reflect.api.StandardDefinitions { private def booltype = BooleanClass.typeConstructor private def inttype = IntClass.typeConstructor private def stringtype = StringClass.typeConstructor - + // Java types def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName) - + def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { case java.lang.Void.TYPE => UnitClass case java.lang.Byte.TYPE => ByteClass @@ -264,7 +264,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def Predef_identity = getMember(PredefModule, nme.identity) def Predef_conforms = getMember(PredefModule, nme.conforms) def Predef_wrapRefArray = getMember(PredefModule, nme.wrapRefArray) - + /** Is `sym` a member of Predef with the given name? * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def` * which does a member lookup (it can't be a lazy val because we might reload Predef @@ -357,7 +357,7 @@ trait Definitions extends reflect.api.StandardDefinitions { ) lazy val EqualsPatternClass = { val clazz = newClass(ScalaPackageClass, tpnme.EQUALS_PATTERN_NAME, Nil) - clazz setInfo polyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, newScope, clazz)) + clazz setInfo GenPolyType(List(newTypeParam(clazz, 0)), ClassInfoType(anyparam, newScope, clazz)) } lazy val MatchingStrategyClass = getRequiredClass("scala.MatchingStrategy") @@ -499,7 +499,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case DoubleClass => nme.wrapDoubleArray case BooleanClass => nme.wrapBooleanArray case UnitClass => nme.wrapUnitArray - case _ => + case _ => if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray else nme.genericWrapArray } @@ -635,7 +635,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => false }) } - + // members of class scala.Any lazy val Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) lazy val Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) @@ -781,10 +781,10 @@ trait Definitions extends reflect.api.StandardDefinitions { while (result.isAliasType) result = result.info.typeSymbol result } - + def getRequiredModule(fullname: String): Symbol = getModule(newTermNameCached(fullname)) - def getRequiredClass(fullname: String): Symbol = + def getRequiredClass(fullname: String): Symbol = getClass(newTypeNameCached(fullname)) def getClassIfDefined(fullname: String): Symbol = @@ -842,7 +842,7 @@ trait Definitions extends reflect.api.StandardDefinitions { else*/ List(p) println("creating " + name + " with parents " + parents) */ clazz.setInfo( - polyType( + GenPolyType( List(tparam), ClassInfoType(List(AnyRefClass.tpe, p), newScope, clazz))) } @@ -859,7 +859,7 @@ trait Definitions extends reflect.api.StandardDefinitions { val msym = owner.info.decls enter owner.newMethod(name.encode) val tparam = newTypeParam(msym, 0) - msym setInfo polyType(List(tparam), tcon(tparam)(msym)) + msym setInfo GenPolyType(List(tparam), tcon(tparam)(msym)) } private def newTypeParam(owner: Symbol, index: Int): Symbol = @@ -961,7 +961,7 @@ trait Definitions extends reflect.api.StandardDefinitions { RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage - + val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 RepeatedParamClass, diff --git a/src/compiler/scala/reflect/internal/Importers.scala b/src/compiler/scala/reflect/internal/Importers.scala index 23b443919a..aaf586b074 100644 --- a/src/compiler/scala/reflect/internal/Importers.scala +++ b/src/compiler/scala/reflect/internal/Importers.scala @@ -70,7 +70,7 @@ trait Importers { self: SymbolTable => case from.PolyType(_, res) => res case result => result } - s setInfo polyType(mytypeParams, importType(result)) + s setInfo GenPolyType(mytypeParams, importType(result)) s setAnnotations (sym.annotations map importAnnotationInfo) } } @@ -157,7 +157,7 @@ trait Importers { self: SymbolTable => val myclazz = importSymbol(clazz) val myscope = if (myclazz.isPackageClass) newPackageScope(myclazz) else newScope val myclazzTpe = ClassInfoType(parents map importType, myscope, myclazz) - myclazz setInfo polyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope + myclazz setInfo GenPolyType(myclazz.typeParams, myclazzTpe) // needed so that newly created symbols find their scope decls foreach importSymbol // will enter itself into myclazz myclazzTpe case from.RefinedType(parents, decls) => diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 9f8476a6fe..009120af00 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -17,7 +17,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => import definitions._ protected var ids = 0 - + val emptySymbolArray = new Array[Symbol](0) def symbolCount = ids // statistics @@ -38,14 +38,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => nextexid += 1 newTypeName("_" + nextexid + suffix) } - + // Set the fields which point companions at one another. Returns the module. def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = { moduleClass.sourceModule = m m setModuleClass moduleClass m } - + /** Create a new free variable. Its owner is NoSymbol. */ def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar = @@ -84,19 +84,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api private[this] var _rawname = initName private[this] var _rawflags = 0L - + def rawowner = _rawowner def rawname = _rawname def rawflags = _rawflags - + protected def rawflags_=(x: FlagsType) { _rawflags = x } - + private var rawpos = initPos - + val id = nextId() // identity displayed when -uniqid private[this] var _validTo: Period = NoPeriod - + def validTo = _validTo def validTo_=(x: Period) { _validTo = x} @@ -169,10 +169,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = new TermSymbol(this, pos, name) initFlags newFlags - + def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol = new AbstractTypeSymbol(this, pos, name) initFlags newFlags - + def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol = new AliasTypeSymbol(this, pos, name) initFlags newFlags @@ -184,10 +184,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = new ClassSymbol(this, pos, name) initFlags newFlags - + def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol = new ModuleClassSymbol(this, pos, name) initFlags newFlags - + /** Derive whether it is an abstract type from the flags; after creation * the DEFERRED flag will be ignored. */ @@ -196,7 +196,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => newAliasTypeSymbol(name, pos, newFlags) else newAbstractTypeSymbol(name, pos, newFlags) - + def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem = if ((newFlags & DEFERRED) == 0L) new TypeSkolem(this, pos, name, origin) initFlags newFlags @@ -233,7 +233,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = newAliasTypeSymbol(name, pos, newFlags) - + /** Symbol of an abstract type type T >: ... <: ... */ final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = @@ -288,7 +288,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) = newClassSymbol(name, pos, newFlags) - + /** A new class with its info set to a ClassInfoType with given scope and parents. */ def newClassWithInfo(name: TypeName, parents: List[Type], scope: Scope, pos: Position = NoPosition, newFlags: Long = 0L) = { val clazz = newClass(name, pos, newFlags) @@ -340,9 +340,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos) @deprecated("Use the other signature", "2.10.0") def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos) - @deprecated("Use the other signature", "2.10.0") + @deprecated("Use the other signature", "2.10.0") def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos) - @deprecated("Use the other signature", "2.10.0") + @deprecated("Use the other signature", "2.10.0") def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos) // ----- locking and unlocking ------------------------------------------------------ @@ -485,6 +485,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => // class C extends D( { class E { ... } ... } ). Here, E is a class local to a constructor final def isClassLocalToConstructor = isClass && hasFlag(INCONSTRUCTOR) + final def isInlineClass = isClass && hasAnnotation(ScalaInlineClass) + final def isAnonymousClass = isClass && (name containsName tpnme.ANON_CLASS_NAME) final def isAnonymousFunction = isSynthetic && (name containsName tpnme.ANON_FUN_NAME) final def isAnonOrRefinementClass = isAnonymousClass || isRefinementClass @@ -824,7 +826,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def addModuleSuffix(n: Name): Name = if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n - + def moduleSuffix: String = ( if (needsModuleSuffix) nme.MODULE_SUFFIX_STRING else "" @@ -832,7 +834,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Whether this symbol needs nme.MODULE_SUFFIX_STRING (aka $) appended on the java platform. */ def needsModuleSuffix = ( - hasModuleFlag + hasModuleFlag && !isMethod && !isImplClass && !isJavaDefined @@ -859,7 +861,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (owner.isEffectiveRoot) name else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name ) - + def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) /** The encoded full path name of this symbol, where outer names and inner names @@ -1011,7 +1013,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Substitute second list of symbols for first in current info. */ def substInfo(syms0: List[Symbol], syms1: List[Symbol]) = modifyInfo(_.substSym(syms0, syms1)) def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info atOwner this) - + /** Set the info and enter this symbol into the owner's scope. */ def setInfoAndEnter(info: Type): this.type = { setInfo(info) @@ -1313,7 +1315,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def isNestedIn(that: Symbol): Boolean = owner == that || owner != NoSymbol && (owner isNestedIn that) - + /** Is this class symbol a subclass of that symbol, * and is this class symbol also different from Null or Nothing? */ def isNonBottomSubClass(that: Symbol): Boolean = false @@ -2081,7 +2083,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def referenced: Symbol = _referenced def referenced_=(x: Symbol) { _referenced = x } - + def existentialBound = singletonBounds(this.tpe) def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = @@ -2175,7 +2177,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (!isMethod && needsFlatClasses) { if (flatname eq null) flatname = nme.flattenedName(rawowner.name, rawname) - + flatname } else rawname.toTermName @@ -2211,7 +2213,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => res } } - + class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) { // Temporary programmatic help tracking down who might do such a thing @@ -2226,13 +2228,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AliasTypeSymbol = owner.newAliasTypeSymbol(name, pos, newFlags) } - + class AbstractTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) with AbstractTypeMixin { override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AbstractTypeSymbol = owner.newAbstractTypeSymbol(name, pos, newFlags) } - + /** Might be mixed into TypeSymbol or TypeSkolem. */ trait AbstractTypeMixin extends TypeSymbol { @@ -2430,8 +2432,8 @@ trait Symbols extends api.Symbols { self: SymbolTable => final override def isNonClassType = false final override def isAbstractType = false final override def isAliasType = false - - override def existentialBound = polyType(this.typeParams, TypeBounds.upper(this.classBound)) + + override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound)) override def sourceFile = if (owner.isPackageClass) source @@ -2458,19 +2460,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => } thisTypeCache } - + override def owner: Symbol = if (needsFlatClasses) rawowner.owner else rawowner override def name: TypeName = ( if (needsFlatClasses) { if (flatname eq null) flatname = nme.flattenedName(rawowner.name, rawname).toTypeName - + flatname } else rawname.toTypeName ) - + /** A symbol carrying the self type of the class as its type */ override def thisSym: Symbol = thissym @@ -2653,7 +2655,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => val syms1 = cloneSymbolsAtOwner(syms, owner) creator(syms1, tpe.substSym(syms, syms1)) } - + /** A deep map on a symbol's paramss. */ def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f) @@ -2661,7 +2663,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** An exception for cyclic references of symbol definitions */ case class CyclicReference(sym: Symbol, info: Type) extends TypeError("illegal cyclic reference involving " + sym) { - // printStackTrace() // debug + if (settings.debug.value) printStackTrace() } case class InvalidCompanions(sym1: Symbol, sym2: Symbol) extends Throwable( diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 5bb0c98bfb..2836eb81fd 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -121,12 +121,15 @@ trait Trees extends api.Trees { self: SymbolTable => new ChangeOwnerTraverser(oldOwner, newOwner) apply t } } - - def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = { - val list = pairs.toList - val subst = new TreeSymSubstituter(list map (_._1), list map (_._2)) - subst(tree) - } + + def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = + substTreeSyms(pairs.map(_._1).toList, pairs.map(_._2).toList) + + def substTreeSyms(from: List[Symbol], to: List[Symbol]): Tree = + new TreeSymSubstituter(from, to)(tree) + + def substTreeThis(clazz: Symbol, to: Tree): Tree = new ThisSubstituter(clazz, to) transform tree + def shallowDuplicate: Tree = new ShallowDuplicator(tree) transform tree def shortClass: String = tree.getClass.getName split "[.$]" last @@ -340,6 +343,13 @@ trait Trees extends api.Trees { self: SymbolTable => override def toString = substituterString("Symbol", "Tree", from, to) } + class ThisSubstituter(clazz: Symbol, to: => Tree) extends Transformer { + override def transform(tree: Tree) = tree match { + case This(_) if tree.symbol == clazz => to + case _ => super.transform(tree) + } + } + class TypeMapTreeSubstituter(val typeMap: TypeMap) extends Traverser { override def traverse(tree: Tree) { if (tree.tpe ne null) diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 35d26493f8..e6d4599417 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -110,13 +110,13 @@ trait Types extends api.Types { self: SymbolTable => * to undo constraints in the case of isSubType/isSameType failure. */ lazy val undoLog = newUndoLog - + protected def newUndoLog = new UndoLog - + class UndoLog { private type UndoPairs = List[(TypeVar, TypeConstraint)] private var log: UndoPairs = List() - + // register with the auto-clearing cache manager perRunCaches.recordCache(this) @@ -136,7 +136,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] def record(tv: TypeVar) = { log ::= ((tv, tv.constr.cloneInternal)) } - + private[scala] def clear() { if (settings.debug.value) self.log("Clearing " + log.size + " entries from the undoLog.") @@ -427,7 +427,7 @@ trait Types extends api.Types { self: SymbolTable => /** For a typeref, its arguments. The empty list for all other types */ def typeArgs: List[Type] = List() - + /** A list of placeholder types derived from the type parameters. * Used by RefinedType and TypeRef. */ @@ -524,7 +524,7 @@ trait Types extends api.Types { self: SymbolTable => * Alternatives of overloaded symbol appear in the order they are declared. */ def decl(name: Name): Symbol = findDecl(name, 0) - + /** A list of all non-private members defined or declared in this type. */ def nonPrivateDecls: List[Symbol] = decls filter (x => !x.isPrivate) toList @@ -565,7 +565,7 @@ trait Types extends api.Types { self: SymbolTable => */ def nonPrivateMember(name: Name): Symbol = memberBasedOnName(name, BridgeAndPrivateFlags) - + /** All members with the given flags, excluding bridges. */ def membersWithFlags(requiredFlags: Long): List[Symbol] = @@ -590,7 +590,7 @@ trait Types extends api.Types { self: SymbolTable => * an OverloadedSymbol if several exist, NoSymbol if none exist */ def nonLocalMember(name: Name): Symbol = memberBasedOnName(name, BridgeFlags | LOCAL) - + /** Members excluding and requiring the given flags. * Note: unfortunately it doesn't work to exclude DEFERRED this way. */ @@ -1236,7 +1236,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] var underlyingPeriod = NoPeriod override def underlying: Type = { val cache = underlyingCache - if (underlyingPeriod == currentPeriod && cache != null) cache + if (underlyingPeriod == currentPeriod && cache != null) cache else { defineUnderlyingOfSingleType(this) underlyingCache @@ -1279,7 +1279,7 @@ trait Types extends api.Types { self: SymbolTable => unique(new UniqueSingleType(pre, sym)) } } - + protected def defineUnderlyingOfSingleType(tpe: SingleType) = { val period = tpe.underlyingPeriod if (period != currentPeriod) { @@ -1349,13 +1349,13 @@ trait Types extends api.Types { self: SymbolTable => override def baseTypeSeq: BaseTypeSeq = { val cached = baseTypeSeqCache - if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq) + if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq) cached else { defineBaseTypeSeqOfCompoundType(this) if (baseTypeSeqCache eq undetBaseTypeSeq) throw new RecoverableCyclicReference(typeSymbol) - + baseTypeSeqCache } } @@ -1369,7 +1369,7 @@ trait Types extends api.Types { self: SymbolTable => defineBaseClassesOfCompoundType(this) if (baseClassesCache eq null) throw new RecoverableCyclicReference(typeSymbol) - + baseClassesCache } } @@ -1415,9 +1415,9 @@ trait Types extends api.Types { self: SymbolTable => (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) decls.mkString("{", "; ", "}") else "") } - + protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = { - val period = tpe.baseTypeSeqPeriod; + val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { tpe.baseTypeSeqPeriod = currentPeriod if (!isValidForBaseClasses(period)) { @@ -1468,7 +1468,7 @@ trait Types extends api.Types { self: SymbolTable => if (tpe.baseTypeSeqCache eq undetBaseTypeSeq) throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol) } - + protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = { def computeBaseClasses: List[Symbol] = if (tpe.parents.isEmpty) List(tpe.typeSymbol) @@ -1787,13 +1787,13 @@ trait Types extends api.Types { self: SymbolTable => } } - /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected + /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected * with synchronized, because they are accessed only from isVolatile, which is called only from * Typer. */ private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] - + class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType { require(args0.nonEmpty, this) @@ -1811,7 +1811,7 @@ trait Types extends api.Types { self: SymbolTable => asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) } - + // note: does not go through typeRef. There's no need to because // neither `pre` nor `sym` changes. And there's a performance // advantage to call TypeRef directly. @@ -1826,7 +1826,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = typeParams.nonEmpty override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) - + override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = if (isHigherKinded) { if (sameLength(formals intersect typeParams, typeParams)) @@ -1846,9 +1846,9 @@ trait Types extends api.Types { self: SymbolTable => res } - override def transformInfo(tp: Type): Type = + override def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), dummyArgs) - + override def narrow = if (sym.isModuleClass) singleType(pre, sym.sourceModule) else super.narrow @@ -1856,14 +1856,14 @@ trait Types extends api.Types { self: SymbolTable => override def typeConstructor = this // eta-expand, subtyping relies on eta-expansion of higher-kinded types - override protected def normalizeImpl: Type = + override protected def normalizeImpl: Type = if (isHigherKinded) etaExpand else super.normalizeImpl } - + trait ClassTypeRef extends TypeRef { // !!! There are scaladoc-created symbols arriving which violate this require. // require(sym.isClass, sym) - + override protected def normalizeImpl: Type = if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers else super.normalizeImpl @@ -1872,7 +1872,7 @@ trait Types extends api.Types { self: SymbolTable => if (sym == clazz) this else transform(sym.info.baseType(clazz)) } - + trait NonClassTypeRef extends TypeRef { require(sym.isNonClassType, sym) @@ -1891,11 +1891,11 @@ trait Types extends api.Types { self: SymbolTable => } relativeInfoCache } - + override def baseType(clazz: Symbol): Type = if (sym == clazz) this else baseTypeOfNonClassTypeRef(this, clazz) } - + protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = try { basetypeRecursions += 1 if (basetypeRecursions < LogPendingBaseTypesThreshold) @@ -1912,7 +1912,7 @@ trait Types extends api.Types { self: SymbolTable => } finally { basetypeRecursions -= 1 } - + trait AliasTypeRef extends NonClassTypeRef { require(sym.isAliasType, sym) @@ -1930,7 +1930,7 @@ trait Types extends api.Types { self: SymbolTable => if (typeParamsMatchArgs) betaReduce.normalize else if (isHigherKinded) super.normalizeImpl else ErrorType - + // isHKSubType0 introduces synthetic type params so that // betaReduce can first apply sym.info to typeArgs before calling // asSeenFrom. asSeenFrom then skips synthetic type params, which @@ -1940,7 +1940,7 @@ trait Types extends api.Types { self: SymbolTable => // this crashes pos/depmet_implicit_tpbetareduce.scala // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) def betaReduce = transform(sym.info.resultType) - + // #3731: return sym1 for which holds: pre bound sym.name to sym and // pre1 now binds sym.name to sym1, conceptually exactly the same // symbol as sym. The selection of sym on pre must be updated to the @@ -1954,12 +1954,12 @@ trait Types extends api.Types { self: SymbolTable => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? case _ => sym } - + } trait AbstractTypeRef extends NonClassTypeRef { require(sym.isAbstractType, sym) - + /** Syncnote: Pure performance caches; no need to synchronize in multi-threaded environment */ private var symInfoCache: Type = _ @@ -1988,7 +1988,7 @@ trait Types extends api.Types { self: SymbolTable => volatileRecursions -= 1 } } - + override def thisInfo = { val symInfo = sym.info if (thisInfoCache == null || (symInfo ne symInfoCache)) { @@ -2021,7 +2021,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] var parentsPeriod = NoPeriod private[reflect] var baseTypeSeqCache: BaseTypeSeq = _ private[reflect] var baseTypeSeqPeriod = NoPeriod - private var normalized: Type = _ + private var normalized: Type = _ // @M: propagate actual type params (args) to `tp`, by replacing // formal type parameters with actual ones. If tp is higher kinded, @@ -2043,7 +2043,7 @@ trait Types extends api.Types { self: SymbolTable => normalized } } - + def etaExpand: Type = { // must initialise symbol, see test/files/pos/ticket0137.scala val tpars = initializedTypeParams @@ -2097,12 +2097,12 @@ trait Types extends api.Types { self: SymbolTable => } thisInfo.decls } - + protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val cache = baseTypeSeqCache - if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq) + if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq) cache else { defineBaseTypeSeqOfTypeRef(this) @@ -2196,7 +2196,7 @@ trait Types extends api.Types { self: SymbolTable => } }) } - + protected def defineParentsOfTypeRef(tpe: TypeRef) = { val period = tpe.parentsPeriod if (period != currentPeriod) { @@ -2208,7 +2208,7 @@ trait Types extends api.Types { self: SymbolTable => } } } - + protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = { val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { @@ -2368,7 +2368,7 @@ trait Types extends api.Types { self: SymbolTable => } object PolyType extends PolyTypeExtractor - + /** A creator for existential types which flattens nested existentials. */ def newExistentialType(quantified: List[Symbol], underlying: Type): Type = @@ -2571,7 +2571,7 @@ trait Types extends api.Types { self: SymbolTable => else if (args.isEmpty) new HKTypeVar(origin, constr, params) else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params))) ) - + trace("create", "In " + tv.originLocation)(tv) } } @@ -2612,7 +2612,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = true override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) } - + /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) */ class AppliedTypeVar( @@ -2620,17 +2620,17 @@ trait Types extends api.Types { self: SymbolTable => _constr: TypeConstraint, zippedArgs: List[(Symbol, Type)] ) extends TypeVar(_origin, _constr) { - + require(zippedArgs.nonEmpty, this) override def params: List[Symbol] = zippedArgs map (_._1) override def typeArgs: List[Type] = zippedArgs map (_._2) - + override protected def typeVarString = ( zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") ) } - + /** A class representing a type variable: not used after phase `typer`. * * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types). @@ -2648,7 +2648,7 @@ trait Types extends api.Types { self: SymbolTable => override def typeArgs: List[Type] = Nil override def isHigherKinded = false - /** The constraint associated with the variable + /** The constraint associated with the variable * Syncnote: Type variables are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of `constr` @@ -2659,7 +2659,7 @@ trait Types extends api.Types { self: SymbolTable => /** The variable's skolemization level */ val level = skolemizationLevel - + /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. * @@ -2690,7 +2690,7 @@ trait Types extends api.Types { self: SymbolTable => // inference may generate several TypeVar's for a single type parameter that must be inferred, // only one of them is in the set of tvars that need to be solved, but // they share the same TypeConstraint instance - + // When comparing to types containing skolems, remember the highest level // of skolemization. If that highest level is higher than our initial // skolemizationLevel, we can't re-use those skolems as the solution of this @@ -2914,7 +2914,7 @@ trait Types extends api.Types { self: SymbolTable => def originLocation = { val sym = origin.typeSymbolDirect val encl = sym.owner.logicallyEnclosingMember - + // This should display somewhere between one and three // things which enclose the origin: at most, a class, a // a method, and a term. At least, a class. @@ -3247,7 +3247,7 @@ trait Types extends api.Types { self: SymbolTable => case _ => abort(debugString(tycon)) } - /** A creator for type parameterizations that strips empty type parameter lists. + /** A creator and extractor for type parameterizations that strips empty type parameter lists. * Use this factory method to indicate the type has kind * (it's a polymorphic value) * until we start tracking explicit kinds equivalent to typeFun (except that the latter requires tparams nonEmpty). * @@ -3256,9 +3256,18 @@ trait Types extends api.Types { self: SymbolTable => * can we instead say this is the canonical creator for polyTypes which * may or may not be poly? (It filched the standard "canonical creator" name.) */ - def polyType(tparams: List[Symbol], tpe: Type): Type = - if (tparams nonEmpty) typeFun(tparams, tpe) - else tpe // it's okay to be forgiving here + object GenPolyType { + def apply(tparams: List[Symbol], tpe: Type): Type = + if (tparams nonEmpty) typeFun(tparams, tpe) + else tpe // it's okay to be forgiving here + def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match { + case PolyType(tparams, restpe) => Some(tparams, restpe) + case _ => Some(List(), tpe) + } + } + + @deprecated("use GenPolyType(...) instead") + def polyType(params: List[Symbol], tpe: Type): Type = GenPolyType(params, tpe) /** A creator for anonymous type functions, where the symbol for the type function still needs to be created. * @@ -3342,7 +3351,7 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } - + /** Type with all top-level occurrences of abstract types replaced by their bounds */ def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) case TypeRef(_, sym, _) if sym.isAbstractType => @@ -3452,7 +3461,7 @@ trait Types extends api.Types { self: SymbolTable => def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType) def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi)) def this() = this(List(), List()) - + /* Syncnote: Type constraints are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of any @@ -3552,7 +3561,7 @@ trait Types extends api.Types { self: SymbolTable => override def variance = _variance def variance_=(x: Int) = _variance = x - + override protected def noChangeToSymbols(origSyms: List[Symbol]) = { origSyms forall { sym => val v = variance @@ -3718,7 +3727,7 @@ trait Types extends api.Types { self: SymbolTable => protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = args mapConserve this - + /** Called by mapOver to determine whether the original symbols can * be returned, or whether they must be cloned. Overridden in VariantTypeMap. */ @@ -3732,7 +3741,7 @@ trait Types extends api.Types { self: SymbolTable => if (elems1 eq elems) scope else newScopeWith(elems1: _*) } - + /** Map this function over given list of symbols */ def mapOver(origSyms: List[Symbol]): List[Symbol] = { // fast path in case nothing changes due to map @@ -3795,7 +3804,7 @@ trait Types extends api.Types { self: SymbolTable => def traverse(tp: Type): Unit def apply(tp: Type): Type = { traverse(tp); tp } } - + abstract class TypeTraverserWithResult[T] extends TypeTraverser { def result: T def clear(): Unit @@ -3815,13 +3824,13 @@ trait Types extends api.Types { self: SymbolTable => */ // class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) with VariantTypeMap { // variance = v - // + // // def traverse(tp: Type) = tp match { // case ExistentialType(_, _) if (variance == v) => result = true // case _ => mapOver(tp) // } // } - // + // // val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) @@ -3875,7 +3884,7 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } - + /** Used by existentialAbstraction. */ class ExistentialExtrapolation(tparams: List[Symbol]) extends VariantTypeMap { @@ -3893,10 +3902,10 @@ trait Types extends api.Types { self: SymbolTable => countOccs(tpe) for (tparam <- tparams) countOccs(tparam.info) - + apply(tpe) } - + def apply(tp: Type): Type = { val tp1 = mapOver(tp) if (variance == 0) tp1 @@ -4475,12 +4484,12 @@ trait Types extends api.Types { self: SymbolTable => result } } - + protected def commonOwnerMap: CommonOwnerMap = commonOwnerMapObj - + protected class CommonOwnerMap extends TypeTraverserWithResult[Symbol] { var result: Symbol = _ - + def clear() { result = null } private def register(sym: Symbol) { @@ -4498,7 +4507,7 @@ trait Types extends api.Types { self: SymbolTable => case _ => mapOver(tp) } } - + private lazy val commonOwnerMapObj = new CommonOwnerMap class MissingAliasControl extends ControlThrowable @@ -4506,7 +4515,7 @@ trait Types extends api.Types { self: SymbolTable => class MissingTypeControl extends ControlThrowable object adaptToNewRunMap extends TypeMap { - + private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = { if (phase.flatClasses) { sym @@ -4673,7 +4682,7 @@ trait Types extends api.Types { self: SymbolTable => case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2) pre1 =:= pre2 && - forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => + forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG if (tparam.variance == 0) arg1 =:= arg2 else if (arg1.isInstanceOf[TypeVar]) @@ -5683,8 +5692,8 @@ trait Types extends api.Types { self: SymbolTable => val formatted = tableDef.table(transposed) println("** Depth is " + depth + "\n" + formatted) } - - /** From a list of types, find any which take type parameters + + /** From a list of types, find any which take type parameters * where the type parameter bounds contain references to other * any types in the list (including itself.) * @@ -6203,13 +6212,13 @@ trait Types extends api.Types { self: SymbolTable => if (ts exists (_.isNotNull)) res.notNull else res } - + /** A list of the typevars in a type. */ def typeVarsInType(tp: Type): List[TypeVar] = { var tvs: List[TypeVar] = Nil tp foreach { case t: TypeVar => tvs ::= t - case _ => + case _ => } tvs.reverse } @@ -6221,7 +6230,7 @@ trait Types extends api.Types { self: SymbolTable => // !!! Is it somehow guaranteed that this will not break under nesting? // In general one has to save and restore the contents of the field... tvs foreach (_.suspended = true) - tvs + tvs } /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list @@ -6379,7 +6388,9 @@ trait Types extends api.Types { self: SymbolTable => // but that would be a big change. Left for further refactoring. /** An exception for cyclic references from which we can recover */ case class RecoverableCyclicReference(sym: Symbol) - extends TypeError("illegal cyclic reference involving " + sym) + extends TypeError("illegal cyclic reference involving " + sym) { + if (settings.debug.value) printStackTrace() + } class NoCommonType(tps: List[Type]) extends Throwable( "lub/glb of incompatible types: " + tps.mkString("", " and ", "")) with ControlThrowable @@ -6449,5 +6460,5 @@ trait Types extends api.Types { self: SymbolTable => } finally { tostringRecursions -= 1 } - + } diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index b4bcc52a23..3b805804a0 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -186,7 +186,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => } finally { parentsLevel -= 1 } - clazz setInfo polyType(tparams, new ClassInfoType(parents, newScope, clazz)) + clazz setInfo GenPolyType(tparams, new ClassInfoType(parents, newScope, clazz)) if (module != NoSymbol) { module.moduleClass setInfo new ClassInfoType(List(), newScope, module.moduleClass) } @@ -354,7 +354,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => def classToScala(jclazz: jClass[_]): Symbol = classCache.toScala(jclazz) { val jname = javaTypeName(jclazz) def lookup = sOwner(jclazz).info.decl(newTypeName(jclazz.getSimpleName)) - + if (jclazz.isMemberClass && !nme.isImplClassName(jname)) { val sym = lookup assert(sym.isType, sym+"/"+jclazz+"/"+sOwner(jclazz)+"/"+jclazz.getSimpleName) @@ -478,7 +478,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => } private def setMethType(meth: Symbol, tparams: List[Symbol], paramtpes: List[Type], restpe: Type) = { - meth setInfo polyType(tparams, MethodType(meth.owner.newSyntheticValueParams(paramtpes map objToAny), restpe)) + meth setInfo GenPolyType(tparams, MethodType(meth.owner.newSyntheticValueParams(paramtpes map objToAny), restpe)) } /** @@ -516,7 +516,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => val tparams = jconstr.getTypeParameters.toList map createTypeParameter val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala setMethType(constr, tparams, paramtpes, clazz.tpe) - constr setInfo polyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) + constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe)) copyAnnotations(constr, jconstr) constr } diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 426700f3b2..301e986167 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -152,7 +152,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Register top level class (called on entering the class) */ def registerTopLevelSym(sym: Symbol) {} - + // ------------------ Reporting ------------------------------------- // not deprecated yet, but a method called "error" imported into @@ -416,66 +416,72 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb val global: Global.this.type = Global.this } with Analyzer + object classInlining extends { + val global: Global.this.type = Global.this + val runsAfter = List("typer") + val runsRightAfter = None + } with ClassInlining + // phaseName = "superaccessors" object superAccessors extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("typer") + val runsAfter = List("typer") val runsRightAfter = None } with SuperAccessors // phaseName = "pickler" object pickler extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("superaccessors") + val runsAfter = List("superaccessors") val runsRightAfter = None } with Pickler // phaseName = "refchecks" override object refChecks extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("pickler") + val runsAfter = List("pickler") val runsRightAfter = None } with RefChecks // phaseName = "liftcode" object liftcode extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("refchecks") + val runsAfter = List("refchecks") val runsRightAfter = None } with LiftCode // phaseName = "uncurry" override object uncurry extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("refchecks", "liftcode") + val runsAfter = List("refchecks", "liftcode") val runsRightAfter = None } with UnCurry // phaseName = "tailcalls" object tailCalls extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("uncurry") + val runsAfter = List("uncurry") val runsRightAfter = None } with TailCalls // phaseName = "explicitouter" object explicitOuter extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("tailcalls") + val runsAfter = List("tailcalls") val runsRightAfter = None } with ExplicitOuter // phaseName = "specialize" object specializeTypes extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("") + val runsAfter = List("") val runsRightAfter = Some("tailcalls") } with SpecializeTypes // phaseName = "erasure" override object erasure extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("explicitouter") + val runsAfter = List("explicitouter") val runsRightAfter = Some("explicitouter") } with Erasure @@ -483,84 +489,84 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb object lazyVals extends { final val FLAGS_PER_WORD = 32 val global: Global.this.type = Global.this - val runsAfter = List[String]("erasure") + val runsAfter = List("erasure") val runsRightAfter = None } with LazyVals // phaseName = "lambdalift" object lambdaLift extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("lazyvals") + val runsAfter = List("lazyvals") val runsRightAfter = None } with LambdaLift // phaseName = "constructors" object constructors extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("lambdalift") + val runsAfter = List("lambdalift") val runsRightAfter = None } with Constructors // phaseName = "flatten" object flatten extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("constructors") + val runsAfter = List("constructors") val runsRightAfter = None } with Flatten // phaseName = "mixin" object mixer extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("flatten", "constructors") + val runsAfter = List("flatten", "constructors") val runsRightAfter = None } with Mixin // phaseName = "cleanup" object cleanup extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("mixin") + val runsAfter = List("mixin") val runsRightAfter = None } with CleanUp // phaseName = "icode" object genicode extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("cleanup") + val runsAfter = List("cleanup") val runsRightAfter = None } with GenICode // phaseName = "inliner" object inliner extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("icode") + val runsAfter = List("icode") val runsRightAfter = None } with Inliners // phaseName = "inlineExceptionHandlers" object inlineExceptionHandlers extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("inliner") + val runsAfter = List("inliner") val runsRightAfter = None } with InlineExceptionHandlers // phaseName = "closelim" object closureElimination extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("inlineExceptionHandlers") + val runsAfter = List("inlineExceptionHandlers") val runsRightAfter = None } with ClosureElimination // phaseName = "dce" object deadCode extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("closelim") + val runsAfter = List("closelim") val runsRightAfter = None } with DeadCodeElimination // phaseName = "jvm" object genJVM extends { val global: Global.this.type = Global.this - val runsAfter = List[String]("dce") + val runsAfter = List("dce") val runsRightAfter = None } with GenJVM @@ -576,7 +582,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb object terminal extends { val global: Global.this.type = Global.this val phaseName = "terminal" - val runsAfter = List[String]("jvm", "msil") + val runsAfter = List("jvm", "msil") val runsRightAfter = None } with SubComponent { private var cache: Option[GlobalPhase] = None @@ -630,6 +636,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb analyzer.packageObjects -> "load package objects", analyzer.typerFactory -> "the meat and potatoes: type the trees", superAccessors -> "add super accessors in traits and nested classes", + classInlining -> "add static methods to inline classes", pickler -> "serialize symbol tables", refChecks -> "reference/override checking, translate nested objects", liftcode -> "reify trees", @@ -682,18 +689,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb private lazy val unitTimings = mutable.HashMap[CompilationUnit, Long]() withDefaultValue 0L // tracking time spent per unit private def unitTimingsFormatted(): String = { def toMillis(nanos: Long) = "%.3f" format nanos / 1000000d - + val formatter = new util.TableDef[(String, String)] { >> ("ms" -> (_._1)) >+ " " << ("path" -> (_._2)) } "" + ( - new formatter.Table(unitTimings.toList sortBy (-_._2) map { + new formatter.Table(unitTimings.toList sortBy (-_._2) map { case (unit, nanos) => (toMillis(nanos), unit.source.path) }) ) } - + protected def addToPhasesSet(sub: SubComponent, descr: String) { phasesSet += sub phasesDescMap(sub) = descr @@ -901,7 +908,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Counts for certain classes of warnings during this run. */ var deprecationWarnings: List[(Position, String)] = Nil var uncheckedWarnings: List[(Position, String)] = Nil - + /** A flag whether macro expansions failed */ var macroExpansionFailed = false diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index b16b3c89a0..662e03d155 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -6,6 +6,7 @@ package scala.tools.nsc package ast +import reflect.internal.HasFlags import reflect.internal.Flags._ import symtab._ @@ -41,4 +42,7 @@ abstract class TreeInfo extends reflect.internal.TreeInfo { case ClassDef(_, `name`, _, _) :: Nil => true case _ => super.firstDefinesClassOrObject(trees, name) } + + def isInterface(mods: HasFlags, body: List[Tree]) = + mods.hasTraitFlag && (body forall isInterfaceMember) } diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 811bb6ee05..2db1875673 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -368,7 +368,7 @@ abstract class ClassfileParser { case arr: Type => Constant(arr) } } - + private def getSubArray(bytes: Array[Byte]): Array[Byte] = { val decodedLength = ByteCodecs.decode(bytes) val arr = new Array[Byte](decodedLength) @@ -719,7 +719,7 @@ abstract class ClassfileParser { index += 1 val bounds = variance match { case '+' => TypeBounds.upper(objToAny(sig2type(tparams, skiptvs))) - case '-' => + case '-' => val tp = sig2type(tparams, skiptvs) // sig2type seems to return AnyClass regardless of the situation: // we don't want Any as a LOWER bound. @@ -841,7 +841,7 @@ abstract class ClassfileParser { } ClassInfoType(parents.toList, instanceDefs, sym) } - polyType(ownTypeParams, tpe) + GenPolyType(ownTypeParams, tpe) } // sigToType class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index e11a5a4ad9..736d1c78a3 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -224,14 +224,14 @@ abstract class TypeParser { if (canBeTakenAddressOf) { clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else polyType(ownTypeParams, classInfoAsInMetadata) ) + else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) clazzBoxed.setFlag(flags) val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType - else polyType(ownTypeParams, rawValueInfoType) ) + else GenPolyType(ownTypeParams, rawValueInfoType) ) } else { clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else polyType(ownTypeParams, classInfoAsInMetadata) ) + else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) } // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params @@ -480,7 +480,7 @@ abstract class TypeParser { val mtype = methodType(method, rettype); if (mtype == null) return; /* START CLR generics (snippet 4) */ - val mInfo = if (method.IsGeneric) polyType(newMethodTParams, mtype(methodSym)) + val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) else mtype(methodSym) /* END CLR generics (snippet 4) */ /* START CLR non-generics (snippet 4) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index b342b95742..2ebaf25b83 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -931,6 +931,10 @@ abstract class Erasure extends AddInterfaces tree case Apply(fn, args) => + def qualifier = fn match { + case Select(qual, _) => qual + case TypeApply(Select(qual, _), _) => qual + } if (fn.symbol == Any_asInstanceOf) (fn: @unchecked) match { case TypeApply(Select(qual, _), List(targ)) => @@ -980,19 +984,12 @@ abstract class Erasure extends AddInterfaces } case _ => tree } - } - else { - def doDynamic(fn: Tree, qual: Tree): Tree = { - if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) - ApplyDynamic(qual, args) setSymbol fn.symbol setPos tree.pos - else tree - } - fn match { - case Select(qual, _) => doDynamic(fn, qual) - case TypeApply(fni@Select(qual, _), _) => doDynamic(fni, qual)// type parameters are irrelevant in case of dynamic call - case _ => - tree - } + } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { + ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos + } else if (false && fn.symbol.owner.isInlineClass && !fn.symbol.isParamAccessor) { + Apply(gen.mkAttributedRef(classInlining.staticMethod(fn.symbol)), qualifier :: args) + } else { + tree } case Select(qual, name) => diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala index c5475fa0f2..26568b4edc 100644 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ b/src/compiler/scala/tools/nsc/transform/LiftCode.scala @@ -1,6 +1,7 @@ /* NSC -- new Scala compiler * Copyright 2005-2011 LAMP/EPFL * @author Gilles Dubochet + * @author Martin Odersky */ package scala.tools.nsc diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 4a104857db..422b1b7b7d 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -74,7 +74,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { AnyRefClass, ObjectClass, Predef_AnyRef, uncheckedVarianceClass } - + /** TODO - this is a lot of maps. */ @@ -494,7 +494,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long) = member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED)) - + sClass.sourceFile = clazz.sourceFile currentRun.symSource(sClass) = clazz.sourceFile // needed later on by mixin @@ -556,7 +556,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { " => " + sClass.defStringSeenAs(sClass.typeOfThis) ) } - polyType(newClassTParams, ClassInfoType(parents ::: extraSpecializedMixins, decls1, sClass)) + GenPolyType(newClassTParams, ClassInfoType(parents ::: extraSpecializedMixins, decls1, sClass)) } atPhase(phase.next)(sClass setInfo specializedInfoType) @@ -787,7 +787,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { // the cloneInfo is necessary so that method parameter symbols are cloned at the new owner val methodType = sym.info.resultType.instantiateTypeParams(keys ++ tps, vals ++ tps1.map(_.tpe)).cloneInfo(specMember) - specMember setInfo polyType(tps1, methodType) + specMember setInfo GenPolyType(tps1, methodType) debuglog("expanded member: " + sym + ": " + sym.info + " -> " + specMember + @@ -1091,7 +1091,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { ) val newScope = newScopeWith(specializeClass(clazz, typeEnv(clazz)) ++ specialOverrides(clazz): _*) // If tparams.isEmpty, this is just the ClassInfoType. - polyType(tparams, ClassInfoType(parents1, newScope, clazz)) + GenPolyType(tparams, ClassInfoType(parents1, newScope, clazz)) case _ => tpe } @@ -1197,7 +1197,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else NoSymbol def illegalSpecializedInheritance(clazz: Symbol): Boolean = ( - hasSpecializedFlag(clazz) + hasSpecializedFlag(clazz) && originalClass(clazz).parentSymbols.exists(p => hasSpecializedParams(p) && !p.isTrait) ) @@ -1261,7 +1261,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val specMember = specCandidates suchThat { s => doesConform(symbol, tree.tpe, qual.tpe.memberType(s), env) } - + log("[specSym] found: " + specCandidates.tpe + ", instantiated as: " + tree.tpe) log("[specSym] found specMember: " + specMember) if (specMember ne NoSymbol) @@ -1378,7 +1378,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { (new CollectMethodBodies)(tree) val parents1 = map2(currentOwner.info.parents, parents)((tpe, parent) => TypeTree(tpe) setPos parent.pos) - + treeCopy.Template(tree, parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ , self, diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 177da9fcf9..4529cc5f07 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -31,14 +31,14 @@ trait ContextErrors { case class NormalTypeError(underlyingTree: Tree, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError { - + def errPos:Position = underlyingTree.pos override def toString() = "[Type error at:" + underlyingTree.pos + "] " + errMsg } case class SymbolTypeError(underlyingSym: Symbol, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError { - + def errPos = underlyingSym.pos } @@ -76,7 +76,7 @@ trait ContextErrors { } def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) } - + def typeErrorMsg(found: Type, req: Type, possiblyMissingArgs: Boolean) = { def missingArgsMsg = if (possiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else "" "type mismatch" + foundReqMsg(found, req) + missingArgsMsg @@ -143,12 +143,12 @@ trait ContextErrors { found } assert(!found.isErroneous && !req.isErroneous) - + issueNormalTypeError(tree, withAddendum(tree.pos)(typeErrorMsg(found, req, infer.isPossiblyMissingArgs(found, req))) ) if (settings.explaintypes.value) explainTypes(found, req) } - + def WithFilterError(tree: Tree, ex: AbsTypeError) = { issueTypeError(ex) setError(tree) @@ -175,13 +175,13 @@ trait ContextErrors { val calcSimilar = ( name.length > 2 && ( startingIdentCx.reportErrors - || startingIdentCx.enclClassOrMethod.reportErrors + || startingIdentCx.enclClassOrMethod.reportErrors ) ) - // avoid calculating if we're in "silent" mode. - // name length check to limit unhelpful suggestions for e.g. "x" and "b1" + // avoid calculating if we're in "silent" mode. + // name length check to limit unhelpful suggestions for e.g. "x" and "b1" val similar = { - if (!calcSimilar) "" + if (!calcSimilar) "" else { val allowed = ( startingIdentCx.enclosingContextChain @@ -632,8 +632,8 @@ trait ContextErrors { def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) - - def MacroExpandError(tree: Tree, t: Any) = { + + def MacroExpandError(tree: Tree, t: Any) = { issueNormalTypeError(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass) setError(tree) } @@ -663,7 +663,7 @@ trait ContextErrors { type ErrorType = Value val WrongNumber, NoParams, ArgsDoNotConform = Value } - + private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) = if (sym1.hasDefaultFlag && sym2.hasDefaultFlag && sym1.enclClass == sym2.enclClass) { val methodName = nme.defaultGetterToMethod(sym1.name) @@ -761,7 +761,7 @@ trait ContextErrors { def PolymorphicExpressionInstantiationError(tree: Tree, undetparams: List[Symbol], pt: Type) = issueNormalTypeError(tree, "polymorphic expression cannot be instantiated to expected type" + - foundReqMsg(polyType(undetparams, skipImplicit(tree.tpe)), pt)) + foundReqMsg(GenPolyType(undetparams, skipImplicit(tree.tpe)), pt)) //checkCheckable def TypePatternOrIsInstanceTestError(tree: Tree, tp: Type) = @@ -826,14 +826,14 @@ trait ContextErrors { object NamerErrorGen { implicit val context0 = context - + object SymValidateErrors extends Enumeration { val ImplicitConstr, ImplicitNotTerm, ImplicitTopObject, OverrideClass, SealedNonClass, AbstractNonClass, OverrideConstr, AbstractOverride, LazyAndEarlyInit, ByNameParameter, AbstractVar = Value } - + object DuplicatesErrorKinds extends Enumeration { val RenamedTwice, AppearsTwice = Value } @@ -841,7 +841,7 @@ trait ContextErrors { import SymValidateErrors._ import DuplicatesErrorKinds._ import symtab.Flags - + def TypeSigError(tree: Tree, ex: TypeError) = { ex match { case CyclicReference(sym, info: TypeCompleter) => @@ -850,7 +850,7 @@ trait ContextErrors { context0.issue(TypeErrorWithUnderlyingTree(tree, ex)) } } - + def GetterDefinedTwiceError(getter: Symbol) = issueSymbolTypeError(getter, getter+" is defined twice") @@ -893,37 +893,37 @@ trait ContextErrors { val msg = errKind match { case ImplicitConstr => "`implicit' modifier not allowed for constructors" - + case ImplicitNotTerm => "`implicit' modifier can be used only for values, variables and methods" - + case ImplicitTopObject => "`implicit' modifier cannot be used for top-level objects" - + case OverrideClass => "`override' modifier not allowed for classes" - + case SealedNonClass => "`sealed' modifier can be used only for classes" - + case AbstractNonClass => "`abstract' modifier can be used only for classes; it should be omitted for abstract members" - + case OverrideConstr => "`override' modifier not allowed for constructors" - + case AbstractOverride => "`abstract override' modifier only allowed for members of traits" - + case LazyAndEarlyInit => "`lazy' definitions may not be initialized early" - + case ByNameParameter => "pass-by-name arguments not allowed for case class parameters" - + case AbstractVar => "only classes can have declared but undefined members" + abstractVarMessage(sym) - + } issueSymbolTypeError(sym, msg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 0cc7478c59..7cd71c7827 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -113,7 +113,7 @@ trait Namers extends MethodSynthesis { private def contextFile = context.unit.source.file private def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = { case ex: TypeError => - // H@ need to ensure that we handle only cyclic references + // H@ need to ensure that we handle only cyclic references TypeSigError(tree, ex) alt } @@ -296,7 +296,7 @@ trait Namers extends MethodSynthesis { val pos = tree.pos val isParameter = tree.mods.isParameter val flags = tree.mods.flags & mask - + tree match { case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(name.toTypeName, pos, flags) case TypeDef(_, _, _, _) => owner.newTypeSymbol(name.toTypeName, pos, flags) @@ -834,14 +834,13 @@ trait Namers extends MethodSynthesis { if (inheritsSelf || tp.isError) AnyRefClass.tpe else tp } - - var parents = typer.parentTypes(templ) map checkParent - if (clazz.hasAnnotation(ScalaInlineClass)) { - if (!(parents exists (_.typeSymbol == NotNullClass))) - parents = parents :+ NotNullClass.tpe - clazz setFlag FINAL - } - + + val parents = typer.parentTypes(templ) map checkParent + +// not yet: +// if (!treeInfo.isInterface(clazz, templ.body) && clazz != ArrayClass) +// ensureParent(ScalaObjectClass) + enterSelf(templ.self) val decls = newScope @@ -892,7 +891,7 @@ trait Namers extends MethodSynthesis { val tparams0 = typer.reenterTypeParams(tparams) val resultType = templateSig(impl) - polyType(tparams0, resultType) + GenPolyType(tparams0, resultType) } private def methodSig(ddef: DefDef, mods: Modifiers, tparams: List[TypeDef], @@ -935,7 +934,7 @@ trait Namers extends MethodSynthesis { // DEPMETTODO: check not needed when they become on by default checkDependencies(restpe) - polyType( + GenPolyType( tparamSyms, // deSkolemized symbols -- TODO: check that their infos don't refer to method args? if (vparamSymss.isEmpty) NullaryMethodType(restpe) // vparamss refer (if they do) to skolemized tparams @@ -1189,7 +1188,7 @@ trait Namers extends MethodSynthesis { // However, separate compilation requires the symbol info to be // loaded to do this check, but loading the info will probably // lead to spurious cyclic errors. So omit the check. - polyType(tparamSyms, tp) + GenPolyType(tparamSyms, tp) } /** Given a case class @@ -1253,8 +1252,12 @@ trait Namers extends MethodSynthesis { if (sym.isModule) annotate(sym.moduleClass) def getSig = tree match { - case ClassDef(_, _, tparams, impl) => - createNamer(tree).classSig(tparams, impl) + case cdef @ ClassDef(_, _, tparams, impl) => + val clazz = tree.symbol + val result = createNamer(tree).classSig(tparams, impl) + clazz setInfo result + if (clazz.isInlineClass) ensureCompanionObject(cdef) + result case ModuleDef(_, _, impl) => val clazz = sym.moduleClass @@ -1387,6 +1390,28 @@ trait Namers extends MethodSynthesis { if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass) fail(ByNameParameter) + def includeParent(tpe: Type, parent: Symbol): Type = tpe match { + case PolyType(tparams, restpe) => + PolyType(tparams, includeParent(restpe, parent)) + case ClassInfoType(parents, decls, clazz) => + if (parents exists (_.typeSymbol == parent)) tpe + else ClassInfoType(parents :+ parent.tpe, decls, clazz) + case _ => + tpe + } + + def ensureParent(parent: Symbol) = { + val info0 = sym.info + val info1 = includeParent(info0, parent) + if (info0 ne info1) sym setInfo info1 + } + + if (sym.isClass && sym.hasAnnotation(ScalaInlineClass)) { + ensureParent(NotNullClass) + sym setFlag FINAL + } + + if (sym.isDeferred) { // Is this symbol type always allowed the deferred flag? def symbolAllowsDeferred = ( diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 889c04a59b..c242326adc 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -154,7 +154,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ErrorType => fun } - + def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = inferView(tree, from, to, reportAmbiguous, true) @@ -274,7 +274,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } tp match { case TypeRef(pre, sym, args) => - checkNotLocked(sym) && + checkNotLocked(sym) && ((!sym.isNonClassType) || checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym)) // @M! info for a type ref to a type parameter now returns a polytype // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym) @@ -939,7 +939,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { adaptType() else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef) { val tree1 = expandMacro(tree) - if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) + if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) adaptConstrPattern() else if (inAllModes(mode, EXPRmode | FUNmode) && @@ -1084,7 +1084,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // Note: implicit arguments are still inferred (this kind of "chaining" is allowed) ) } - + def adaptToMember(qual: Tree, searchTemplate: Type): Tree = adaptToMember(qual, searchTemplate, true, true) def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree = @@ -1099,12 +1099,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match { case EmptyTree => qual - case coercion => + case coercion => if (settings.logImplicitConv.value) unit.echo(qual.pos, "applied implicit conversion from %s to %s = %s".format( qual.tpe, searchTemplate, coercion.symbol.defString)) - + typedQualifier(atPos(qual.pos)(new ApplyImplicitView(coercion, List(qual)))) } } @@ -2890,10 +2890,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else existentialTransform(hidden, tp)(existentialAbstraction) - + def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = - ctx.owner.isTerm && - (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || + ctx.owner.isTerm && + (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || { var ctx1 = ctx.outer while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer @@ -3056,7 +3056,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // as we don't know which alternative to choose... here we do map2Conserve(args, tparams) { //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe)) } } else // @M: there's probably something wrong when args.length != tparams.length... (triggered by bug #320) // Martin, I'm using fake trees, because, if you use args or arg.map(typedType), @@ -3880,7 +3880,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { reallyExists(sym) && ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.hasFlag(ACCESSOR)) } - + if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -4068,7 +4068,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // if symbol hasn't been fully loaded, can't check kind-arity else map2Conserve(args, tparams) { (arg, tparam) => //@M! the polytype denotes the expected kind - typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe)) } val argtypes = args1 map (_.tpe) @@ -4276,7 +4276,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // @M maybe the well-kindedness check should be done when checking the type arguments conform to the type parameters' bounds? val args1 = if (sameLength(args, tparams)) map2Conserve(args, tparams) { //@M! the polytype denotes the expected kind - (arg, tparam) => typedHigherKindedType(arg, mode, polyType(tparam.typeParams, AnyClass.tpe)) + (arg, tparam) => typedHigherKindedType(arg, mode, GenPolyType(tparam.typeParams, AnyClass.tpe)) } else { //@M this branch is correctly hit for an overloaded polymorphic type. It also has to handle erroneous cases. // Until the right alternative for an overloaded method is known, be very liberal, @@ -4371,7 +4371,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ReferenceToBoxed(idt @ Ident(_)) => val id1 = typed1(idt, mode, pt) match { case id: Ident => id } - treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe + treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe case Literal(value) => tree setType ( -- cgit v1.2.3 From 5118fd0d0894012da2e9fc95ee4c6ae5de198bd4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 30 Jan 2012 13:22:56 +0100 Subject: New phase that creates extension methods for inline classes. --- .../scala/tools/nsc/transform/ClassInliner.scala | 161 +++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 src/compiler/scala/tools/nsc/transform/ClassInliner.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/transform/ClassInliner.scala b/src/compiler/scala/tools/nsc/transform/ClassInliner.scala new file mode 100644 index 0000000000..c1104b025c --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/ClassInliner.scala @@ -0,0 +1,161 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Gilles Dubochet + * @author Martin Odersky + */ + +package scala.tools.nsc +package transform + +import symtab._ +import Flags._ +import scala.collection.{ mutable, immutable } +import scala.collection.mutable +import scala.tools.nsc.util.FreshNameCreator +import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } +import sun.tools.tree.OrExpression + +/** + * Perform Step 1 in the inline classes SIP + * + * @author Martin Odersky + * @version 2.10 + */ +abstract class ClassInlining extends Transform with TypingTransformers { + + import global._ // the global environment + import definitions._ // standard classes and methods + import typer.{ typed, atOwner } // methods to type trees + + /** the following two members override abstract members in Transform */ + val phaseName: String = "inlineclasses" + + def newTransformer(unit: CompilationUnit): Transformer = + new ClassInliner(unit) + + def hasUnboxedVersion(sym: Symbol) = + !sym.isParamAccessor && !sym.isConstructor + + /** Generate stream of possible names for the unboxed version of given instance method `imeth`. + * If the method is not overloaded, this stream consists of just "unboxed$imeth". + * If the method is overloaded, the stream has as first element "unboxedX$imeth", where X is the + * index of imeth in the sequence of overloaded alternatives with the same name. This choice will + * always be picked as the name of the generated unboxed method. + * After this first choice, all other possible indices in the range of 0 until the number + * of overloaded alternatives are returned. The secondary choices are used to find a matching method + * in `unboxedMethod` if the first name has the wrong type. We thereby gain a level of insensitivity + * of how overloaded types are ordered between phases and picklings. + */ + private def unboxedNames(imeth: Symbol): Stream[Name] = + imeth.owner.info.decl(imeth.name).tpe match { + case OverloadedType(_, alts) => + val index = alts indexOf imeth + assert(index >= 0, alts+" does not contain "+imeth) + def altName(index: Int) = newTermName("unboxed"+index+"$"+imeth.name) + altName(index) #:: ((0 until alts.length).toStream filter (index !=) map altName) + case tpe => + assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls) + Stream(newTermName("unboxed$"+imeth.name)) + } + + /** Return the unboxed method that corresponds to given instance method `meth`. + */ + def unboxedMethod(imeth: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { + val companionInfo = imeth.owner.companionModule.info + val candidates = unboxedNames(imeth) map (companionInfo.decl(_)) + val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) + assert(matching.nonEmpty, "no unboxed method found for "+imeth+" among "+candidates+"/"+unboxedNames(imeth)) + matching.head + } + + private def normalize(stpe: Type, clazz: Symbol): Type = stpe match { + case PolyType(tparams, restpe) => + GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe, clazz)) + case MethodType(tparams, restpe) => + restpe + case _ => + stpe + } + + class ClassInliner(unit: CompilationUnit) extends TypingTransformer(unit) { + + private val unboxedDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]() + + def unboxedMethInfo(unboxedMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { + var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, unboxedMeth) + val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpe)) + val thisParam = unboxedMeth.newValueParameter(nme.SELF, unboxedMeth.pos) setInfo thisParamType + def transform(clonedType: Type): Type = clonedType match { + case MethodType(params, restpe) => + MethodType(List(thisParam), clonedType) + case NullaryMethodType(restpe) => + MethodType(List(thisParam), restpe) + } + val GenPolyType(tparams, restpe) = origInfo cloneInfo unboxedMeth + GenPolyType(tparams ::: newTypeParams, transform(restpe)) + } + + private def allParams(tpe: Type): List[Symbol] = tpe match { + case MethodType(params, res) => params ::: allParams(res) + case _ => List() + } + + override def transform(tree: Tree): Tree = { + tree match { + case Template(_, _, _) => + if (currentOwner.isInlineClass) { + unboxedDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree] + super.transform(tree) + } + else tree + case DefDef(mods, name, tparams, vparamss, tpt, rhs) + if currentOwner.isInlineClass && hasUnboxedVersion(tree.symbol) => + val companion = currentOwner.companionModule + val origMeth = tree.symbol + val unboxedName = unboxedNames(origMeth).head + val unboxedMeth = companion.moduleClass.newMethod(unboxedName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL) + .setAnnotations(origMeth.annotations) + companion.info.decls.enter(unboxedMeth) + unboxedMeth.setInfo(unboxedMethInfo(unboxedMeth, origMeth.info, currentOwner)) + def thisParamRef = gen.mkAttributedIdent(unboxedMeth.info.params.head setPos unboxedMeth.pos) + val GenPolyType(unboxedTpeParams, unboxedMono) = unboxedMeth.info + val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams + val unboxedBody = rhs + .substTreeSyms(origTpeParams, unboxedTpeParams) + .substTreeSyms(vparamss.flatten map (_.symbol), allParams(unboxedMono).tail) + .substTreeThis(currentOwner, thisParamRef) + .changeOwner((origMeth, unboxedMeth)) + unboxedDefs(companion) += atPos(tree.pos) { DefDef(unboxedMeth, unboxedBody) } + val unboxedCallPrefix = Apply( + gen.mkTypeApply(gen.mkAttributedRef(companion), unboxedMeth, origTpeParams map (_.tpe)), + List(This(currentOwner))) + val unboxedCall = atOwner(origMeth) { + localTyper.typed { + atPos(rhs.pos) { + (unboxedCallPrefix /: vparamss) { + case (fn, params) => Apply(fn, params map (param => Ident(param.symbol))) + } + } + } + } + treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, unboxedCall) + case _ => + super.transform(tree) + } + } + + override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = + super.transformStats(stats, exprOwner) map { + case stat @ ModuleDef(mods, name, tmpl @ Template(parents, self, body)) => + unboxedDefs.remove(stat.symbol) match { + case Some(buf) => + val unboxedDefs = buf.toList map { mdef => atOwner(stat.symbol) { localTyper.typed(mdef) }} + treeCopy.ModuleDef(stat, mods, name, treeCopy.Template(tmpl, parents, self, body ++ buf)) + case None => + stat + } + case stat => + stat + } + } +} -- cgit v1.2.3 From df01dc8d91852a7d663a8fe4a15fef52933bab25 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 30 Jan 2012 13:23:24 +0100 Subject: Fixed problems with step 2 --- src/compiler/scala/tools/nsc/Global.scala | 9 +++++---- src/compiler/scala/tools/nsc/transform/Erasure.scala | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 8ed3393796..1092c7bce1 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -867,7 +867,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Counts for certain classes of warnings during this run. */ var deprecationWarnings: List[(Position, String)] = Nil var uncheckedWarnings: List[(Position, String)] = Nil - + /** A flag whether macro expansions failed */ var macroExpansionFailed = false @@ -1014,7 +1014,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } def cancel() { reporter.cancelled = true } - + private def currentProgress = (phasec * size) + unitc private def totalProgress = (phaseDescriptors.size - 1) * size // -1: drops terminal phase private def refreshProgress() = if (size > 0) progress(currentProgress, totalProgress) @@ -1031,6 +1031,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb val namerPhase = phaseNamed("namer") // packageobjects val typerPhase = phaseNamed("typer") + val inlineclassesPhase = phaseNamed("inlineclasses") // superaccessors val picklerPhase = phaseNamed("pickler") val refchecksPhase = phaseNamed("refchecks") @@ -1180,12 +1181,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb */ def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { try compileUnitsInternal(units, fromPhase) - catch { case ex => + catch { case ex => globalError(supplementErrorMessage("uncaught exception during compilation: " + ex.getClass.getName)) throw ex } } - + private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) { units foreach addUnit if (opt.profileAll) { diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 50350455a1..51941408a2 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -602,7 +602,7 @@ abstract class Erasure extends AddInterfaces Console.println("exception when typing " + tree) Console.println(er.msg + " in file " + context.owner.sourceFile) er.printStackTrace - abort() + abort("unrecoverable error") case ex: Exception => //if (settings.debug.value) try Console.println("exception when typing " + tree) @@ -986,8 +986,8 @@ abstract class Erasure extends AddInterfaces } } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos - } else if (false && fn.symbol.owner.isInlineClass && classInlining.hasUnboxedVersion(fn.symbol)) { - Apply(gen.mkAttributedRef(classInlining.staticMethod(fn.symbol)), qualifier :: args) + } else if (fn.symbol.owner.isInlineClass && classInlining.hasUnboxedVersion(fn.symbol)) { + Apply(gen.mkAttributedRef(classInlining.unboxedMethod(fn.symbol)), qualifier :: args) } else { tree } -- cgit v1.2.3 From 6eb066dade3f6541fb33a0b325c67ca98aa413ad Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 30 Jan 2012 15:42:20 +0100 Subject: Resinstantiating anyval-children test. Getting he complete build to run. --- .../scala/reflect/internal/Definitions.scala | 14 +- src/compiler/scala/tools/nsc/Global.scala | 6 +- .../scala/tools/nsc/transform/ClassInliner.scala | 161 --------------------- .../scala/tools/nsc/transform/Erasure.scala | 4 +- .../tools/nsc/transform/ExtensionMethods.scala | 161 +++++++++++++++++++++ src/library/scala/AnyVal.scala | 3 +- test/disabled/pos/anyval-children.scala | 1 - test/files/pos/anyval-children.flags | 1 + test/files/pos/anyval-children.scala | 1 + 9 files changed, 182 insertions(+), 170 deletions(-) delete mode 100644 src/compiler/scala/tools/nsc/transform/ClassInliner.scala create mode 100644 src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala delete mode 100644 test/disabled/pos/anyval-children.scala create mode 100644 test/files/pos/anyval-children.flags create mode 100644 test/files/pos/anyval-children.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index e8fc1c9cc9..715a68cf55 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -659,6 +659,15 @@ trait Definitions extends reflect.api.StandardDefinitions { AnyClass, nme.isInstanceOf_, tparam => NullaryMethodType(booltype)) setFlag FINAL lazy val Any_asInstanceOf = newPolyMethod( AnyClass, nme.asInstanceOf_, tparam => NullaryMethodType(tparam.typeConstructor)) setFlag FINAL + + // AnyVal_getClass is defined here. Once we have a new strap, it could also be + // defined directly in the AnyVal trait. Right now this does not work, because + // strap complains about overriding a final getClass method in Any. + lazy val AnyVal_getClass = { + val m = AnyValClass.newMethod(nme.getClass_) + val tparam = m.newExistential(newTypeName("T")) setInfo TypeBounds(NothingClass.tpe, AnyValClass.tpe) + m setInfoAndEnter MethodType(List(), ExistentialType(List(tparam), appliedType(ClassClass.typeConstructor, List(tparam.tpe)))) + } // members of class java.lang.{ Object, String } lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) @@ -859,7 +868,7 @@ trait Definitions extends reflect.api.StandardDefinitions { val msym = owner.info.decls enter owner.newMethod(name.encode) val tparam = newTypeParam(msym, 0) - msym setInfo GenPolyType(List(tparam), tcon(tparam)(msym)) + msym setInfo PolyType(List(tparam), tcon(tparam)(msym)) } private def newTypeParam(owner: Symbol, index: Int): Symbol = @@ -991,7 +1000,8 @@ trait Definitions extends reflect.api.StandardDefinitions { Object_synchronized, Object_isInstanceOf, Object_asInstanceOf, - String_+ + String_+, + AnyVal_getClass ) /** Removing the anyref parent they acquire from having a source file. diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 1092c7bce1..8026e92a21 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -436,11 +436,11 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb val global: Global.this.type = Global.this } with Analyzer - object classInlining extends { + object extensionMethods extends { val global: Global.this.type = Global.this val runsAfter = List("typer") val runsRightAfter = None - } with ClassInlining + } with ExtensionMethods // phaseName = "superaccessors" object superAccessors extends { @@ -656,7 +656,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb analyzer.packageObjects -> "load package objects", analyzer.typerFactory -> "the meat and potatoes: type the trees", superAccessors -> "add super accessors in traits and nested classes", - classInlining -> "add static methods to inline classes", + extensionMethods -> "add extension methods for inline classes", pickler -> "serialize symbol tables", refChecks -> "reference/override checking, translate nested objects", liftcode -> "reify trees", diff --git a/src/compiler/scala/tools/nsc/transform/ClassInliner.scala b/src/compiler/scala/tools/nsc/transform/ClassInliner.scala deleted file mode 100644 index c1104b025c..0000000000 --- a/src/compiler/scala/tools/nsc/transform/ClassInliner.scala +++ /dev/null @@ -1,161 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Gilles Dubochet - * @author Martin Odersky - */ - -package scala.tools.nsc -package transform - -import symtab._ -import Flags._ -import scala.collection.{ mutable, immutable } -import scala.collection.mutable -import scala.tools.nsc.util.FreshNameCreator -import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } -import sun.tools.tree.OrExpression - -/** - * Perform Step 1 in the inline classes SIP - * - * @author Martin Odersky - * @version 2.10 - */ -abstract class ClassInlining extends Transform with TypingTransformers { - - import global._ // the global environment - import definitions._ // standard classes and methods - import typer.{ typed, atOwner } // methods to type trees - - /** the following two members override abstract members in Transform */ - val phaseName: String = "inlineclasses" - - def newTransformer(unit: CompilationUnit): Transformer = - new ClassInliner(unit) - - def hasUnboxedVersion(sym: Symbol) = - !sym.isParamAccessor && !sym.isConstructor - - /** Generate stream of possible names for the unboxed version of given instance method `imeth`. - * If the method is not overloaded, this stream consists of just "unboxed$imeth". - * If the method is overloaded, the stream has as first element "unboxedX$imeth", where X is the - * index of imeth in the sequence of overloaded alternatives with the same name. This choice will - * always be picked as the name of the generated unboxed method. - * After this first choice, all other possible indices in the range of 0 until the number - * of overloaded alternatives are returned. The secondary choices are used to find a matching method - * in `unboxedMethod` if the first name has the wrong type. We thereby gain a level of insensitivity - * of how overloaded types are ordered between phases and picklings. - */ - private def unboxedNames(imeth: Symbol): Stream[Name] = - imeth.owner.info.decl(imeth.name).tpe match { - case OverloadedType(_, alts) => - val index = alts indexOf imeth - assert(index >= 0, alts+" does not contain "+imeth) - def altName(index: Int) = newTermName("unboxed"+index+"$"+imeth.name) - altName(index) #:: ((0 until alts.length).toStream filter (index !=) map altName) - case tpe => - assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls) - Stream(newTermName("unboxed$"+imeth.name)) - } - - /** Return the unboxed method that corresponds to given instance method `meth`. - */ - def unboxedMethod(imeth: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { - val companionInfo = imeth.owner.companionModule.info - val candidates = unboxedNames(imeth) map (companionInfo.decl(_)) - val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) - assert(matching.nonEmpty, "no unboxed method found for "+imeth+" among "+candidates+"/"+unboxedNames(imeth)) - matching.head - } - - private def normalize(stpe: Type, clazz: Symbol): Type = stpe match { - case PolyType(tparams, restpe) => - GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe, clazz)) - case MethodType(tparams, restpe) => - restpe - case _ => - stpe - } - - class ClassInliner(unit: CompilationUnit) extends TypingTransformer(unit) { - - private val unboxedDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]() - - def unboxedMethInfo(unboxedMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { - var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, unboxedMeth) - val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpe)) - val thisParam = unboxedMeth.newValueParameter(nme.SELF, unboxedMeth.pos) setInfo thisParamType - def transform(clonedType: Type): Type = clonedType match { - case MethodType(params, restpe) => - MethodType(List(thisParam), clonedType) - case NullaryMethodType(restpe) => - MethodType(List(thisParam), restpe) - } - val GenPolyType(tparams, restpe) = origInfo cloneInfo unboxedMeth - GenPolyType(tparams ::: newTypeParams, transform(restpe)) - } - - private def allParams(tpe: Type): List[Symbol] = tpe match { - case MethodType(params, res) => params ::: allParams(res) - case _ => List() - } - - override def transform(tree: Tree): Tree = { - tree match { - case Template(_, _, _) => - if (currentOwner.isInlineClass) { - unboxedDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree] - super.transform(tree) - } - else tree - case DefDef(mods, name, tparams, vparamss, tpt, rhs) - if currentOwner.isInlineClass && hasUnboxedVersion(tree.symbol) => - val companion = currentOwner.companionModule - val origMeth = tree.symbol - val unboxedName = unboxedNames(origMeth).head - val unboxedMeth = companion.moduleClass.newMethod(unboxedName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL) - .setAnnotations(origMeth.annotations) - companion.info.decls.enter(unboxedMeth) - unboxedMeth.setInfo(unboxedMethInfo(unboxedMeth, origMeth.info, currentOwner)) - def thisParamRef = gen.mkAttributedIdent(unboxedMeth.info.params.head setPos unboxedMeth.pos) - val GenPolyType(unboxedTpeParams, unboxedMono) = unboxedMeth.info - val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams - val unboxedBody = rhs - .substTreeSyms(origTpeParams, unboxedTpeParams) - .substTreeSyms(vparamss.flatten map (_.symbol), allParams(unboxedMono).tail) - .substTreeThis(currentOwner, thisParamRef) - .changeOwner((origMeth, unboxedMeth)) - unboxedDefs(companion) += atPos(tree.pos) { DefDef(unboxedMeth, unboxedBody) } - val unboxedCallPrefix = Apply( - gen.mkTypeApply(gen.mkAttributedRef(companion), unboxedMeth, origTpeParams map (_.tpe)), - List(This(currentOwner))) - val unboxedCall = atOwner(origMeth) { - localTyper.typed { - atPos(rhs.pos) { - (unboxedCallPrefix /: vparamss) { - case (fn, params) => Apply(fn, params map (param => Ident(param.symbol))) - } - } - } - } - treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, unboxedCall) - case _ => - super.transform(tree) - } - } - - override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = - super.transformStats(stats, exprOwner) map { - case stat @ ModuleDef(mods, name, tmpl @ Template(parents, self, body)) => - unboxedDefs.remove(stat.symbol) match { - case Some(buf) => - val unboxedDefs = buf.toList map { mdef => atOwner(stat.symbol) { localTyper.typed(mdef) }} - treeCopy.ModuleDef(stat, mods, name, treeCopy.Template(tmpl, parents, self, body ++ buf)) - case None => - stat - } - case stat => - stat - } - } -} diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 51941408a2..5b1555bfb7 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -986,8 +986,8 @@ abstract class Erasure extends AddInterfaces } } else if (fn.symbol.owner.isRefinementClass && !fn.symbol.isOverridingSymbol) { ApplyDynamic(qualifier, args) setSymbol fn.symbol setPos tree.pos - } else if (fn.symbol.owner.isInlineClass && classInlining.hasUnboxedVersion(fn.symbol)) { - Apply(gen.mkAttributedRef(classInlining.unboxedMethod(fn.symbol)), qualifier :: args) + } else if (fn.symbol.owner.isInlineClass && extensionMethods.hasExtension(fn.symbol)) { + Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) } else { tree } diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala new file mode 100644 index 0000000000..5f62dfab39 --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -0,0 +1,161 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Gilles Dubochet + * @author Martin Odersky + */ + +package scala.tools.nsc +package transform + +import symtab._ +import Flags._ +import scala.collection.{ mutable, immutable } +import scala.collection.mutable +import scala.tools.nsc.util.FreshNameCreator +import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } +import sun.tools.tree.OrExpression + +/** + * Perform Step 1 in the inline classes SIP + * + * @author Martin Odersky + * @version 2.10 + */ +abstract class ExtensionMethods extends Transform with TypingTransformers { + + import global._ // the global environment + import definitions._ // standard classes and methods + import typer.{ typed, atOwner } // methods to type trees + + /** the following two members override abstract members in Transform */ + val phaseName: String = "extmethods" + + def newTransformer(unit: CompilationUnit): Transformer = + new Extender(unit) + + def hasExtension(sym: Symbol) = + !sym.isParamAccessor && !sym.isConstructor + + /** Generate stream of possible names for the extension version of given instance method `imeth`. + * If the method is not overloaded, this stream consists of just "extension$imeth". + * If the method is overloaded, the stream has as first element "extensionX$imeth", where X is the + * index of imeth in the sequence of overloaded alternatives with the same name. This choice will + * always be picked as the name of the generated extension method. + * After this first choice, all other possible indices in the range of 0 until the number + * of overloaded alternatives are returned. The secondary choices are used to find a matching method + * in `extensionMethod` if the first name has the wrong type. We thereby gain a level of insensitivity + * of how overloaded types are ordered between phases and picklings. + */ + private def extensionNames(imeth: Symbol): Stream[Name] = + imeth.owner.info.decl(imeth.name).tpe match { + case OverloadedType(_, alts) => + val index = alts indexOf imeth + assert(index >= 0, alts+" does not contain "+imeth) + def altName(index: Int) = newTermName("extension"+index+"$"+imeth.name) + altName(index) #:: ((0 until alts.length).toStream filter (index !=) map altName) + case tpe => + assert(tpe != NoType, imeth.name+" not found in "+imeth.owner+"'s decls: "+imeth.owner.info.decls) + Stream(newTermName("extension$"+imeth.name)) + } + + /** Return the extension method that corresponds to given instance method `meth`. + */ + def extensionMethod(imeth: Symbol): Symbol = atPhase(currentRun.refchecksPhase) { + val companionInfo = imeth.owner.companionModule.info + val candidates = extensionNames(imeth) map (companionInfo.decl(_)) + val matching = candidates filter (alt => normalize(alt.tpe, imeth.owner) matches imeth.tpe) + assert(matching.nonEmpty, "no extension method found for "+imeth+" among "+candidates+"/"+extensionNames(imeth)) + matching.head + } + + private def normalize(stpe: Type, clazz: Symbol): Type = stpe match { + case PolyType(tparams, restpe) => + GenPolyType(tparams dropRight clazz.typeParams.length, normalize(restpe, clazz)) + case MethodType(tparams, restpe) => + restpe + case _ => + stpe + } + + class Extender(unit: CompilationUnit) extends TypingTransformer(unit) { + + private val extensionDefs = mutable.Map[Symbol, mutable.ListBuffer[Tree]]() + + def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { + var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) + val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpe)) + val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType + def transform(clonedType: Type): Type = clonedType match { + case MethodType(params, restpe) => + MethodType(List(thisParam), clonedType) + case NullaryMethodType(restpe) => + MethodType(List(thisParam), restpe) + } + val GenPolyType(tparams, restpe) = origInfo cloneInfo extensionMeth + GenPolyType(tparams ::: newTypeParams, transform(restpe)) + } + + private def allParams(tpe: Type): List[Symbol] = tpe match { + case MethodType(params, res) => params ::: allParams(res) + case _ => List() + } + + override def transform(tree: Tree): Tree = { + tree match { + case Template(_, _, _) => + if (currentOwner.isInlineClass) { + extensionDefs(currentOwner.companionModule) = new mutable.ListBuffer[Tree] + super.transform(tree) + } + else tree + case DefDef(mods, name, tparams, vparamss, tpt, rhs) + if currentOwner.isInlineClass && hasExtension(tree.symbol) => + val companion = currentOwner.companionModule + val origMeth = tree.symbol + val extensionName = extensionNames(origMeth).head + val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL) + .setAnnotations(origMeth.annotations) + companion.info.decls.enter(extensionMeth) + extensionMeth.setInfo(extensionMethInfo(extensionMeth, origMeth.info, currentOwner)) + def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos) + val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info + val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams + val extensionBody = rhs + .substTreeSyms(origTpeParams, extensionTpeParams) + .substTreeSyms(vparamss.flatten map (_.symbol), allParams(extensionMono).tail) + .substTreeThis(currentOwner, thisParamRef) + .changeOwner((origMeth, extensionMeth)) + extensionDefs(companion) += atPos(tree.pos) { DefDef(extensionMeth, extensionBody) } + val extensionCallPrefix = Apply( + gen.mkTypeApply(gen.mkAttributedRef(companion), extensionMeth, origTpeParams map (_.tpe)), + List(This(currentOwner))) + val extensionCall = atOwner(origMeth) { + localTyper.typed { + atPos(rhs.pos) { + (extensionCallPrefix /: vparamss) { + case (fn, params) => Apply(fn, params map (param => Ident(param.symbol))) + } + } + } + } + treeCopy.DefDef(tree, mods, name, tparams, vparamss, tpt, extensionCall) + case _ => + super.transform(tree) + } + } + + override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = + super.transformStats(stats, exprOwner) map { + case stat @ ModuleDef(mods, name, tmpl @ Template(parents, self, body)) => + extensionDefs.remove(stat.symbol) match { + case Some(buf) => + val extensionDefs = buf.toList map { mdef => atOwner(stat.symbol) { localTyper.typed(mdef) }} + treeCopy.ModuleDef(stat, mods, name, treeCopy.Template(tmpl, parents, self, body ++ buf)) + case None => + stat + } + case stat => + stat + } + } +} diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index ed4c5f5948..fb36d61c57 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -26,6 +26,7 @@ package scala * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ trait AnyVal { -// disabled for now to make the standard build go through +// disabled for now to make the standard build go through. +// Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. // def getClass(): Class[_ <: AnyVal] = ??? } diff --git a/test/disabled/pos/anyval-children.scala b/test/disabled/pos/anyval-children.scala deleted file mode 100644 index 7a2eda8b3f..0000000000 --- a/test/disabled/pos/anyval-children.scala +++ /dev/null @@ -1 +0,0 @@ -class Bippy extends AnyVal \ No newline at end of file diff --git a/test/files/pos/anyval-children.flags b/test/files/pos/anyval-children.flags new file mode 100644 index 0000000000..80fce051e6 --- /dev/null +++ b/test/files/pos/anyval-children.flags @@ -0,0 +1 @@ +-Ystop-after:erasure \ No newline at end of file diff --git a/test/files/pos/anyval-children.scala b/test/files/pos/anyval-children.scala new file mode 100644 index 0000000000..7a2eda8b3f --- /dev/null +++ b/test/files/pos/anyval-children.scala @@ -0,0 +1 @@ +class Bippy extends AnyVal \ No newline at end of file -- cgit v1.2.3 From 6eb24b2beacdb2c94b7818de319b338add298c98 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 30 Jan 2012 08:05:12 -0800 Subject: Moving getClassReturnType out of erasure. And other post-merge cleanup. --- .../scala/reflect/internal/Definitions.scala | 35 +++++++++++++++++++++- .../scala/tools/nsc/transform/Erasure.scala | 33 -------------------- .../scala/tools/nsc/typechecker/Typers.scala | 2 +- 3 files changed, 35 insertions(+), 35 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 9c9a9293aa..4857ec6b80 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -663,7 +663,40 @@ trait Definitions extends reflect.api.StandardDefinitions { // AnyVal_getClass is defined here. Once we have a new strap, it could also be // defined directly in the AnyVal trait. Right now this does not work, because // strap complains about overriding a final getClass method in Any. - lazy val AnyVal_getClass = newMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe), DEFERRED) + lazy val AnyVal_getClass = newMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe)) + + // A type function from T => Class[U], used to determine the return + // type of getClass calls. The returned type is: + // + // 1. If T is a value type, Class[T]. + // 2. If T is a phantom type (Any or AnyVal), Class[_]. + // 3. If T is a local class, Class[_ <: |T|]. + // 4. Otherwise, Class[_ <: T]. + // + // Note: AnyVal cannot be Class[_ <: AnyVal] because if the static type of the + // receiver is AnyVal, it implies the receiver is boxed, so the correct + // class object is that of java.lang.Integer, not Int. + // + // TODO: If T is final, return type could be Class[T]. Should it? + def getClassReturnType(tp: Type): Type = { + val sym = tp.typeSymbol + + if (phase.erasedTypes) ClassClass.tpe + else if (isValueClass(sym)) ClassType(tp.widen) + else { + val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams) + val upperBound = ( + if (isPhantomClass(sym)) AnyClass.tpe + else if (sym.isLocalClass) erasure.intersectionDominator(tp.parents) + else tp.widen + ) + + existentialAbstraction( + eparams, + ClassType(eparams.head setInfo TypeBounds.upper(upperBound) tpe) + ) + } + } // members of class java.lang.{ Object, String } lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 1d321b068c..6b7e34cf49 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -31,39 +31,6 @@ abstract class Erasure extends AddInterfaces // -------- erasure on types -------------------------------------------------------- - // A type function from T => Class[U], used to determine the return - // type of getClass calls. The returned type is: - // - // 1. If T is a value type, Class[T]. - // 2. If T is a phantom type (Any or AnyVal), Class[_]. - // 3. If T is a local class, Class[_ <: |T|]. - // 4. Otherwise, Class[_ <: T]. - // - // Note: AnyVal cannot be Class[_ <: AnyVal] because if the static type of the - // receiver is AnyVal, it implies the receiver is boxed, so the correct - // class object is that of java.lang.Integer, not Int. - // - // TODO: If T is final, return type could be Class[T]. Should it? - def getClassReturnType(tp: Type): Type = { - val sym = tp.typeSymbol - - if (phase.erasedTypes) ClassClass.tpe - else if (isValueClass(sym)) ClassType(tp.widen) - else { - val eparams = typeParamsToExistentials(ClassClass, ClassClass.typeParams) - val upperBound = ( - if (isPhantomClass(sym)) AnyClass.tpe - else if (sym.isLocalClass) intersectionDominator(tp.parents) - else tp.widen - ) - - existentialAbstraction( - eparams, - ClassType(eparams.head setInfo TypeBounds.upper(upperBound) tpe) - ) - } - } - // convert a numeric with a toXXX method def numericConversion(tree: Tree, numericSym: Symbol): Tree = { val mname = newTermName("to" + numericSym.name) diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b427e19820..161daa4275 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3823,7 +3823,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { && qual.tpe.typeSymbol.isPublic ) if (isRefinableGetClass) - selection setType MethodType(Nil, erasure.getClassReturnType(qual.tpe)) + selection setType MethodType(Nil, getClassReturnType(qual.tpe)) else selection } -- cgit v1.2.3 From d762e4caf9e201e597a76566eb9f61ad53b5f4cf Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 30 Jan 2012 11:06:22 -0800 Subject: Working AnyVal#getClass. Renamed newMethod in Definitions to enterNewMethod to better indicate what it does, and also so AnyVal's getClass can avoid the "enter" part. --- .../scala/reflect/internal/Definitions.scala | 42 +++++++++++----------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 4857ec6b80..7d31537e7a 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -22,15 +22,17 @@ trait Definitions extends reflect.api.StandardDefinitions { */ private type PolyMethodCreator = List[Symbol] => (Option[List[Type]], Type) - private def newClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { + private def enterNewClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { val clazz = owner.newClassSymbol(name, NoPosition, flags) clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) } private def newMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = { val msym = owner.newMethod(name.encode, NoPosition, flags) val params = msym.newSyntheticValueParams(formals) - msym setInfoAndEnter MethodType(params, restpe) + msym setInfo MethodType(params, restpe) } + private def enterNewMethod(owner: Symbol, name: TermName, formals: List[Type], restpe: Type, flags: Long = 0L): Symbol = + owner.info.decls enter newMethod(owner, name, formals, restpe, flags) // the scala value classes trait ValueClassDefinitions { @@ -206,7 +208,7 @@ trait Definitions extends reflect.api.StandardDefinitions { } // top types - lazy val AnyClass = newClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) + lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) lazy val ObjectClass = getClass(sn.Object) lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") initFlags (SEALED | ABSTRACT | TRAIT) @@ -311,7 +313,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // .setInfo(UnitClass.tpe) lazy val TypeConstraintClass = getRequiredClass("scala.annotation.TypeConstraint") - lazy val SingletonClass = newClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) + lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) lazy val ComparableClass = getRequiredClass("java.lang.Comparable") @@ -640,12 +642,12 @@ trait Definitions extends reflect.api.StandardDefinitions { } // members of class scala.Any - lazy val Any_== = newMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) - lazy val Any_!= = newMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) - lazy val Any_equals = newMethod(AnyClass, nme.equals_, anyparam, booltype) - lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, Nil, inttype) - lazy val Any_toString = newMethod(AnyClass, nme.toString_, Nil, stringtype) - lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL) + lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) + lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) + lazy val Any_equals = enterNewMethod(AnyClass, nme.equals_, anyparam, booltype) + lazy val Any_hashCode = enterNewMethod(AnyClass, nme.hashCode_, Nil, inttype) + lazy val Any_toString = enterNewMethod(AnyClass, nme.toString_, Nil, stringtype) + lazy val Any_## = enterNewMethod(AnyClass, nme.HASHHASH, Nil, inttype, FINAL) // Any_getClass requires special handling. The return type is determined on // a per-call-site basis as if the function being called were actually: @@ -656,7 +658,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // Since getClass is not actually a polymorphic method, this requires compiler // participation. At the "Any" level, the return type is Class[_] as it is in // java.lang.Object. Java also special cases the return type. - lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED) + lazy val Any_getClass = enterNewMethod(AnyClass, nme.getClass_, Nil, getMember(ObjectClass, nme.getClass_).tpe.resultType, DEFERRED) lazy val Any_isInstanceOf = newT1NullaryMethod(AnyClass, nme.isInstanceOf_, FINAL)(_ => booltype) lazy val Any_asInstanceOf = newT1NullaryMethod(AnyClass, nme.asInstanceOf_, FINAL)(_.typeConstructor) @@ -699,17 +701,17 @@ trait Definitions extends reflect.api.StandardDefinitions { } // members of class java.lang.{ Object, String } - lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) - lazy val Object_== = newMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) - lazy val Object_!= = newMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) - lazy val Object_eq = newMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) - lazy val Object_ne = newMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) + lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) + lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) + lazy val Object_!= = enterNewMethod(ObjectClass, nme.NE, anyrefparam, booltype, FINAL) + lazy val Object_eq = enterNewMethod(ObjectClass, nme.eq, anyrefparam, booltype, FINAL) + lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype) lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor) lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor) ) - lazy val String_+ = newMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) + lazy val String_+ = enterNewMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) def Object_getClass = getMember(ObjectClass, nme.getClass_) def Object_clone = getMember(ObjectClass, nme.clone_) @@ -794,7 +796,7 @@ trait Definitions extends reflect.api.StandardDefinitions { ) lazy val AnnotationDefaultAttr: Symbol = { - val attr = newClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor)) + val attr = enterNewClass(RuntimePackageClass, tpnme.AnnotationDefaultATTR, List(AnnotationClass.typeConstructor)) // This attribute needs a constructor so that modifiers in parsed Java code make sense attr.info.decls enter attr.newClassConstructor(NoPosition) attr @@ -868,7 +870,7 @@ trait Definitions extends reflect.api.StandardDefinitions { owner.newAliasType(name) setInfoAndEnter alias private def specialPolyClass(name: TypeName, flags: Long)(parentFn: Symbol => Type): Symbol = { - val clazz = newClass(ScalaPackageClass, name, Nil) + val clazz = enterNewClass(ScalaPackageClass, name, Nil) val tparam = clazz.newSyntheticTypeParam("T0", flags) val parents = List(AnyRefClass.tpe, parentFn(tparam)) @@ -1044,7 +1046,7 @@ trait Definitions extends reflect.api.StandardDefinitions { // tparam => resultType, which is the resultType of PolyType, i.e. the result type after applying the // type parameter =-> a MethodType in this case // TODO: set type bounds manually (-> MulticastDelegate), see newTypeParam - val newCaller = newMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC) + val newCaller = enterNewMethod(DelegateClass, name, paramTypes, delegateType, FINAL | STATIC) // val newCaller = newPolyMethod(DelegateClass, name, // tparam => MethodType(paramTypes, tparam.typeConstructor)) setFlag (FINAL | STATIC) Delegate_scalaCallers = Delegate_scalaCallers ::: List(newCaller) -- cgit v1.2.3 From 2bfb2e6de12a7cecd2f67a52ce5f8fe079b7ac5e Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 30 Jan 2012 12:00:50 -0800 Subject: Eliminated 2500 lines of whitespace changes. --- .../scala/reflect/internal/Definitions.scala | 18 +-- src/compiler/scala/reflect/internal/Symbols.scala | 64 ++++----- .../scala/reflect/internal/TreePrinters.scala | 20 +-- src/compiler/scala/reflect/internal/Trees.scala | 4 +- src/compiler/scala/reflect/internal/Types.scala | 148 ++++++++++----------- .../scala/reflect/runtime/JavaToScala.scala | 2 +- src/compiler/scala/tools/nsc/Global.scala | 16 +-- .../scala/tools/nsc/ast/parser/Parsers.scala | 4 +- .../nsc/symtab/classfile/ClassfileParser.scala | 4 +- .../scala/tools/nsc/transform/Erasure.scala | 4 +- .../scala/tools/nsc/transform/LambdaLift.scala | 16 +-- .../tools/nsc/transform/SpecializeTypes.scala | 10 +- .../tools/nsc/typechecker/ContextErrors.scala | 50 +++---- .../scala/tools/nsc/typechecker/Namers.scala | 4 +- .../scala/tools/nsc/typechecker/RefChecks.scala | 10 +- .../scala/tools/nsc/typechecker/Typers.scala | 22 +-- src/library/scala/Byte.scala | 112 ++++++++-------- src/library/scala/Char.scala | 112 ++++++++-------- src/library/scala/Int.scala | 112 ++++++++-------- src/library/scala/Long.scala | 112 ++++++++-------- src/library/scala/Short.scala | 112 ++++++++-------- 21 files changed, 478 insertions(+), 478 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 7d31537e7a..f8342444c8 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -166,7 +166,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val RuntimePackage = getRequiredModule("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass - + lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum") // convenient one-argument parameter lists @@ -178,10 +178,10 @@ trait Definitions extends reflect.api.StandardDefinitions { private def booltype = BooleanClass.typeConstructor private def inttype = IntClass.typeConstructor private def stringtype = StringClass.typeConstructor - + // Java types def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName) - + def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { case java.lang.Void.TYPE => UnitClass case java.lang.Byte.TYPE => ByteClass @@ -274,7 +274,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def Predef_identity = getMember(PredefModule, nme.identity) def Predef_conforms = getMember(PredefModule, nme.conforms) def Predef_wrapRefArray = getMember(PredefModule, nme.wrapRefArray) - + /** Is `sym` a member of Predef with the given name? * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def` * which does a member lookup (it can't be a lazy val because we might reload Predef @@ -496,7 +496,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case DoubleClass => nme.wrapDoubleArray case BooleanClass => nme.wrapBooleanArray case UnitClass => nme.wrapUnitArray - case _ => + case _ => if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray else nme.genericWrapArray } @@ -640,7 +640,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => false }) } - + // members of class scala.Any lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) @@ -816,10 +816,10 @@ trait Definitions extends reflect.api.StandardDefinitions { while (result.isAliasType) result = result.info.typeSymbol result } - + def getRequiredModule(fullname: String): Symbol = getModule(newTermNameCached(fullname)) - def getRequiredClass(fullname: String): Symbol = + def getRequiredClass(fullname: String): Symbol = getClass(newTypeNameCached(fullname)) def getClassIfDefined(fullname: String): Symbol = @@ -993,7 +993,7 @@ trait Definitions extends reflect.api.StandardDefinitions { RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage - + val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 RepeatedParamClass, diff --git a/src/compiler/scala/reflect/internal/Symbols.scala b/src/compiler/scala/reflect/internal/Symbols.scala index 92c896d30b..e504cea8cf 100644 --- a/src/compiler/scala/reflect/internal/Symbols.scala +++ b/src/compiler/scala/reflect/internal/Symbols.scala @@ -17,7 +17,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => import definitions._ protected var ids = 0 - + val emptySymbolArray = new Array[Symbol](0) def symbolCount = ids // statistics @@ -38,14 +38,14 @@ trait Symbols extends api.Symbols { self: SymbolTable => nextexid += 1 newTypeName("_" + nextexid + suffix) } - + // Set the fields which point companions at one another. Returns the module. def connectModuleToClass(m: ModuleSymbol, moduleClass: ClassSymbol): ModuleSymbol = { moduleClass.sourceModule = m m setModuleClass moduleClass m } - + /** Create a new free variable. Its owner is NoSymbol. */ def newFreeVar(name: TermName, tpe: Type, value: Any, newFlags: Long = 0L): FreeVar = @@ -84,19 +84,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => private[this] var _rawowner = initOwner // Syncnote: need not be protected, as only assignment happens in owner_=, which is not exposed to api private[this] var _rawname = initName private[this] var _rawflags = 0L - + def rawowner = _rawowner def rawname = _rawname def rawflags = _rawflags - + protected def rawflags_=(x: FlagsType) { _rawflags = x } - + private var rawpos = initPos - + val id = nextId() // identity displayed when -uniqid private[this] var _validTo: Period = NoPeriod - + def validTo = _validTo def validTo_=(x: Period) { _validTo = x} @@ -169,10 +169,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ def newTermSymbol(name: TermName, pos: Position = NoPosition, newFlags: Long = 0L): TermSymbol = new TermSymbol(this, pos, name) initFlags newFlags - + def newAbstractTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AbstractTypeSymbol = new AbstractTypeSymbol(this, pos, name) initFlags newFlags - + def newAliasTypeSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): AliasTypeSymbol = new AliasTypeSymbol(this, pos, name) initFlags newFlags @@ -184,10 +184,10 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ClassSymbol = new ClassSymbol(this, pos, name) initFlags newFlags - + def newModuleClassSymbol(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): ModuleClassSymbol = new ModuleClassSymbol(this, pos, name) initFlags newFlags - + /** Derive whether it is an abstract type from the flags; after creation * the DEFERRED flag will be ignored. */ @@ -196,7 +196,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => newAliasTypeSymbol(name, pos, newFlags) else newAbstractTypeSymbol(name, pos, newFlags) - + def newTypeSkolemSymbol(name: TypeName, origin: AnyRef, pos: Position = NoPosition, newFlags: Long = 0L): TypeSkolem = if ((newFlags & DEFERRED) == 0L) new TypeSkolem(this, pos, name, origin) initFlags newFlags @@ -233,7 +233,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def newAliasType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = newAliasTypeSymbol(name, pos, newFlags) - + /** Symbol of an abstract type type T >: ... <: ... */ final def newAbstractType(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L): Symbol = @@ -292,7 +292,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final def newClass(name: TypeName, pos: Position = NoPosition, newFlags: Long = 0L) = newClassSymbol(name, pos, newFlags) - + /** A new class with its info set to a ClassInfoType with given scope and parents. */ def newClassWithInfo(name: TypeName, parents: List[Type], scope: Scope, pos: Position = NoPosition, newFlags: Long = 0L) = { val clazz = newClass(name, pos, newFlags) @@ -344,9 +344,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def newAliasType(pos: Position, name: TypeName): Symbol = newAliasType(name, pos) @deprecated("Use the other signature", "2.10.0") def newAbstractType(pos: Position, name: TypeName): Symbol = newAbstractType(name, pos) - @deprecated("Use the other signature", "2.10.0") + @deprecated("Use the other signature", "2.10.0") def newExistential(pos: Position, name: TypeName): Symbol = newExistential(name, pos) - @deprecated("Use the other signature", "2.10.0") + @deprecated("Use the other signature", "2.10.0") def newMethod(pos: Position, name: TermName): MethodSymbol = newMethod(name, pos) // ----- locking and unlocking ------------------------------------------------------ @@ -830,7 +830,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => private def addModuleSuffix(n: Name): Name = if (needsModuleSuffix) n append nme.MODULE_SUFFIX_STRING else n - + def moduleSuffix: String = ( if (needsModuleSuffix) nme.MODULE_SUFFIX_STRING else "" @@ -838,7 +838,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Whether this symbol needs nme.MODULE_SUFFIX_STRING (aka $) appended on the java platform. */ def needsModuleSuffix = ( - hasModuleFlag + hasModuleFlag && !isMethod && !isImplClass && !isJavaDefined @@ -865,7 +865,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => else if (owner.isEffectiveRoot) name else effectiveOwner.enclClass.fullNameAsName(separator) append separator append name ) - + def fullNameAsName(separator: Char): Name = nme.dropLocalSuffix(fullNameInternal(separator)) /** The encoded full path name of this symbol, where outer names and inner names @@ -1017,7 +1017,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => /** Substitute second list of symbols for first in current info. */ def substInfo(syms0: List[Symbol], syms1: List[Symbol]) = modifyInfo(_.substSym(syms0, syms1)) def setInfoOwnerAdjusted(info: Type): this.type = setInfo(info atOwner this) - + /** Set the info and enter this symbol into the owner's scope. */ def setInfoAndEnter(info: Type): this.type = { setInfo(info) @@ -1319,7 +1319,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => */ final def isNestedIn(that: Symbol): Boolean = owner == that || owner != NoSymbol && (owner isNestedIn that) - + /** Is this class symbol a subclass of that symbol, * and is this class symbol also different from Null or Nothing? */ def isNonBottomSubClass(that: Symbol): Boolean = false @@ -2119,7 +2119,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => def referenced: Symbol = _referenced def referenced_=(x: Symbol) { _referenced = x } - + def existentialBound = singletonBounds(this.tpe) def cloneSymbolImpl(owner: Symbol, newFlags: Long): Symbol = @@ -2213,7 +2213,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => if (!isMethod && needsFlatClasses) { if (flatname eq null) flatname = nme.flattenedName(rawowner.name, rawname) - + flatname } else rawname.toTermName @@ -2249,7 +2249,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => res } } - + class AliasTypeSymbol protected[Symbols] (initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) { // Temporary programmatic help tracking down who might do such a thing @@ -2264,13 +2264,13 @@ trait Symbols extends api.Symbols { self: SymbolTable => override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AliasTypeSymbol = owner.newAliasTypeSymbol(name, pos, newFlags) } - + class AbstractTypeSymbol(initOwner: Symbol, initPos: Position, initName: TypeName) extends TypeSymbol(initOwner, initPos, initName) with AbstractTypeMixin { override def cloneSymbolImpl(owner: Symbol, newFlags: Long): AbstractTypeSymbol = owner.newAbstractTypeSymbol(name, pos, newFlags) } - + /** Might be mixed into TypeSymbol or TypeSkolem. */ trait AbstractTypeMixin extends TypeSymbol { @@ -2468,7 +2468,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => final override def isNonClassType = false final override def isAbstractType = false final override def isAliasType = false - + override def existentialBound = GenPolyType(this.typeParams, TypeBounds.upper(this.classBound)) override def sourceFile = @@ -2496,19 +2496,19 @@ trait Symbols extends api.Symbols { self: SymbolTable => } thisTypeCache } - + override def owner: Symbol = if (needsFlatClasses) rawowner.owner else rawowner override def name: TypeName = ( if (needsFlatClasses) { if (flatname eq null) flatname = nme.flattenedName(rawowner.name, rawname).toTypeName - + flatname } else rawname.toTypeName ) - + /** A symbol carrying the self type of the class as its type */ override def thisSym: Symbol = thissym @@ -2691,7 +2691,7 @@ trait Symbols extends api.Symbols { self: SymbolTable => val syms1 = cloneSymbolsAtOwner(syms, owner) creator(syms1, tpe.substSym(syms, syms1)) } - + /** A deep map on a symbol's paramss. */ def mapParamss[T](sym: Symbol)(f: Symbol => T): List[List[T]] = mmap(sym.info.paramss)(f) diff --git a/src/compiler/scala/reflect/internal/TreePrinters.scala b/src/compiler/scala/reflect/internal/TreePrinters.scala index aaee72f644..e7ba0c793d 100644 --- a/src/compiler/scala/reflect/internal/TreePrinters.scala +++ b/src/compiler/scala/reflect/internal/TreePrinters.scala @@ -249,17 +249,17 @@ trait TreePrinters extends api.TreePrinters { self: SymbolTable => print("AnyVal") } else { - printRow(parents, " with ") - if (!body.isEmpty) { - if (self.name != nme.WILDCARD) { - print(" { ", self.name); printOpt(": ", self.tpt); print(" => ") - } else if (!self.tpt.isEmpty) { - print(" { _ : ", self.tpt, " => ") - } else { - print(" {") - } - printColumn(body, "", ";", "}") + printRow(parents, " with ") + if (!body.isEmpty) { + if (self.name != nme.WILDCARD) { + print(" { ", self.name); printOpt(": ", self.tpt); print(" => ") + } else if (!self.tpt.isEmpty) { + print(" { _ : ", self.tpt, " => ") + } else { + print(" {") } + printColumn(body, "", ";", "}") + } } currentOwner = currentOwner1 diff --git a/src/compiler/scala/reflect/internal/Trees.scala b/src/compiler/scala/reflect/internal/Trees.scala index 50929ecc32..3c339ad8e2 100644 --- a/src/compiler/scala/reflect/internal/Trees.scala +++ b/src/compiler/scala/reflect/internal/Trees.scala @@ -10,7 +10,7 @@ import Flags._ import api.Modifier trait Trees extends api.Trees { self: SymbolTable => - + // Belongs in TreeInfo but then I can't reach it from TreePrinters. def isReferenceToScalaMember(t: Tree, Id: Name) = t match { case Ident(Id) => true @@ -133,7 +133,7 @@ trait Trees extends api.Trees { self: SymbolTable => new ChangeOwnerTraverser(oldOwner, newOwner) apply t } } - + def substTreeSyms(pairs: (Symbol, Symbol)*): Tree = substTreeSyms(pairs.map(_._1).toList, pairs.map(_._2).toList) diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 5fa03eab3c..49ac205409 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -110,13 +110,13 @@ trait Types extends api.Types { self: SymbolTable => * to undo constraints in the case of isSubType/isSameType failure. */ lazy val undoLog = newUndoLog - + protected def newUndoLog = new UndoLog - + class UndoLog { private type UndoPairs = List[(TypeVar, TypeConstraint)] private var log: UndoPairs = List() - + // register with the auto-clearing cache manager perRunCaches.recordCache(this) @@ -136,7 +136,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] def record(tv: TypeVar) = { log ::= ((tv, tv.constr.cloneInternal)) } - + private[scala] def clear() { if (settings.debug.value) self.log("Clearing " + log.size + " entries from the undoLog.") @@ -427,7 +427,7 @@ trait Types extends api.Types { self: SymbolTable => /** For a typeref, its arguments. The empty list for all other types */ def typeArgs: List[Type] = List() - + /** A list of placeholder types derived from the type parameters. * Used by RefinedType and TypeRef. */ @@ -524,7 +524,7 @@ trait Types extends api.Types { self: SymbolTable => * Alternatives of overloaded symbol appear in the order they are declared. */ def decl(name: Name): Symbol = findDecl(name, 0) - + /** A list of all non-private members defined or declared in this type. */ def nonPrivateDecls: List[Symbol] = decls filter (x => !x.isPrivate) toList @@ -565,7 +565,7 @@ trait Types extends api.Types { self: SymbolTable => */ def nonPrivateMember(name: Name): Symbol = memberBasedOnName(name, BridgeAndPrivateFlags) - + /** All members with the given flags, excluding bridges. */ def membersWithFlags(requiredFlags: Long): List[Symbol] = @@ -590,7 +590,7 @@ trait Types extends api.Types { self: SymbolTable => * an OverloadedSymbol if several exist, NoSymbol if none exist */ def nonLocalMember(name: Name): Symbol = memberBasedOnName(name, BridgeFlags | LOCAL) - + /** Members excluding and requiring the given flags. * Note: unfortunately it doesn't work to exclude DEFERRED this way. */ @@ -1236,7 +1236,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] var underlyingPeriod = NoPeriod override def underlying: Type = { val cache = underlyingCache - if (underlyingPeriod == currentPeriod && cache != null) cache + if (underlyingPeriod == currentPeriod && cache != null) cache else { defineUnderlyingOfSingleType(this) underlyingCache @@ -1279,7 +1279,7 @@ trait Types extends api.Types { self: SymbolTable => unique(new UniqueSingleType(pre, sym)) } } - + protected def defineUnderlyingOfSingleType(tpe: SingleType) = { val period = tpe.underlyingPeriod if (period != currentPeriod) { @@ -1349,13 +1349,13 @@ trait Types extends api.Types { self: SymbolTable => override def baseTypeSeq: BaseTypeSeq = { val cached = baseTypeSeqCache - if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq) + if (baseTypeSeqPeriod == currentPeriod && cached != null && cached != undetBaseTypeSeq) cached else { defineBaseTypeSeqOfCompoundType(this) if (baseTypeSeqCache eq undetBaseTypeSeq) throw new RecoverableCyclicReference(typeSymbol) - + baseTypeSeqCache } } @@ -1369,7 +1369,7 @@ trait Types extends api.Types { self: SymbolTable => defineBaseClassesOfCompoundType(this) if (baseClassesCache eq null) throw new RecoverableCyclicReference(typeSymbol) - + baseClassesCache } } @@ -1415,7 +1415,7 @@ trait Types extends api.Types { self: SymbolTable => (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) decls.mkString("{", "; ", "}") else "") } - + protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = { val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { @@ -1468,7 +1468,7 @@ trait Types extends api.Types { self: SymbolTable => if (tpe.baseTypeSeqCache eq undetBaseTypeSeq) throw new TypeError("illegal cyclic inheritance involving " + tpe.typeSymbol) } - + protected def defineBaseClassesOfCompoundType(tpe: CompoundType) = { def computeBaseClasses: List[Symbol] = if (tpe.parents.isEmpty) List(tpe.typeSymbol) @@ -1787,13 +1787,13 @@ trait Types extends api.Types { self: SymbolTable => } } - /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected + /* Syncnote: The `volatile` var and `pendingVolatiles` mutable set need not be protected * with synchronized, because they are accessed only from isVolatile, which is called only from * Typer. */ private var volatileRecursions: Int = 0 private val pendingVolatiles = new mutable.HashSet[Symbol] - + class ArgsTypeRef(pre0: Type, sym0: Symbol, args0: List[Type]) extends TypeRef(pre0, sym0, args0) with UniqueType { require(args0.nonEmpty, this) @@ -1811,7 +1811,7 @@ trait Types extends api.Types { self: SymbolTable => asSeenFromOwner(tp).instantiateTypeParams(sym.typeParams, args) } - + // note: does not go through typeRef. There's no need to because // neither `pre` nor `sym` changes. And there's a performance // advantage to call TypeRef directly. @@ -1826,7 +1826,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = typeParams.nonEmpty override def typeParams = if (isDefinitionsInitialized) sym.typeParams else sym.unsafeTypeParams private def isRaw = !phase.erasedTypes && isRawIfWithoutArgs(sym) - + override def instantiateTypeParams(formals: List[Symbol], actuals: List[Type]): Type = if (isHigherKinded) { if (sameLength(formals intersect typeParams, typeParams)) @@ -1846,9 +1846,9 @@ trait Types extends api.Types { self: SymbolTable => res } - override def transformInfo(tp: Type): Type = + override def transformInfo(tp: Type): Type = appliedType(asSeenFromOwner(tp), dummyArgs) - + override def narrow = if (sym.isModuleClass) singleType(pre, sym.sourceModule) else super.narrow @@ -1856,14 +1856,14 @@ trait Types extends api.Types { self: SymbolTable => override def typeConstructor = this // eta-expand, subtyping relies on eta-expansion of higher-kinded types - override protected def normalizeImpl: Type = + override protected def normalizeImpl: Type = if (isHigherKinded) etaExpand else super.normalizeImpl } - + trait ClassTypeRef extends TypeRef { // !!! There are scaladoc-created symbols arriving which violate this require. // require(sym.isClass, sym) - + override protected def normalizeImpl: Type = if (sym.isRefinementClass) sym.info.normalize // I think this is okay, but see #1241 (r12414), #2208, and typedTypeConstructor in Typers else super.normalizeImpl @@ -1872,7 +1872,7 @@ trait Types extends api.Types { self: SymbolTable => if (sym == clazz) this else transform(sym.info.baseType(clazz)) } - + trait NonClassTypeRef extends TypeRef { require(sym.isNonClassType, sym) @@ -1891,11 +1891,11 @@ trait Types extends api.Types { self: SymbolTable => } relativeInfoCache } - + override def baseType(clazz: Symbol): Type = if (sym == clazz) this else baseTypeOfNonClassTypeRef(this, clazz) } - + protected def baseTypeOfNonClassTypeRef(tpe: NonClassTypeRef, clazz: Symbol) = try { basetypeRecursions += 1 if (basetypeRecursions < LogPendingBaseTypesThreshold) @@ -1912,7 +1912,7 @@ trait Types extends api.Types { self: SymbolTable => } finally { basetypeRecursions -= 1 } - + trait AliasTypeRef extends NonClassTypeRef { require(sym.isAliasType, sym) @@ -1930,7 +1930,7 @@ trait Types extends api.Types { self: SymbolTable => if (typeParamsMatchArgs) betaReduce.normalize else if (isHigherKinded) super.normalizeImpl else ErrorType - + // isHKSubType0 introduces synthetic type params so that // betaReduce can first apply sym.info to typeArgs before calling // asSeenFrom. asSeenFrom then skips synthetic type params, which @@ -1940,7 +1940,7 @@ trait Types extends api.Types { self: SymbolTable => // this crashes pos/depmet_implicit_tpbetareduce.scala // appliedType(sym.info, typeArgs).asSeenFrom(pre, sym.owner) def betaReduce = transform(sym.info.resultType) - + // #3731: return sym1 for which holds: pre bound sym.name to sym and // pre1 now binds sym.name to sym1, conceptually exactly the same // symbol as sym. The selection of sym on pre must be updated to the @@ -1954,12 +1954,12 @@ trait Types extends api.Types { self: SymbolTable => // TODO: is there another way a typeref's symbol can refer to a symbol defined in its pre? case _ => sym } - + } trait AbstractTypeRef extends NonClassTypeRef { require(sym.isAbstractType, sym) - + /** Syncnote: Pure performance caches; no need to synchronize in multi-threaded environment */ private var symInfoCache: Type = _ @@ -1988,7 +1988,7 @@ trait Types extends api.Types { self: SymbolTable => volatileRecursions -= 1 } } - + override def thisInfo = { val symInfo = sym.info if (thisInfoCache == null || (symInfo ne symInfoCache)) { @@ -2021,7 +2021,7 @@ trait Types extends api.Types { self: SymbolTable => private[reflect] var parentsPeriod = NoPeriod private[reflect] var baseTypeSeqCache: BaseTypeSeq = _ private[reflect] var baseTypeSeqPeriod = NoPeriod - private var normalized: Type = _ + private var normalized: Type = _ // @M: propagate actual type params (args) to `tp`, by replacing // formal type parameters with actual ones. If tp is higher kinded, @@ -2043,7 +2043,7 @@ trait Types extends api.Types { self: SymbolTable => normalized } } - + def etaExpand: Type = { // must initialise symbol, see test/files/pos/ticket0137.scala val tpars = initializedTypeParams @@ -2097,12 +2097,12 @@ trait Types extends api.Types { self: SymbolTable => } thisInfo.decls } - + protected[Types] def baseTypeSeqImpl: BaseTypeSeq = sym.info.baseTypeSeq map transform override def baseTypeSeq: BaseTypeSeq = { val cache = baseTypeSeqCache - if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq) + if (baseTypeSeqPeriod == currentPeriod && cache != null && cache != undetBaseTypeSeq) cache else { defineBaseTypeSeqOfTypeRef(this) @@ -2196,7 +2196,7 @@ trait Types extends api.Types { self: SymbolTable => } }) } - + protected def defineParentsOfTypeRef(tpe: TypeRef) = { val period = tpe.parentsPeriod if (period != currentPeriod) { @@ -2208,7 +2208,7 @@ trait Types extends api.Types { self: SymbolTable => } } } - + protected def defineBaseTypeSeqOfTypeRef(tpe: TypeRef) = { val period = tpe.baseTypeSeqPeriod if (period != currentPeriod) { @@ -2368,7 +2368,7 @@ trait Types extends api.Types { self: SymbolTable => } object PolyType extends PolyTypeExtractor - + /** A creator for existential types which flattens nested existentials. */ def newExistentialType(quantified: List[Symbol], underlying: Type): Type = @@ -2571,7 +2571,7 @@ trait Types extends api.Types { self: SymbolTable => else if (args.isEmpty) new HKTypeVar(origin, constr, params) else throw new Error("Invalid TypeVar construction: " + ((origin, constr, args, params))) ) - + trace("create", "In " + tv.originLocation)(tv) } } @@ -2612,7 +2612,7 @@ trait Types extends api.Types { self: SymbolTable => override def isHigherKinded = true override protected def typeVarString = params.map(_.name).mkString("[", ", ", "]=>" + originName) } - + /** Precondition: zipped params/args nonEmpty. (Size equivalence enforced structurally.) */ class AppliedTypeVar( @@ -2620,17 +2620,17 @@ trait Types extends api.Types { self: SymbolTable => _constr: TypeConstraint, zippedArgs: List[(Symbol, Type)] ) extends TypeVar(_origin, _constr) { - + require(zippedArgs.nonEmpty, this) override def params: List[Symbol] = zippedArgs map (_._1) override def typeArgs: List[Type] = zippedArgs map (_._2) - + override protected def typeVarString = ( zippedArgs map { case (p, a) => p.name + "=" + a } mkString (origin + "[", ", ", "]") ) } - + /** A class representing a type variable: not used after phase `typer`. * * A higher-kinded TypeVar has params (Symbols) and typeArgs (Types). @@ -2648,7 +2648,7 @@ trait Types extends api.Types { self: SymbolTable => override def typeArgs: List[Type] = Nil override def isHigherKinded = false - /** The constraint associated with the variable + /** The constraint associated with the variable * Syncnote: Type variables are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of `constr` @@ -2659,7 +2659,7 @@ trait Types extends api.Types { self: SymbolTable => /** The variable's skolemization level */ val level = skolemizationLevel - + /** Two occurrences of a higher-kinded typevar, e.g. `?CC[Int]` and `?CC[String]`, correspond to * ''two instances'' of `TypeVar` that share the ''same'' `TypeConstraint`. * @@ -2690,7 +2690,7 @@ trait Types extends api.Types { self: SymbolTable => // inference may generate several TypeVar's for a single type parameter that must be inferred, // only one of them is in the set of tvars that need to be solved, but // they share the same TypeConstraint instance - + // When comparing to types containing skolems, remember the highest level // of skolemization. If that highest level is higher than our initial // skolemizationLevel, we can't re-use those skolems as the solution of this @@ -2914,7 +2914,7 @@ trait Types extends api.Types { self: SymbolTable => def originLocation = { val sym = origin.typeSymbolDirect val encl = sym.owner.logicallyEnclosingMember - + // This should display somewhere between one and three // things which enclose the origin: at most, a class, a // a method, and a term. At least, a class. @@ -3258,8 +3258,8 @@ trait Types extends api.Types { self: SymbolTable => */ object GenPolyType { def apply(tparams: List[Symbol], tpe: Type): Type = - if (tparams nonEmpty) typeFun(tparams, tpe) - else tpe // it's okay to be forgiving here + if (tparams nonEmpty) typeFun(tparams, tpe) + else tpe // it's okay to be forgiving here def unapply(tpe: Type): Option[(List[Symbol], Type)] = tpe match { case PolyType(tparams, restpe) => Some(tparams, restpe) case _ => Some(List(), tpe) @@ -3351,7 +3351,7 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } - + /** Type with all top-level occurrences of abstract types replaced by their bounds */ def abstractTypesToBounds(tp: Type): Type = tp match { // @M don't normalize here (compiler loops on pos/bug1090.scala ) case TypeRef(_, sym, _) if sym.isAbstractType => @@ -3461,7 +3461,7 @@ trait Types extends api.Types { self: SymbolTable => def this(lo0: List[Type], hi0: List[Type]) = this(lo0, hi0, NoType, NoType) def this(bounds: TypeBounds) = this(List(bounds.lo), List(bounds.hi)) def this() = this(List(), List()) - + /* Syncnote: Type constraints are assumed to be used from only one * thread. They are not exposed in api.Types and are used only locally * in operations that are exposed from types. Hence, no syncing of any @@ -3561,7 +3561,7 @@ trait Types extends api.Types { self: SymbolTable => override def variance = _variance def variance_=(x: Int) = _variance = x - + override protected def noChangeToSymbols(origSyms: List[Symbol]) = { origSyms forall { sym => val v = variance @@ -3727,7 +3727,7 @@ trait Types extends api.Types { self: SymbolTable => protected def mapOverArgs(args: List[Type], tparams: List[Symbol]): List[Type] = args mapConserve this - + /** Called by mapOver to determine whether the original symbols can * be returned, or whether they must be cloned. Overridden in VariantTypeMap. */ @@ -3741,7 +3741,7 @@ trait Types extends api.Types { self: SymbolTable => if (elems1 eq elems) scope else newScopeWith(elems1: _*) } - + /** Map this function over given list of symbols */ def mapOver(origSyms: List[Symbol]): List[Symbol] = { // fast path in case nothing changes due to map @@ -3804,7 +3804,7 @@ trait Types extends api.Types { self: SymbolTable => def traverse(tp: Type): Unit def apply(tp: Type): Type = { traverse(tp); tp } } - + abstract class TypeTraverserWithResult[T] extends TypeTraverser { def result: T def clear(): Unit @@ -3824,13 +3824,13 @@ trait Types extends api.Types { self: SymbolTable => */ // class ContainsVariantExistentialCollector(v: Int) extends TypeCollector(false) with VariantTypeMap { // variance = v - // + // // def traverse(tp: Type) = tp match { // case ExistentialType(_, _) if (variance == v) => result = true // case _ => mapOver(tp) // } // } - // + // // val containsCovariantExistentialCollector = new ContainsVariantExistentialCollector(1) // val containsContravariantExistentialCollector = new ContainsVariantExistentialCollector(-1) @@ -3884,7 +3884,7 @@ trait Types extends api.Types { self: SymbolTable => mapOver(tp) } } - + /** Used by existentialAbstraction. */ class ExistentialExtrapolation(tparams: List[Symbol]) extends VariantTypeMap { @@ -3902,10 +3902,10 @@ trait Types extends api.Types { self: SymbolTable => countOccs(tpe) for (tparam <- tparams) countOccs(tparam.info) - + apply(tpe) } - + def apply(tp: Type): Type = { val tp1 = mapOver(tp) if (variance == 0) tp1 @@ -4484,12 +4484,12 @@ trait Types extends api.Types { self: SymbolTable => result } } - + protected def commonOwnerMap: CommonOwnerMap = commonOwnerMapObj - + protected class CommonOwnerMap extends TypeTraverserWithResult[Symbol] { var result: Symbol = _ - + def clear() { result = null } private def register(sym: Symbol) { @@ -4507,7 +4507,7 @@ trait Types extends api.Types { self: SymbolTable => case _ => mapOver(tp) } } - + private lazy val commonOwnerMapObj = new CommonOwnerMap class MissingAliasControl extends ControlThrowable @@ -4515,7 +4515,7 @@ trait Types extends api.Types { self: SymbolTable => class MissingTypeControl extends ControlThrowable object adaptToNewRunMap extends TypeMap { - + private def adaptToNewRun(pre: Type, sym: Symbol): Symbol = { if (phase.flatClasses) { sym @@ -4682,7 +4682,7 @@ trait Types extends api.Types { self: SymbolTable => case (TypeRef(pre1, sym1, args1), TypeRef(pre2, sym2, args2)) => assert(sym1 == sym2) pre1 =:= pre2 && - forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => + forall3(args1, args2, sym1.typeParams) { (arg1, arg2, tparam) => //if (tparam.variance == 0 && !(arg1 =:= arg2)) Console.println("inconsistent: "+arg1+"!="+arg2)//DEBUG if (tparam.variance == 0) arg1 =:= arg2 else if (arg1.isInstanceOf[TypeVar]) @@ -5692,8 +5692,8 @@ trait Types extends api.Types { self: SymbolTable => val formatted = tableDef.table(transposed) println("** Depth is " + depth + "\n" + formatted) } - - /** From a list of types, find any which take type parameters + + /** From a list of types, find any which take type parameters * where the type parameter bounds contain references to other * any types in the list (including itself.) * @@ -6212,13 +6212,13 @@ trait Types extends api.Types { self: SymbolTable => if (ts exists (_.isNotNull)) res.notNull else res } - + /** A list of the typevars in a type. */ def typeVarsInType(tp: Type): List[TypeVar] = { var tvs: List[TypeVar] = Nil tp foreach { case t: TypeVar => tvs ::= t - case _ => + case _ => } tvs.reverse } @@ -6230,7 +6230,7 @@ trait Types extends api.Types { self: SymbolTable => // !!! Is it somehow guaranteed that this will not break under nesting? // In general one has to save and restore the contents of the field... tvs foreach (_.suspended = true) - tvs + tvs } /** Compute lub (if `variance == 1`) or glb (if `variance == -1`) of given list @@ -6460,5 +6460,5 @@ trait Types extends api.Types { self: SymbolTable => } finally { tostringRecursions -= 1 } - + } diff --git a/src/compiler/scala/reflect/runtime/JavaToScala.scala b/src/compiler/scala/reflect/runtime/JavaToScala.scala index 3b805804a0..813c66e1f0 100644 --- a/src/compiler/scala/reflect/runtime/JavaToScala.scala +++ b/src/compiler/scala/reflect/runtime/JavaToScala.scala @@ -354,7 +354,7 @@ trait JavaToScala extends ConversionUtil { self: SymbolTable => def classToScala(jclazz: jClass[_]): Symbol = classCache.toScala(jclazz) { val jname = javaTypeName(jclazz) def lookup = sOwner(jclazz).info.decl(newTypeName(jclazz.getSimpleName)) - + if (jclazz.isMemberClass && !nme.isImplClassName(jname)) { val sym = lookup assert(sym.isType, sym+"/"+jclazz+"/"+sOwner(jclazz)+"/"+jclazz.getSimpleName) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 8026e92a21..c63070b18f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -152,7 +152,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Register top level class (called on entering the class) */ def registerTopLevelSym(sym: Symbol) {} - + // ------------------ Reporting ------------------------------------- // not deprecated yet, but a method called "error" imported into @@ -709,18 +709,18 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb private lazy val unitTimings = mutable.HashMap[CompilationUnit, Long]() withDefaultValue 0L // tracking time spent per unit private def unitTimingsFormatted(): String = { def toMillis(nanos: Long) = "%.3f" format nanos / 1000000d - + val formatter = new util.TableDef[(String, String)] { >> ("ms" -> (_._1)) >+ " " << ("path" -> (_._2)) } "" + ( - new formatter.Table(unitTimings.toList sortBy (-_._2) map { + new formatter.Table(unitTimings.toList sortBy (-_._2) map { case (unit, nanos) => (toMillis(nanos), unit.source.path) }) ) } - + protected def addToPhasesSet(sub: SubComponent, descr: String) { phasesSet += sub phasesDescMap(sub) = descr @@ -867,7 +867,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** Counts for certain classes of warnings during this run. */ var deprecationWarnings: List[(Position, String)] = Nil var uncheckedWarnings: List[(Position, String)] = Nil - + /** A flag whether macro expansions failed */ var macroExpansionFailed = false @@ -1014,7 +1014,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb } def cancel() { reporter.cancelled = true } - + private def currentProgress = (phasec * size) + unitc private def totalProgress = (phaseDescriptors.size - 1) * size // -1: drops terminal phase private def refreshProgress() = if (size > 0) progress(currentProgress, totalProgress) @@ -1181,12 +1181,12 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb */ def compileUnits(units: List[CompilationUnit], fromPhase: Phase) { try compileUnitsInternal(units, fromPhase) - catch { case ex => + catch { case ex => globalError(supplementErrorMessage("uncaught exception during compilation: " + ex.getClass.getName)) throw ex } } - + private def compileUnitsInternal(units: List[CompilationUnit], fromPhase: Phase) { units foreach addUnit if (opt.profileAll) { diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index c3e156104f..eb7c5a6699 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -292,8 +292,8 @@ self => } private lazy val primitiveNames: Set[Name] = tpnme.ScalaValueNames.toSet - private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" - private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array + private def inScalaRootPackage = inScalaPackage && currentPackage == "scala" + private def isScalaArray(name: Name) = inScalaRootPackage && name == tpnme.Array private def isPrimitiveType(name: Name) = inScalaRootPackage && primitiveNames(name) def parseStartRule: () => Tree diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 7aa3e77471..a0826c19c3 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -368,7 +368,7 @@ abstract class ClassfileParser { case arr: Type => Constant(arr) } } - + private def getSubArray(bytes: Array[Byte]): Array[Byte] = { val decodedLength = ByteCodecs.decode(bytes) val arr = new Array[Byte](decodedLength) @@ -719,7 +719,7 @@ abstract class ClassfileParser { index += 1 val bounds = variance match { case '+' => TypeBounds.upper(objToAny(sig2type(tparams, skiptvs))) - case '-' => + case '-' => val tp = sig2type(tparams, skiptvs) // sig2type seems to return AnyClass regardless of the situation: // we don't want Any as a LOWER bound. diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 6b7e34cf49..30bfdbaf5b 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -956,8 +956,8 @@ abstract class Erasure extends AddInterfaces } else if (fn.symbol.owner.isInlineClass && extensionMethods.hasExtension(fn.symbol)) { Apply(gen.mkAttributedRef(extensionMethods.extensionMethod(fn.symbol)), qualifier :: args) } else { - tree - } + tree + } case Select(qual, name) => val owner = tree.symbol.owner diff --git a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala index 35edf19a41..712298bd89 100644 --- a/src/compiler/scala/tools/nsc/transform/LambdaLift.scala +++ b/src/compiler/scala/tools/nsc/transform/LambdaLift.scala @@ -18,7 +18,7 @@ abstract class LambdaLift extends InfoTransform { /** the following two members override abstract members in Transform */ val phaseName: String = "lambdalift" - + /** Converts types of captured variables to *Ref types. */ def boxIfCaptured(sym: Symbol, tpe: Type, erasedTypes: Boolean) = @@ -72,10 +72,10 @@ abstract class LambdaLift extends InfoTransform { /** Buffers for lifted out classes and methods */ private val liftedDefs = new LinkedHashMap[Symbol, List[Tree]] - + /** True if we are transforming under a ReferenceToBoxed node */ private var isBoxedRef = false - + private type SymSet = TreeSet[Symbol] private def newSymSet = new TreeSet[Symbol](_ isLess _) @@ -213,7 +213,7 @@ abstract class LambdaLift extends InfoTransform { for (caller <- called.keys ; callee <- called(caller) ; fvs <- free get callee ; fv <- fvs) markFree(fv, caller) } while (changedFreeVars) - + def renameSym(sym: Symbol) { val originalName = sym.name val base = sym.name + nme.NAME_JOIN_STRING + ( @@ -404,10 +404,10 @@ abstract class LambdaLift extends InfoTransform { def refConstr(expr: Tree): Tree = expr match { case Try(block, catches, finalizer) => Try(refConstr(block), catches map refConstrCase, finalizer) - case _ => + case _ => Apply(Select(New(TypeTree(sym.tpe)), nme.CONSTRUCTOR), List(expr)) } - def refConstrCase(cdef: CaseDef): CaseDef = + def refConstrCase(cdef: CaseDef): CaseDef = CaseDef(cdef.pat, cdef.guard, refConstr(cdef.body)) treeCopy.ValDef(tree, mods, name, tpt1, typer.typedPos(rhs.pos) { refConstr(constructorArg) @@ -452,7 +452,7 @@ abstract class LambdaLift extends InfoTransform { tree } } - + private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe) override def transform(tree: Tree): Tree = tree match { @@ -461,7 +461,7 @@ abstract class LambdaLift extends InfoTransform { case _ => postTransform(preTransform(tree)) } - + /** Transform statements and add lifted definitions to them. */ override def transformStats(stats: List[Tree], exprOwner: Symbol): List[Tree] = { def addLifted(stat: Tree): Tree = stat match { diff --git a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala index 422b1b7b7d..7d49c98dfb 100644 --- a/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala +++ b/src/compiler/scala/tools/nsc/transform/SpecializeTypes.scala @@ -74,7 +74,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { AnyRefClass, ObjectClass, Predef_AnyRef, uncheckedVarianceClass } - + /** TODO - this is a lot of maps. */ @@ -494,7 +494,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { def cloneInSpecializedClass(member: Symbol, flagFn: Long => Long) = member.cloneSymbol(sClass, flagFn(member.flags | SPECIALIZED)) - + sClass.sourceFile = clazz.sourceFile currentRun.symSource(sClass) = clazz.sourceFile // needed later on by mixin @@ -1197,7 +1197,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { } else NoSymbol def illegalSpecializedInheritance(clazz: Symbol): Boolean = ( - hasSpecializedFlag(clazz) + hasSpecializedFlag(clazz) && originalClass(clazz).parentSymbols.exists(p => hasSpecializedParams(p) && !p.isTrait) ) @@ -1261,7 +1261,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { val specMember = specCandidates suchThat { s => doesConform(symbol, tree.tpe, qual.tpe.memberType(s), env) } - + log("[specSym] found: " + specCandidates.tpe + ", instantiated as: " + tree.tpe) log("[specSym] found specMember: " + specMember) if (specMember ne NoSymbol) @@ -1378,7 +1378,7 @@ abstract class SpecializeTypes extends InfoTransform with TypingTransformers { (new CollectMethodBodies)(tree) val parents1 = map2(currentOwner.info.parents, parents)((tpe, parent) => TypeTree(tpe) setPos parent.pos) - + treeCopy.Template(tree, parents1 /*currentOwner.info.parents.map(tpe => TypeTree(tpe) setPos parents.head.pos)*/ , self, diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 685dce213c..68bc80ffc4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -31,14 +31,14 @@ trait ContextErrors { case class NormalTypeError(underlyingTree: Tree, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError { - + def errPos:Position = underlyingTree.pos override def toString() = "[Type error at:" + underlyingTree.pos + "] " + errMsg } case class SymbolTypeError(underlyingSym: Symbol, errMsg: String, kind: ErrorKind = ErrorKinds.Normal) extends AbsTypeError { - + def errPos = underlyingSym.pos } @@ -76,7 +76,7 @@ trait ContextErrors { } def issueTypeError(err: AbsTypeError)(implicit context: Context) { context.issue(err) } - + def typeErrorMsg(found: Type, req: Type, possiblyMissingArgs: Boolean) = { def missingArgsMsg = if (possiblyMissingArgs) "\n possible cause: missing arguments for method or constructor" else "" "type mismatch" + foundReqMsg(found, req) + missingArgsMsg @@ -177,13 +177,13 @@ trait ContextErrors { val calcSimilar = ( name.length > 2 && ( startingIdentCx.reportErrors - || startingIdentCx.enclClassOrMethod.reportErrors + || startingIdentCx.enclClassOrMethod.reportErrors ) ) - // avoid calculating if we're in "silent" mode. - // name length check to limit unhelpful suggestions for e.g. "x" and "b1" + // avoid calculating if we're in "silent" mode. + // name length check to limit unhelpful suggestions for e.g. "x" and "b1" val similar = { - if (!calcSimilar) "" + if (!calcSimilar) "" else { val allowed = ( startingIdentCx.enclosingContextChain @@ -636,8 +636,8 @@ trait ContextErrors { def CyclicReferenceError(errPos: Position, lockedSym: Symbol) = issueTypeError(PosAndMsgTypeError(errPos, "illegal cyclic reference involving " + lockedSym)) - - def MacroExpandError(tree: Tree, t: Any) = { + + def MacroExpandError(tree: Tree, t: Any) = { issueNormalTypeError(tree, "macros must return a compiler-specific tree; returned class is: " + t.getClass) setError(tree) } @@ -667,7 +667,7 @@ trait ContextErrors { type ErrorType = Value val WrongNumber, NoParams, ArgsDoNotConform = Value } - + private def ambiguousErrorMsgPos(pos: Position, pre: Type, sym1: Symbol, sym2: Symbol, rest: String) = if (sym1.hasDefaultFlag && sym2.hasDefaultFlag && sym1.enclClass == sym2.enclClass) { val methodName = nme.defaultGetterToMethod(sym1.name) @@ -830,14 +830,14 @@ trait ContextErrors { object NamerErrorGen { implicit val context0 = context - + object SymValidateErrors extends Enumeration { val ImplicitConstr, ImplicitNotTerm, ImplicitTopObject, OverrideClass, SealedNonClass, AbstractNonClass, OverrideConstr, AbstractOverride, LazyAndEarlyInit, ByNameParameter, AbstractVar = Value } - + object DuplicatesErrorKinds extends Enumeration { val RenamedTwice, AppearsTwice = Value } @@ -845,7 +845,7 @@ trait ContextErrors { import SymValidateErrors._ import DuplicatesErrorKinds._ import symtab.Flags - + def TypeSigError(tree: Tree, ex: TypeError) = { ex match { case CyclicReference(sym, info: TypeCompleter) => @@ -854,7 +854,7 @@ trait ContextErrors { context0.issue(TypeErrorWithUnderlyingTree(tree, ex)) } } - + def GetterDefinedTwiceError(getter: Symbol) = issueSymbolTypeError(getter, getter+" is defined twice") @@ -897,37 +897,37 @@ trait ContextErrors { val msg = errKind match { case ImplicitConstr => "`implicit' modifier not allowed for constructors" - + case ImplicitNotTerm => "`implicit' modifier can be used only for values, variables and methods" - + case ImplicitTopObject => "`implicit' modifier cannot be used for top-level objects" - + case OverrideClass => "`override' modifier not allowed for classes" - + case SealedNonClass => "`sealed' modifier can be used only for classes" - + case AbstractNonClass => "`abstract' modifier can be used only for classes; it should be omitted for abstract members" - + case OverrideConstr => "`override' modifier not allowed for constructors" - + case AbstractOverride => "`abstract override' modifier only allowed for members of traits" - + case LazyAndEarlyInit => "`lazy' definitions may not be initialized early" - + case ByNameParameter => "pass-by-name arguments not allowed for case class parameters" - + case AbstractVar => "only classes can have declared but undefined members" + abstractVarMessage(sym) - + } issueSymbolTypeError(sym, msg) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 1c40675508..b9f3adec75 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -113,7 +113,7 @@ trait Namers extends MethodSynthesis { private def contextFile = context.unit.source.file private def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = { case ex: TypeError => - // H@ need to ensure that we handle only cyclic references + // H@ need to ensure that we handle only cyclic references TypeSigError(tree, ex) alt } @@ -296,7 +296,7 @@ trait Namers extends MethodSynthesis { val pos = tree.pos val isParameter = tree.mods.isParameter val flags = tree.mods.flags & mask - + tree match { case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(name.toTypeName, pos, flags) case TypeDef(_, _, _, _) => owner.newTypeSymbol(name.toTypeName, pos, flags) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index d492ba3662..4449116fd1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -686,13 +686,13 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R } else if (clazz.isTrait) { // prevent abstract methods in interfaces that override final members in Object; see #4431 if (!(clazz isSubClass AnyValClass)) { - for (decl <- clazz.info.decls.iterator) { - val overridden = decl.overriddenSymbol(ObjectClass) - if (overridden.isFinal) - unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") - } + for (decl <- clazz.info.decls.iterator) { + val overridden = decl.overriddenSymbol(ObjectClass) + if (overridden.isFinal) + unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") } } + } /** Returns whether there is a symbol declared in class `inclazz` * (which must be different from `clazz`) whose name and type diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7c16c7642d..b6f555e42a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -154,7 +154,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ErrorType => fun } - + def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = inferView(tree, from, to, reportAmbiguous, true) @@ -274,7 +274,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } tp match { case TypeRef(pre, sym, args) => - checkNotLocked(sym) && + checkNotLocked(sym) && ((!sym.isNonClassType) || checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym)) // @M! info for a type ref to a type parameter now returns a polytype // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym) @@ -939,7 +939,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { adaptType() else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef) { val tree1 = expandMacro(tree) - if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) + if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) adaptConstrPattern() else if (inAllModes(mode, EXPRmode | FUNmode) && @@ -1084,7 +1084,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // Note: implicit arguments are still inferred (this kind of "chaining" is allowed) ) } - + def adaptToMember(qual: Tree, searchTemplate: Type): Tree = adaptToMember(qual, searchTemplate, true, true) def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree = @@ -1099,12 +1099,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match { case EmptyTree => qual - case coercion => + case coercion => if (settings.logImplicitConv.value) unit.echo(qual.pos, "applied implicit conversion from %s to %s = %s".format( qual.tpe, searchTemplate, coercion.symbol.defString)) - + typedQualifier(atPos(qual.pos)(new ApplyImplicitView(coercion, List(qual)))) } } @@ -2889,10 +2889,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else existentialTransform(hidden, tp)(existentialAbstraction) - + def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = - ctx.owner.isTerm && - (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || + ctx.owner.isTerm && + (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || { var ctx1 = ctx.outer while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer @@ -3879,7 +3879,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { reallyExists(sym) && ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.hasFlag(ACCESSOR)) } - + if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -4370,7 +4370,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ReferenceToBoxed(idt @ Ident(_)) => val id1 = typed1(idt, mode, pt) match { case id: Ident => id } - treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe + treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe case Literal(value) => tree setType ( diff --git a/src/library/scala/Byte.scala b/src/library/scala/Byte.scala index beff5ce208..f9c5f6003e 100644 --- a/src/library/scala/Byte.scala +++ b/src/library/scala/Byte.scala @@ -30,7 +30,7 @@ final class Byte extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Byte extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Byte extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Byte extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Byte extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Byte extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Byte extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ diff --git a/src/library/scala/Char.scala b/src/library/scala/Char.scala index dade572396..3d459782cd 100644 --- a/src/library/scala/Char.scala +++ b/src/library/scala/Char.scala @@ -30,7 +30,7 @@ final class Char extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Char extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Char extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Char extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Char extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Char extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Char extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ diff --git a/src/library/scala/Int.scala b/src/library/scala/Int.scala index 6b7debf2df..316bbced2d 100644 --- a/src/library/scala/Int.scala +++ b/src/library/scala/Int.scala @@ -30,7 +30,7 @@ final class Int extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Int extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Int extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Int extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Int extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Int extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Int extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ diff --git a/src/library/scala/Long.scala b/src/library/scala/Long.scala index e734c92112..ce8618c22a 100644 --- a/src/library/scala/Long.scala +++ b/src/library/scala/Long.scala @@ -30,7 +30,7 @@ final class Long extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Long extends AnyVal { def <<(x: Long): Long = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Long = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Long extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Long extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Long extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Long extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Long extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ diff --git a/src/library/scala/Short.scala b/src/library/scala/Short.scala index 98e227d992..5664c3b44c 100644 --- a/src/library/scala/Short.scala +++ b/src/library/scala/Short.scala @@ -30,7 +30,7 @@ final class Short extends AnyVal { * @return the bitwise negation of this value * @example {{{ * ~5 == -6 - * // in binary: ~00000101 == + * // in binary: ~00000101 == * // 11111010 * }}} */ @@ -60,22 +60,22 @@ final class Short extends AnyVal { def <<(x: Long): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ def >>>(x: Int): Int = sys.error("stub") /** * @return this value bit-shifted right by the specified number of bits, - * filling the new left bits with zeroes. + * filling the new left bits with zeroes. * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}} * @example {{{ - * -21 >>> 3 == 536870909 - * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == + * -21 >>> 3 == 536870909 + * // in binary: 11111111 11111111 11111111 11101011 >>> 3 == * // 00011111 11111111 11111111 11111101 * }}} */ @@ -85,8 +85,8 @@ final class Short extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -96,8 +96,8 @@ final class Short extends AnyVal { * filling in the right bits with the same value as the left-most bit of this. * The effect of this is to retain the sign of the value. * @example {{{ - * -21 >> 3 == -3 - * // in binary: 11111111 11111111 11111111 11101011 >> 3 == + * -21 >> 3 == -3 + * // in binary: 11111111 11111111 11111111 11101011 >> 3 == * // 11111111 11111111 11111111 11111101 * }}} */ @@ -281,9 +281,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -292,9 +292,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -303,9 +303,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -314,9 +314,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -325,9 +325,9 @@ final class Short extends AnyVal { * @return the bitwise OR of this value and x * @example {{{ * (0xf0 | 0xaa) == 0xfa - * // in binary: 11110000 - * // | 10101010 - * // -------- + * // in binary: 11110000 + * // | 10101010 + * // -------- * // 11111010 * }}} */ @@ -337,9 +337,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -348,9 +348,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -359,9 +359,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -370,9 +370,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -381,9 +381,9 @@ final class Short extends AnyVal { * @return the bitwise AND of this value and x * @example {{{ * (0xf0 & 0xaa) == 0xa0 - * // in binary: 11110000 - * // & 10101010 - * // -------- + * // in binary: 11110000 + * // & 10101010 + * // -------- * // 10100000 * }}} */ @@ -393,9 +393,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -404,9 +404,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -415,9 +415,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -426,9 +426,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ @@ -437,9 +437,9 @@ final class Short extends AnyVal { * @return the bitwise XOR of this value and x * @example {{{ * (0xf0 ^ 0xaa) == 0x5a - * // in binary: 11110000 - * // ^ 10101010 - * // -------- + * // in binary: 11110000 + * // ^ 10101010 + * // -------- * // 01011010 * }}} */ -- cgit v1.2.3 From cb952efd2955eb1bf80ae7fb9f6fe2efc465b45f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 30 Jan 2012 12:13:16 -0800 Subject: Synthesize getClass method for AnyVal children. The synthetic method is only a null for now. --- .../scala/tools/nsc/typechecker/SyntheticMethods.scala | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 4ea21b1c44..3ee5bf601d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -47,6 +47,17 @@ trait SyntheticMethods extends ast.TreeDSL { newTyper( if (reporter.hasErrors) context makeSilent false else context ) ) import synthesizer._ + + if (clazz0 isSubClass AnyValClass) return { + if (clazz0.info member nme.getClass_ isDeferred) { + val getClassMethod = createMethod(nme.getClass_, getClassReturnType(clazz.tpe)) { sym => + // XXX dummy implementation for now + NULL + } + treeCopy.Template(templ, templ.parents, templ.self, templ.body :+ getClassMethod) + } + else templ + } val originalAccessors = clazz.caseFieldAccessors // private ones will have been renamed -- make sure they are entered -- cgit v1.2.3 From a9eb9c5b69071a944d2a5225aa320babdf33ad42 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Mon, 30 Jan 2012 12:42:26 -0800 Subject: More work on inline classes. Fail compile if AnyVal is inherited by a trait, a non-@inline class, or a class with an AnyRef parent somewhere. Added tests. Added logging, like [log extmethods] Inline class class Bippy spawns extension method. Old: def getClass: Class[_ <: Bippy] New: final def extension$getClass($this: Bippy): Class[_ <: Bippy] Fixed what I hope was a bug in ExtensionMethods where the original method params were dropped. Since adding a NonNull parent was also inflicting an AnyRef on AnyVal subclasses, suppressed that for those. Had the bright idea that AnyVal could extend NotNull. It doesn't seem to accomplish much, but then, I don't think NotNull accomplishes much. Still, maybe it's time to restrict the ways one can use AnyVal so one can't do this: scala> var x: AnyVal = _ x: AnyVal = null --- .../scala/reflect/internal/Definitions.scala | 8 ++++++- .../scala/tools/nsc/ast/parser/Parsers.scala | 2 +- .../tools/nsc/transform/ExtensionMethods.scala | 13 ++++++++--- .../scala/tools/nsc/typechecker/Namers.scala | 6 +++-- .../scala/tools/nsc/typechecker/RefChecks.scala | 23 +++++++++++++++---- src/library/scala/AnyVal.scala | 2 +- src/library/scala/NotNull.scala | 2 -- test/files/neg/anyval-children-2.check | 4 ++++ test/files/neg/anyval-children-2.scala | 1 + test/files/neg/anyval-children.check | 26 ++++++++++++++++++++++ test/files/neg/anyval-children.scala | 14 ++++++++++++ test/files/pos/anyval-children.scala | 2 +- 12 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 test/files/neg/anyval-children-2.check create mode 100644 test/files/neg/anyval-children-2.scala create mode 100644 test/files/neg/anyval-children.check create mode 100644 test/files/neg/anyval-children.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index f8342444c8..ce0505bf44 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -910,6 +910,12 @@ trait Definitions extends reflect.api.StandardDefinitions { private lazy val scalaValueClassesSet = ScalaValueClasses.toSet private lazy val boxedValueClassesSet = boxedClass.values.toSet + BoxedUnitClass + /** Now that AnyVal is unsealing we need less ambiguous names + * for when we need to distinguish the Nine Original AnyVals + * from the heathen masses. + */ + def isPrimitiveValueClass(sym: Symbol) = scalaValueClassesSet(sym) + /** Is symbol a value class? */ def isValueClass(sym: Symbol) = scalaValueClassesSet(sym) def isNonUnitValueClass(sym: Symbol) = (sym != UnitClass) && isValueClass(sym) @@ -1029,7 +1035,7 @@ trait Definitions extends reflect.api.StandardDefinitions { /** Removing the anyref parent they acquire from having a source file. */ - setParents(AnyValClass, anyparam) + setParents(AnyValClass, List(NotNullClass.tpe, AnyClass.tpe)) ScalaValueClasses foreach { sym => setParents(sym, anyvalparam) } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index eb7c5a6699..3ee8b62bc6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2757,7 +2757,7 @@ self => Template(List(scalaDot(tpnme.AnyVal)), self, body) } else if (parents0 exists isReferenceToAnyVal) { - // TODO - enforce @inline annotation, and no other parents + // @inline and other restrictions enforced in refchecks Template(parents0, self, body) } else if (name == tpnme.AnyVal) { diff --git a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala index 5f62dfab39..c308a3633e 100644 --- a/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala +++ b/src/compiler/scala/tools/nsc/transform/ExtensionMethods.scala @@ -84,10 +84,11 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { def extensionMethInfo(extensionMeth: Symbol, origInfo: Type, clazz: Symbol): Type = { var newTypeParams = cloneSymbolsAtOwner(clazz.typeParams, extensionMeth) val thisParamType = appliedType(clazz.typeConstructor, newTypeParams map (_.tpe)) - val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType + val thisParam = extensionMeth.newValueParameter(nme.SELF, extensionMeth.pos) setInfo thisParamType def transform(clonedType: Type): Type = clonedType match { case MethodType(params, restpe) => - MethodType(List(thisParam), clonedType) + // I assume it was a bug that this was dropping params... + MethodType(thisParam :: params, clonedType) case NullaryMethodType(restpe) => MethodType(List(thisParam), restpe) } @@ -116,7 +117,13 @@ abstract class ExtensionMethods extends Transform with TypingTransformers { val extensionMeth = companion.moduleClass.newMethod(extensionName, origMeth.pos, origMeth.flags & ~OVERRIDE | FINAL) .setAnnotations(origMeth.annotations) companion.info.decls.enter(extensionMeth) - extensionMeth.setInfo(extensionMethInfo(extensionMeth, origMeth.info, currentOwner)) + val newInfo = extensionMethInfo(extensionMeth, origMeth.info, currentOwner) + extensionMeth setInfo newInfo + log("Inline class %s spawns extension method.\n Old: %s\n New: %s".format( + currentOwner, + origMeth.defString, + extensionMeth.defString)) // extensionMeth.defStringSeenAs(origInfo + def thisParamRef = gen.mkAttributedIdent(extensionMeth.info.params.head setPos extensionMeth.pos) val GenPolyType(extensionTpeParams, extensionMono) = extensionMeth.info val origTpeParams = origMeth.typeParams ::: currentOwner.typeParams diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index b9f3adec75..2f31347829 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1407,7 +1407,9 @@ trait Namers extends MethodSynthesis { } if (sym.isClass && sym.hasAnnotation(ScalaInlineClass) && !phase.erasedTypes) { - ensureParent(NotNullClass) + if (!sym.isSubClass(AnyValClass)) + ensureParent(NotNullClass) + sym setFlag FINAL } @@ -1437,7 +1439,7 @@ trait Namers extends MethodSynthesis { checkNoConflict(PRIVATE, PROTECTED) // checkNoConflict(PRIVATE, OVERRIDE) // this one leads to bad error messages like #4174, so catch in refchecks // checkNoConflict(PRIVATE, FINAL) // can't do this because FINAL also means compile-time constant - checkNoConflict(ABSTRACT, FINAL) + // checkNoConflict(ABSTRACT, FINAL) // this one gives a bad error for non-@inline classes which extend AnyVal // @PP: I added this as a sanity check because these flags are supposed to be // converted to ABSOVERRIDE before arriving here. checkNoConflict(ABSTRACT, OVERRIDE) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 4449116fd1..f7a6815905 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -683,16 +683,16 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if (abstractErrors.nonEmpty) unit.error(clazz.pos, abstractErrorMessage) - } else if (clazz.isTrait) { - // prevent abstract methods in interfaces that override final members in Object; see #4431 - if (!(clazz isSubClass AnyValClass)) { + } + else if (clazz.isTrait && !(clazz isSubClass AnyValClass)) { + // For non-AnyVal classes, prevent abstract methods in interfaces that override + // final members in Object; see #4431 for (decl <- clazz.info.decls.iterator) { val overridden = decl.overriddenSymbol(ObjectClass) if (overridden.isFinal) unit.error(decl.pos, "trait cannot redefine final method from class AnyRef") } } - } /** Returns whether there is a symbol declared in class `inclazz` * (which must be different from `clazz`) whose name and type @@ -1527,6 +1527,19 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R ) case _ => () } + + // verify classes extending AnyVal meet the requirements + // (whatever those are to be, but at least: @inline annotation) + private def checkAnyValSubclass(clazz: Symbol) = { + if ((clazz isSubClass AnyValClass) && (clazz ne AnyValClass) && !isPrimitiveValueClass(clazz)) { + if (!clazz.hasAnnotation(ScalaInlineClass)) + unit.error(clazz.pos, "Only @inline classes are allowed to extend AnyVal") + if (clazz.isTrait) + unit.error(clazz.pos, "Only @inline classes (not traits) are allowed to extend AnyVal") + if (clazz.tpe <:< AnyRefClass.tpe) + unit.error(clazz.pos, "Classes which extend AnyVal may not have an ancestor which inherits AnyRef") + } + } override def transform(tree: Tree): Tree = { val savedLocalTyper = localTyper @@ -1562,6 +1575,8 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R checkOverloadedRestrictions(currentOwner) val bridges = addVarargBridges(currentOwner) checkAllOverrides(currentOwner) + checkAnyValSubclass(currentOwner) + if (bridges.nonEmpty) treeCopy.Template(tree, parents, self, body ::: bridges) else tree diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index fb36d61c57..ed32fb7302 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -25,7 +25,7 @@ package scala * The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ -trait AnyVal { +trait AnyVal extends NotNull { // disabled for now to make the standard build go through. // Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. // def getClass(): Class[_ <: AnyVal] = ??? diff --git a/src/library/scala/NotNull.scala b/src/library/scala/NotNull.scala index d47d47a83e..f90b95c789 100644 --- a/src/library/scala/NotNull.scala +++ b/src/library/scala/NotNull.scala @@ -6,8 +6,6 @@ ** |/ ** \* */ - - package scala /** diff --git a/test/files/neg/anyval-children-2.check b/test/files/neg/anyval-children-2.check new file mode 100644 index 0000000000..cb327faeeb --- /dev/null +++ b/test/files/neg/anyval-children-2.check @@ -0,0 +1,4 @@ +anyval-children-2.scala:1: error: Only @inline classes (not traits) are allowed to extend AnyVal +@inline trait NotOkDingus1 extends AnyVal // fail + ^ +one error found diff --git a/test/files/neg/anyval-children-2.scala b/test/files/neg/anyval-children-2.scala new file mode 100644 index 0000000000..4034eb22dd --- /dev/null +++ b/test/files/neg/anyval-children-2.scala @@ -0,0 +1 @@ +@inline trait NotOkDingus1 extends AnyVal // fail diff --git a/test/files/neg/anyval-children.check b/test/files/neg/anyval-children.check new file mode 100644 index 0000000000..cbb5a2b1d1 --- /dev/null +++ b/test/files/neg/anyval-children.check @@ -0,0 +1,26 @@ +anyval-children.scala:7: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait ScalaObject +class NotOkBippy1 extends Bippy // fail + ^ +anyval-children.scala:9: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait Immutable +class NotOkBippy2 extends Bippy with Immutable //fail + ^ +anyval-children.scala:9: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait ScalaObject +class NotOkBippy2 extends Bippy with Immutable //fail + ^ +anyval-children.scala:11: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait Immutable +@inline class NotOkBippy3 extends Bippy with Immutable //fail + ^ +anyval-children.scala:11: error: illegal inheritance; superclass Bippy + is not a subclass of the superclass Object + of the mixin trait ScalaObject +@inline class NotOkBippy3 extends Bippy with Immutable //fail + ^ +5 errors found diff --git a/test/files/neg/anyval-children.scala b/test/files/neg/anyval-children.scala new file mode 100644 index 0000000000..5a6109f786 --- /dev/null +++ b/test/files/neg/anyval-children.scala @@ -0,0 +1,14 @@ +class Bippy extends AnyVal // fail + +@inline class NotOkDingus2 extends Immutable with AnyVal // fail + +@inline object NotOkDingus3 extends AnyVal // fail + +class NotOkBippy1 extends Bippy // fail + +class NotOkBippy2 extends Bippy with Immutable //fail + +@inline class NotOkBippy3 extends Bippy with Immutable //fail + + +@inline class OkBippy extends AnyVal // ok diff --git a/test/files/pos/anyval-children.scala b/test/files/pos/anyval-children.scala index 7a2eda8b3f..4ef10a094f 100644 --- a/test/files/pos/anyval-children.scala +++ b/test/files/pos/anyval-children.scala @@ -1 +1 @@ -class Bippy extends AnyVal \ No newline at end of file +@inline class Bippy extends AnyVal \ No newline at end of file -- cgit v1.2.3 From 5cb688172c86d3f34a4149e8280694f64bbf1422 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 31 Jan 2012 12:32:07 +0100 Subject: New trait for erasure of inline classes. --- src/compiler/scala/tools/nsc/transform/InlineErasure.scala | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/compiler/scala/tools/nsc/transform/InlineErasure.scala (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/transform/InlineErasure.scala b/src/compiler/scala/tools/nsc/transform/InlineErasure.scala new file mode 100644 index 0000000000..0af3cf732f --- /dev/null +++ b/src/compiler/scala/tools/nsc/transform/InlineErasure.scala @@ -0,0 +1,9 @@ +package scala.tools.nsc +package transform + +trait InlineErasure { self: Erasure => + + import global._ + import definitions._ + +} \ No newline at end of file -- cgit v1.2.3 From e9a70f564a29ec0e2262cc9e6608c990b6b05274 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 31 Jan 2012 12:33:47 +0100 Subject: First steps towards erasure of inline classes. --- src/compiler/scala/reflect/internal/Types.scala | 12 ++++++++++++ src/compiler/scala/reflect/internal/transform/Erasure.scala | 8 ++++++++ 2 files changed, 20 insertions(+) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index bf0017d989..0d25ccf86d 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -65,6 +65,8 @@ import util.Statistics._ // inst is the instantiation and constr is a list of bounds. case DeBruijnIndex(level, index) // for dependent method types: a type referring to a method parameter. + case ErasedInlineType(tp) + // only used during erasure of inline classes. */ trait Types extends api.Types { self: SymbolTable => @@ -3067,6 +3069,15 @@ trait Types extends api.Types { self: SymbolTable => "De Bruijn "+kind+"("+(pnames mkString ",")+";"+(ptypes mkString ",")+";"+restpe+")" } } + + abstract case class ErasedInlineType(sym: Symbol) extends Type + + final class UniqueErasedInlineType(sym: Symbol) extends ErasedInlineType(sym) with UniqueType + + object ErasedInlineType { + def apply(sym: Symbol): Type = + unique(new UniqueErasedInlineType(sym)) + } /** A class representing an as-yet unevaluated type. */ @@ -3732,6 +3743,7 @@ trait Types extends api.Types { self: SymbolTable => case WildcardType => tp case NoType => tp case NoPrefix => tp + case ErasedSingleType(sym) => tp */ case _ => tp diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index 9faa399cad..38a60587a4 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -62,6 +62,13 @@ trait Erasure { protected def rebindInnerClass(pre: Type, cls: Symbol): Type = { if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? } + + protected def unboxInlineType(clazz: Symbol): Type = + clazz.primaryConstructor.info.params.head.tpe + + protected def eraseInlineClassRef(clazz: Symbol): Type = { + scalaErasure(unboxInlineType(clazz)) + } abstract class ErasureMap extends TypeMap { def mergeParents(parents: List[Type]): Type @@ -80,6 +87,7 @@ trait Erasure { else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass) else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) else if (sym.isRefinementClass) apply(mergeParents(tp.parents)) + else if (sym.isInlineClass) eraseInlineClassRef(sym) else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585 else apply(sym.info) // alias type or abstract type case PolyType(tparams, restpe) => -- cgit v1.2.3 From b4cfd1161e9f549a909d9f563f557c17dbddad00 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 3 Feb 2012 07:44:41 +0100 Subject: intermediate work towards a new starr for value classes. --- .../scala/reflect/internal/Definitions.scala | 84 ++++++++++++++-------- .../scala/reflect/internal/transform/Erasure.scala | 8 +-- src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 7 ++ .../scala/tools/nsc/ast/parser/Parsers.scala | 12 ++-- .../scala/tools/nsc/typechecker/Namers.scala | 51 ++++++------- .../scala/tools/nsc/typechecker/Typers.scala | 28 +++++--- src/library/scala/Proxy.scala | 10 +-- .../scala/collection/GenTraversableOnce.scala | 2 +- .../scala/collection/immutable/StringOps.scala | 2 +- src/library/scala/math/Ordered.scala | 2 +- src/library/scala/runtime/ScalaNumberProxy.scala | 2 +- test/files/neg/override-object-no.check | 12 ++-- 12 files changed, 134 insertions(+), 86 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index ce0505bf44..792c8ad215 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -21,7 +21,7 @@ trait Definitions extends reflect.api.StandardDefinitions { * methods. */ private type PolyMethodCreator = List[Symbol] => (Option[List[Type]], Type) - + private def enterNewClass(owner: Symbol, name: TypeName, parents: List[Type], flags: Long = 0L): Symbol = { val clazz = owner.newClassSymbol(name, NoPosition, flags) clazz setInfoAndEnter ClassInfoType(parents, newScope, clazz) @@ -104,7 +104,6 @@ trait Definitions extends reflect.api.StandardDefinitions { def isGetClass(sym: Symbol) = (sym.name == nme.getClass_) && (sym.paramss.isEmpty || sym.paramss.head.isEmpty) - lazy val AnyValClass = valueCache(tpnme.AnyVal) lazy val UnitClass = valueCache(tpnme.Unit) lazy val ByteClass = valueCache(tpnme.Byte) lazy val ShortClass = valueCache(tpnme.Short) @@ -166,7 +165,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val RuntimePackage = getRequiredModule("scala.runtime") lazy val RuntimePackageClass = RuntimePackage.moduleClass - + lazy val JavaLangEnumClass = getRequiredClass("java.lang.Enum") // convenient one-argument parameter lists @@ -178,10 +177,10 @@ trait Definitions extends reflect.api.StandardDefinitions { private def booltype = BooleanClass.typeConstructor private def inttype = IntClass.typeConstructor private def stringtype = StringClass.typeConstructor - + // Java types def javaTypeName(jclazz: Class[_]): TypeName = newTypeName(jclazz.getName) - + def javaTypeToValueClass(jtype: Class[_]): Symbol = jtype match { case java.lang.Void.TYPE => UnitClass case java.lang.Byte.TYPE => ByteClass @@ -207,6 +206,23 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => null } + private def fixupAsAnyTrait(clazz: Symbol): Symbol = { + clazz setInfo fixupAsAnyTrait(clazz.info) + clazz + } + + private def fixupAsAnyTrait(tpe: Type): Type = tpe match { + case ClassInfoType(parents, decls, clazz) => + if (parents.head.typeSymbol == AnyClass) tpe + else { + assert(parents.head.typeSymbol == ObjectClass, parents) + ClassInfoType(AnyClass.tpe :: parents.tail, decls, clazz) + } + case PolyType(tparams, restpe) => + PolyType(tparams, fixupAsAnyTrait(restpe)) +// case _ => tpe + } + // top types lazy val AnyClass = enterNewClass(ScalaPackageClass, tpnme.Any, Nil, ABSTRACT) lazy val AnyRefClass = newAlias(ScalaPackageClass, tpnme.AnyRef, ObjectClass.typeConstructor) @@ -214,6 +230,18 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") initFlags (SEALED | ABSTRACT | TRAIT) lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") initFlags (SEALED | ABSTRACT | TRAIT) + private var oldValueScheme = true + + lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse { +// println("new anyval") + oldValueScheme = true + val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, anyparam, 0L) + val av_constr = anyval.newClassConstructor(NoPosition) + anyval.info.decls enter av_constr + anyval + } + lazy val AnyVal_getClass = enterNewMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe)) + // bottom types lazy val RuntimeNothingClass = getClass(fulltpnme.RuntimeNothing) lazy val RuntimeNullClass = getClass(fulltpnme.RuntimeNull) @@ -274,7 +302,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def Predef_identity = getMember(PredefModule, nme.identity) def Predef_conforms = getMember(PredefModule, nme.conforms) def Predef_wrapRefArray = getMember(PredefModule, nme.wrapRefArray) - + /** Is `sym` a member of Predef with the given name? * Note: DON't replace this by sym == Predef_conforms/etc, as Predef_conforms is a `def` * which does a member lookup (it can't be a lazy val because we might reload Predef @@ -316,7 +344,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) - lazy val ComparableClass = getRequiredClass("java.lang.Comparable") + lazy val ComparableClass = fixupAsAnyTrait(getRequiredClass("java.lang.Comparable")) lazy val JavaCloneableClass = getRequiredClass("java.lang.Cloneable") lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote") lazy val RemoteExceptionClass = getRequiredClass("java.rmi.RemoteException") @@ -426,7 +454,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case m: ClassManifest[_] => val sym = manifestToSymbol(m) val args = m.typeArguments - + if ((sym eq NoSymbol) || args.isEmpty) sym.tpe else appliedType(sym.typeConstructor, args map manifestToType) case _ => @@ -436,7 +464,7 @@ trait Definitions extends reflect.api.StandardDefinitions { def manifestToSymbol(m: ClassManifest[_]): Symbol = m match { case x: scala.reflect.AnyValManifest[_] => getMember(ScalaPackageClass, newTypeName("" + x)) - case _ => + case _ => val name = m.erasure.getName if (name endsWith nme.MODULE_SUFFIX_STRING) getModuleIfDefined(name stripSuffix nme.MODULE_SUFFIX_STRING) @@ -496,7 +524,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case DoubleClass => nme.wrapDoubleArray case BooleanClass => nme.wrapBooleanArray case UnitClass => nme.wrapUnitArray - case _ => + case _ => if ((elemtp <:< AnyRefClass.tpe) && !isPhantomClass(elemtp.typeSymbol)) nme.wrapRefArray else nme.genericWrapArray } @@ -640,7 +668,7 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => false }) } - + // members of class scala.Any lazy val Any_== = enterNewMethod(AnyClass, nme.EQ, anyparam, booltype, FINAL) lazy val Any_!= = enterNewMethod(AnyClass, nme.NE, anyparam, booltype, FINAL) @@ -662,12 +690,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val Any_isInstanceOf = newT1NullaryMethod(AnyClass, nme.isInstanceOf_, FINAL)(_ => booltype) lazy val Any_asInstanceOf = newT1NullaryMethod(AnyClass, nme.asInstanceOf_, FINAL)(_.typeConstructor) - // AnyVal_getClass is defined here. Once we have a new strap, it could also be - // defined directly in the AnyVal trait. Right now this does not work, because - // strap complains about overriding a final getClass method in Any. - lazy val AnyVal_getClass = newMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe)) - - // A type function from T => Class[U], used to determine the return + // A type function from T => Class[U], used to determine the return // type of getClass calls. The returned type is: // // 1. If T is a value type, Class[T]. @@ -708,7 +731,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val Object_ne = enterNewMethod(ObjectClass, nme.ne, anyrefparam, booltype, FINAL) lazy val Object_isInstanceOf = newT1NoParamsMethod(ObjectClass, nme.isInstanceOf_Ob, FINAL | SYNTHETIC)(_ => booltype) lazy val Object_asInstanceOf = newT1NoParamsMethod(ObjectClass, nme.asInstanceOf_Ob, FINAL | SYNTHETIC)(_.typeConstructor) - lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => + lazy val Object_synchronized = newPolyMethod(1, ObjectClass, nme.synchronized_, FINAL)(tps => (Some(List(tps.head.typeConstructor)), tps.head.typeConstructor) ) lazy val String_+ = enterNewMethod(StringClass, nme.raw.PLUS, anyparam, stringtype, FINAL) @@ -816,10 +839,10 @@ trait Definitions extends reflect.api.StandardDefinitions { while (result.isAliasType) result = result.info.typeSymbol result } - + def getRequiredModule(fullname: String): Symbol = getModule(newTermNameCached(fullname)) - def getRequiredClass(fullname: String): Symbol = + def getRequiredClass(fullname: String): Symbol = getClass(newTypeNameCached(fullname)) def getClassIfDefined(fullname: String): Symbol = @@ -868,15 +891,15 @@ trait Definitions extends reflect.api.StandardDefinitions { private def newAlias(owner: Symbol, name: TypeName, alias: Type): Symbol = owner.newAliasType(name) setInfoAndEnter alias - + private def specialPolyClass(name: TypeName, flags: Long)(parentFn: Symbol => Type): Symbol = { val clazz = enterNewClass(ScalaPackageClass, name, Nil) val tparam = clazz.newSyntheticTypeParam("T0", flags) val parents = List(AnyRefClass.tpe, parentFn(tparam)) - + clazz setInfo GenPolyType(List(tparam), ClassInfoType(parents, newScope, clazz)) } - + def newPolyMethod(typeParamCount: Int, owner: Symbol, name: TermName, flags: Long)(createFn: PolyMethodCreator): Symbol = { val msym = owner.newMethod(name.encode, NoPosition, flags) val tparams = msym.newSyntheticTypeParams(typeParamCount) @@ -887,7 +910,7 @@ trait Definitions extends reflect.api.StandardDefinitions { msym setInfoAndEnter polyType(tparams, mtpe) } - + /** T1 means one type parameter. */ def newT1NullaryMethod(owner: Symbol, name: TermName, flags: Long)(createFn: Symbol => Type): Symbol = { @@ -999,7 +1022,7 @@ trait Definitions extends reflect.api.StandardDefinitions { RootClass.info.decls enter EmptyPackage RootClass.info.decls enter RootPackage - + val forced = List( // force initialization of every symbol that is entered as a side effect AnnotationDefaultAttr, // #2264 RepeatedParamClass, @@ -1029,13 +1052,18 @@ trait Definitions extends reflect.api.StandardDefinitions { Object_synchronized, Object_isInstanceOf, Object_asInstanceOf, + //AnyVal_getClass, String_+, - AnyVal_getClass + ComparableClass ) - /** Removing the anyref parent they acquire from having a source file. + /* Removing the anyref parent they acquire from having a source file. */ - setParents(AnyValClass, List(NotNullClass.tpe, AnyClass.tpe)) + if (oldValueScheme) { + setParents(AnyValClass, List(NotNullClass.tpe, AnyClass.tpe)) + } else { + AnyVal_getClass // force it! + } ScalaValueClasses foreach { sym => setParents(sym, anyvalparam) } diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index 38a60587a4..4775541855 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -62,10 +62,10 @@ trait Erasure { protected def rebindInnerClass(pre: Type, cls: Symbol): Type = { if (cls.owner.isClass) cls.owner.tpe else pre // why not cls.isNestedClass? } - - protected def unboxInlineType(clazz: Symbol): Type = + + protected def unboxInlineType(clazz: Symbol): Type = clazz.primaryConstructor.info.params.head.tpe - + protected def eraseInlineClassRef(clazz: Symbol): Type = { scalaErasure(unboxInlineType(clazz)) } @@ -87,7 +87,7 @@ trait Erasure { else if (sym == AnyClass || sym == AnyValClass || sym == SingletonClass || sym == NotNullClass) erasedTypeRef(ObjectClass) else if (sym == UnitClass) erasedTypeRef(BoxedUnitClass) else if (sym.isRefinementClass) apply(mergeParents(tp.parents)) - else if (sym.isInlineClass) eraseInlineClassRef(sym) + //else if (sym.isInlineClass) eraseInlineClassRef(sym) else if (sym.isClass) typeRef(apply(rebindInnerClass(pre, sym)), sym, List()) // #2585 else apply(sym.info) // alias type or abstract type case PolyType(tparams, restpe) => diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 662e03d155..81a6659b3c 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -45,4 +45,11 @@ abstract class TreeInfo extends reflect.internal.TreeInfo { def isInterface(mods: HasFlags, body: List[Tree]) = mods.hasTraitFlag && (body forall isInterfaceMember) + + def isAllowedInAnyTrait(stat: Tree): Boolean = stat match { + case _: ValDef => false + case Import(_, _) | EmptyTree => true + case _: DefTree => true + case _ => false + } } diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 3ee8b62bc6..acb4e9b122 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -38,7 +38,7 @@ trait ParsersCommon extends ScannersCommon { def freshTypeName(prefix: String): TypeName def deprecationWarning(off: Int, msg: String): Unit def accept(token: Int): Int - + /** Methods inParensOrError and similar take a second argument which, should * the next token not be the expected opener (e.g. LPAREN) will be returned * instead of the contents of the groupers. However in all cases accept(LPAREN) @@ -1141,7 +1141,7 @@ self => private def interpolatedString(): Tree = atPos(in.offset) { val start = in.offset val interpolator = in.name - + val partsBuf = new ListBuffer[Tree] val exprBuf = new ListBuffer[Tree] in.nextToken() @@ -1153,7 +1153,7 @@ self => } } if (in.token == STRINGLIT) partsBuf += literal() - + val t1 = atPos(o2p(start)) { Ident(nme.StringContext) } val t2 = atPos(start) { Apply(t1, partsBuf.toList) } t2 setPos t2.pos.makeTransparent @@ -2765,8 +2765,10 @@ self => } else { val parents = ( - if (!isInterface(mods, body) && !isScalaArray(name)) parents0 :+ scalaScalaObjectConstr - else if (parents0.isEmpty) List(scalaAnyRefConstr) + if (parents0.isEmpty) List(scalaAnyRefConstr) + /*if (!isInterface(mods, body) && !isScalaArray(name)) + parents0 /* :+ scalaScalaObjectConstr*/ + else*/ else parents0 ) ++ caseParents() Template(parents, self, constrMods, vparamss, argss, body, o2p(tstart)) diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 2f31347829..5f156b98e8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -113,7 +113,7 @@ trait Namers extends MethodSynthesis { private def contextFile = context.unit.source.file private def typeErrorHandler[T](tree: Tree, alt: T): PartialFunction[Throwable, T] = { case ex: TypeError => - // H@ need to ensure that we handle only cyclic references + // H@ need to ensure that we handle only cyclic references TypeSigError(tree, ex) alt } @@ -296,7 +296,7 @@ trait Namers extends MethodSynthesis { val pos = tree.pos val isParameter = tree.mods.isParameter val flags = tree.mods.flags & mask - + tree match { case TypeDef(_, _, _, _) if isParameter => owner.newTypeParameter(name.toTypeName, pos, flags) case TypeDef(_, _, _, _) => owner.newTypeSymbol(name.toTypeName, pos, flags) @@ -705,6 +705,13 @@ trait Namers extends MethodSynthesis { if (needsCycleCheck && !typer.checkNonCyclic(tree.pos, tp)) sym setInfo ErrorType } + tree match { + case cdef: ClassDef => + if (!treeInfo.isInterface(sym, cdef.impl.body) && sym != ArrayClass && + (sym.info.parents forall (_.typeSymbol != AnyValClass))) + ensureParent(sym, ScalaObjectClass) + case _ => + } } def moduleClassTypeCompleter(tree: Tree) = { @@ -837,10 +844,6 @@ trait Namers extends MethodSynthesis { val parents = typer.parentTypes(templ) map checkParent -// not yet: -// if (!treeInfo.isInterface(clazz, templ.body) && clazz != ArrayClass) -// ensureParent(ScalaObjectClass) - enterSelf(templ.self) val decls = newScope @@ -1313,6 +1316,22 @@ trait Namers extends MethodSynthesis { } } + def includeParent(tpe: Type, parent: Symbol): Type = tpe match { + case PolyType(tparams, restpe) => + PolyType(tparams, includeParent(restpe, parent)) + case ClassInfoType(parents, decls, clazz) => + if (parents exists (_.typeSymbol == parent)) tpe + else ClassInfoType(parents :+ parent.tpe, decls, clazz) + case _ => + tpe + } + + def ensureParent(clazz: Symbol, parent: Symbol) = { + val info0 = clazz.info + val info1 = includeParent(info0, parent) + if (info0 ne info1) clazz setInfo info1 + } + class LogTransitions[S](onEnter: S => String, onExit: S => String) { val enabled = settings.debug.value @inline final def apply[T](entity: S)(body: => T): T = { @@ -1390,25 +1409,9 @@ trait Namers extends MethodSynthesis { if (sym.info.typeSymbol == FunctionClass(0) && sym.isValueParameter && sym.owner.isCaseClass) fail(ByNameParameter) - def includeParent(tpe: Type, parent: Symbol): Type = tpe match { - case PolyType(tparams, restpe) => - PolyType(tparams, includeParent(restpe, parent)) - case ClassInfoType(parents, decls, clazz) => - if (parents exists (_.typeSymbol == parent)) tpe - else ClassInfoType(parents :+ parent.tpe, decls, clazz) - case _ => - tpe - } - - def ensureParent(parent: Symbol) = { - val info0 = sym.info - val info1 = includeParent(info0, parent) - if (info0 ne info1) sym setInfo info1 - } - - if (sym.isClass && sym.hasAnnotation(ScalaInlineClass) && !phase.erasedTypes) { + if (sym.isClass && sym.hasAnnotation(ScalaInlineClass) && !phase.erasedTypes) { if (!sym.isSubClass(AnyValClass)) - ensureParent(NotNullClass) + ensureParent(sym, NotNullClass) sym setFlag FINAL } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index b6f555e42a..680a298230 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -154,7 +154,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ErrorType => fun } - + def inferView(tree: Tree, from: Type, to: Type, reportAmbiguous: Boolean): Tree = inferView(tree, from, to, reportAmbiguous, true) @@ -274,7 +274,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } tp match { case TypeRef(pre, sym, args) => - checkNotLocked(sym) && + checkNotLocked(sym) && ((!sym.isNonClassType) || checkNonCyclic(pos, appliedType(pre.memberInfo(sym), args), sym)) // @M! info for a type ref to a type parameter now returns a polytype // @M was: checkNonCyclic(pos, pre.memberInfo(sym).subst(sym.typeParams, args), sym) @@ -939,7 +939,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { adaptType() else if (inExprModeButNot(mode, FUNmode) && tree.symbol != null && tree.symbol.isMacro && !tree.isDef) { val tree1 = expandMacro(tree) - if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) + if (tree1.isErroneous) tree1 else typed(tree1, mode, pt) } else if ((mode & (PATTERNmode | FUNmode)) == (PATTERNmode | FUNmode)) adaptConstrPattern() else if (inAllModes(mode, EXPRmode | FUNmode) && @@ -1084,7 +1084,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // Note: implicit arguments are still inferred (this kind of "chaining" is allowed) ) } - + def adaptToMember(qual: Tree, searchTemplate: Type): Tree = adaptToMember(qual, searchTemplate, true, true) def adaptToMember(qual: Tree, searchTemplate: Type, reportAmbiguous: Boolean): Tree = @@ -1099,12 +1099,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } inferView(qual, qual.tpe, searchTemplate, reportAmbiguous, saveErrors) match { case EmptyTree => qual - case coercion => + case coercion => if (settings.logImplicitConv.value) unit.echo(qual.pos, "applied implicit conversion from %s to %s = %s".format( qual.tpe, searchTemplate, coercion.symbol.defString)) - + typedQualifier(atPos(qual.pos)(new ApplyImplicitView(coercion, List(qual)))) } } @@ -1205,6 +1205,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { supertpt = TypeTree(supertpt1.tpe.parents.head) setPos supertpt.pos.focus } } + if (supertpt.tpe.typeSymbol == AnyClass && firstParent.isTrait && firstParent != AnyValClass) + supertpt.tpe = AnyRefClass.tpe // Determine // - supertparams: Missing type parameters from supertype @@ -1407,6 +1409,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { _.typedTemplate(cdef.impl, parentTypes(cdef.impl)) } val impl2 = finishMethodSynthesis(impl1, clazz, context) + if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.parents.head.typeSymbol == AnyClass) + for (stat <- impl2.body) + if (!treeInfo.isAllowedInAnyTrait(stat)) + unit.error(stat.pos, "this statement is not allowed in trait extending from class Any: "+stat) if ((clazz != ClassfileAnnotationClass) && (clazz isNonBottomSubClass ClassfileAnnotationClass)) restrictionWarning(cdef.pos, unit, @@ -2889,10 +2895,10 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { def packSymbols(hidden: List[Symbol], tp: Type): Type = if (hidden.isEmpty) tp else existentialTransform(hidden, tp)(existentialAbstraction) - + def isReferencedFrom(ctx: Context, sym: Symbol): Boolean = - ctx.owner.isTerm && - (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || + ctx.owner.isTerm && + (ctx.scope.exists { dcl => dcl.isInitialized && (dcl.info contains sym) }) || { var ctx1 = ctx.outer while ((ctx1 != NoContext) && (ctx1.scope eq ctx.scope)) ctx1 = ctx1.outer @@ -3879,7 +3885,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { reallyExists(sym) && ((mode & PATTERNmode | FUNmode) != (PATTERNmode | FUNmode) || !sym.isSourceMethod || sym.hasFlag(ACCESSOR)) } - + if (defSym == NoSymbol) { var defEntry: ScopeEntry = null // the scope entry of defSym, if defined in a local scope @@ -4370,7 +4376,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { case ReferenceToBoxed(idt @ Ident(_)) => val id1 = typed1(idt, mode, pt) match { case id: Ident => id } - treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe + treeCopy.ReferenceToBoxed(tree, id1) setType AnyRefClass.tpe case Literal(value) => tree setType ( diff --git a/src/library/scala/Proxy.scala b/src/library/scala/Proxy.scala index 383ff5b3bb..16c3c3fa56 100644 --- a/src/library/scala/Proxy.scala +++ b/src/library/scala/Proxy.scala @@ -22,13 +22,15 @@ package scala * @author Matthias Zenger * @version 1.0, 26/04/2004 */ -trait Proxy { +trait Proxy extends Any { def self: Any override def hashCode: Int = self.hashCode override def equals(that: Any): Boolean = that match { - case null => false - case x: AnyRef => (x eq this) || (x eq self.asInstanceOf[AnyRef]) || (x equals self) + case null => false + case _ => + val x = that.asInstanceOf[AnyRef] + (x eq this.asInstanceOf[AnyRef]) || (x eq self.asInstanceOf[AnyRef]) || (x equals self) } override def toString = "" + self } @@ -36,7 +38,7 @@ trait Proxy { object Proxy { /** A proxy which exposes the type it is proxying for via a type parameter. */ - trait Typed[T] extends Proxy { + trait Typed[T] extends /*Any with */Proxy { def self: T } } diff --git a/src/library/scala/collection/GenTraversableOnce.scala b/src/library/scala/collection/GenTraversableOnce.scala index 305f8d768d..18b1a96155 100644 --- a/src/library/scala/collection/GenTraversableOnce.scala +++ b/src/library/scala/collection/GenTraversableOnce.scala @@ -41,7 +41,7 @@ package scala.collection * @author Aleksandar Prokopec * @since 2.9 */ -trait GenTraversableOnce[+A] { +trait GenTraversableOnce[+A] extends AnyRef { def foreach[U](f: A => U): Unit diff --git a/src/library/scala/collection/immutable/StringOps.scala b/src/library/scala/collection/immutable/StringOps.scala index 8612357db9..09cbd247e9 100644 --- a/src/library/scala/collection/immutable/StringOps.scala +++ b/src/library/scala/collection/immutable/StringOps.scala @@ -28,7 +28,7 @@ import mutable.StringBuilder * @define Coll StringOps * @define coll string */ -final class StringOps(override val repr: String) extends StringLike[String] { +final class StringOps(override val repr: String) extends AnyRef with StringLike[String] { override protected[this] def thisCollection: WrappedString = new WrappedString(repr) override protected[this] def toCollection(repr: String): WrappedString = new WrappedString(repr) diff --git a/src/library/scala/math/Ordered.scala b/src/library/scala/math/Ordered.scala index 53d618db63..4397f14c94 100644 --- a/src/library/scala/math/Ordered.scala +++ b/src/library/scala/math/Ordered.scala @@ -50,7 +50,7 @@ package scala.math * @author Martin Odersky * @version 1.1, 2006-07-24 */ -trait Ordered[A] extends java.lang.Comparable[A] { +trait Ordered[A] extends /*Any with*/ java.lang.Comparable[A] { /** Result of comparing `this` with operand `that`. * diff --git a/src/library/scala/runtime/ScalaNumberProxy.scala b/src/library/scala/runtime/ScalaNumberProxy.scala index 09e1611dcd..bd19e099e0 100644 --- a/src/library/scala/runtime/ScalaNumberProxy.scala +++ b/src/library/scala/runtime/ScalaNumberProxy.scala @@ -64,7 +64,7 @@ abstract class FractionalProxy[T : Fractional] extends ScalaNumberProxy[T] with def to(end: T, step: T): NumericRange.Inclusive[T] = NumericRange.inclusive(self, end, step) } -trait OrderedProxy[T] extends Typed[T] with Ordered[T] { +trait OrderedProxy[T] extends Ordered[T] with Typed[T] { protected def ord: Ordering[T] def compare(y: T) = ord.compare(self, y) diff --git a/test/files/neg/override-object-no.check b/test/files/neg/override-object-no.check index 6e028d0add..f9fb37381b 100644 --- a/test/files/neg/override-object-no.check +++ b/test/files/neg/override-object-no.check @@ -1,13 +1,13 @@ override-object-no.scala:14: error: overriding object Bar in trait Foo with object Bar in trait Foo2: an overriding object must conform to the overridden object's class bound; - found : case1.Bippy with ScalaObject - required: case1.Bippy with case1.Bippo with ScalaObject + found : case1.Bippy + required: case1.Bippy with case1.Bippo override object Bar extends Bippy { // err ^ override-object-no.scala:21: error: overriding object Bar in trait Quux1 with object Bar in trait Quux2: an overriding object must conform to the overridden object's class bound; - found : Object with ScalaObject{def g: String} - required: Object with ScalaObject{def g: Int} + found : Object{def g: String} + required: Object{def g: Int} trait Quux2 extends Quux1 { override object Bar { def g = "abc" } } // err ^ override-object-no.scala:25: error: overriding object Bar in trait Quux3 of type object Quux4.this.Bar; @@ -16,8 +16,8 @@ override-object-no.scala:25: error: overriding object Bar in trait Quux3 of type ^ override-object-no.scala:43: error: overriding object A in class Foo with object A in class P2: an overriding object must conform to the overridden object's class bound; - found : case2.Bar[List[String]] with ScalaObject - required: case2.Bar[Traversable[String]] with ScalaObject + found : case2.Bar[List[String]] + required: case2.Bar[Traversable[String]] override object A extends Bar[List[String]] // err ^ four errors found -- cgit v1.2.3 From c5871a974aeaed8d90794c44629bde61f516dfaa Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 3 Feb 2012 09:54:02 -0800 Subject: Mostly eliminated ScalaObject. --- src/android-library/scala/ScalaObject.scala | 13 ------------- src/compiler/scala/reflect/internal/Definitions.scala | 1 - src/compiler/scala/reflect/internal/StdNames.scala | 1 - src/compiler/scala/reflect/internal/SymbolTable.scala | 2 +- src/compiler/scala/reflect/internal/TreeGen.scala | 1 - src/compiler/scala/reflect/internal/TreeInfo.scala | 1 - src/compiler/scala/reflect/runtime/ToolBoxes.scala | 2 +- src/compiler/scala/tools/nsc/Global.scala | 3 +-- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 +- src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala | 1 - src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala | 11 +++++------ src/compiler/scala/tools/nsc/transform/AddInterfaces.scala | 2 +- src/compiler/scala/tools/nsc/transform/Constructors.scala | 2 +- src/compiler/scala/tools/nsc/typechecker/Contexts.scala | 3 +-- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 7 ------- src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 2 +- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 1 + src/compiler/scala/tools/nsc/typechecker/Unapplies.scala | 3 +-- src/compiler/scala/tools/nsc/util/ClassPath.scala | 2 +- src/detach/plugin/scala/tools/detach/Detach.scala | 5 ++--- src/library/scala/ScalaObject.scala | 13 ------------- src/library/scala/util/Properties.scala | 2 +- 22 files changed, 19 insertions(+), 61 deletions(-) delete mode 100644 src/android-library/scala/ScalaObject.scala delete mode 100644 src/library/scala/ScalaObject.scala (limited to 'src/compiler') diff --git a/src/android-library/scala/ScalaObject.scala b/src/android-library/scala/ScalaObject.scala deleted file mode 100644 index f44116d1ce..0000000000 --- a/src/android-library/scala/ScalaObject.scala +++ /dev/null @@ -1,13 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala - -trait ScalaObject extends AnyRef diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 792c8ad215..47c711e81c 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -274,7 +274,6 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val UninitializedErrorClass = getRequiredClass("scala.UninitializedFieldError") // fundamental reference classes - lazy val ScalaObjectClass = getMember(ScalaPackageClass, tpnme.ScalaObject) lazy val PartialFunctionClass = getRequiredClass("scala.PartialFunction") lazy val AbstractPartialFunctionClass = getRequiredClass("scala.runtime.AbstractPartialFunction") lazy val SymbolClass = getRequiredClass("scala.Symbol") diff --git a/src/compiler/scala/reflect/internal/StdNames.scala b/src/compiler/scala/reflect/internal/StdNames.scala index b1a24c0be2..c3a7dc23f3 100644 --- a/src/compiler/scala/reflect/internal/StdNames.scala +++ b/src/compiler/scala/reflect/internal/StdNames.scala @@ -143,7 +143,6 @@ trait StdNames extends NameManglers { self: SymbolTable => final val Object: NameType = "Object" final val PartialFunction: NameType = "PartialFunction" final val Product: NameType = "Product" - final val ScalaObject: NameType = "ScalaObject" final val Serializable: NameType = "Serializable" final val Singleton: NameType = "Singleton" final val String: NameType = "String" diff --git a/src/compiler/scala/reflect/internal/SymbolTable.scala b/src/compiler/scala/reflect/internal/SymbolTable.scala index fb827b0658..2e799f914a 100644 --- a/src/compiler/scala/reflect/internal/SymbolTable.scala +++ b/src/compiler/scala/reflect/internal/SymbolTable.scala @@ -164,7 +164,7 @@ abstract class SymbolTable extends api.Universe } // enter decls of parent classes for (p <- container.parentSymbols) { - if (p != definitions.ObjectClass && p != definitions.ScalaObjectClass) { + if (p != definitions.ObjectClass) { openPackageModule(p, dest) } } diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala index e537c6b83f..d0c5bc8e5b 100644 --- a/src/compiler/scala/reflect/internal/TreeGen.scala +++ b/src/compiler/scala/reflect/internal/TreeGen.scala @@ -12,7 +12,6 @@ abstract class TreeGen { def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name) def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) def scalaUnitConstr = scalaDot(tpnme.Unit) - def scalaScalaObjectConstr = scalaDot(tpnme.ScalaObject) def productConstr = scalaDot(tpnme.Product) def serializableConstr = scalaDot(tpnme.Serializable) diff --git a/src/compiler/scala/reflect/internal/TreeInfo.scala b/src/compiler/scala/reflect/internal/TreeInfo.scala index 4380487555..ecd31c784d 100644 --- a/src/compiler/scala/reflect/internal/TreeInfo.scala +++ b/src/compiler/scala/reflect/internal/TreeInfo.scala @@ -470,7 +470,6 @@ abstract class TreeInfo { } ( isUnitInScala(body, nme.Predef) - || isUnitInScala(body, tpnme.ScalaObject) || containsLeadingPredefImport(List(body))) } diff --git a/src/compiler/scala/reflect/runtime/ToolBoxes.scala b/src/compiler/scala/reflect/runtime/ToolBoxes.scala index 6e671ae06e..70a3061fc7 100644 --- a/src/compiler/scala/reflect/runtime/ToolBoxes.scala +++ b/src/compiler/scala/reflect/runtime/ToolBoxes.scala @@ -59,7 +59,7 @@ trait ToolBoxes extends { self: Universe => def wrapInObject(expr: Tree, fvs: List[Symbol]): ModuleDef = { val obj = EmptyPackageClass.newModule(nextWrapperModuleName()) - val minfo = ClassInfoType(List(ObjectClass.tpe, ScalaObjectClass.tpe), newScope, obj.moduleClass) + val minfo = ClassInfoType(List(ObjectClass.tpe), newScope, obj.moduleClass) obj.moduleClass setInfo minfo obj setInfo obj.moduleClass.tpe val meth = obj.moduleClass.newMethod(newTermName(wrapperMethodName)) diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index c63070b18f..8e5ca2156a 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1361,7 +1361,7 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb /** * Re-orders the source files to - * 1. ScalaObject + * 1. This Space Intentionally Left Blank * 2. LowPriorityImplicits / EmbeddedControls (i.e. parents of Predef) * 3. the rest * @@ -1389,7 +1389,6 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb def rank(f: SourceFile) = { if (f.file.container.name != "scala") goLast else f.file.name match { - case "ScalaObject.scala" => 1 case "LowPriorityImplicits.scala" => 2 case "StandardEmbeddings.scala" => 2 case "EmbeddedControls.scala" => 2 diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index acb4e9b122..40e7d88a3b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -392,7 +392,7 @@ self => // object Main def moduleName = newTermName(ScriptRunner scriptMain settings) - def moduleBody = Template(List(scalaScalaObjectConstr), emptyValDef, List(emptyInit, mainDef)) + def moduleBody = Template(List(scalaAnyRefConstr), emptyValDef, List(emptyInit, mainDef)) def moduleDef = ModuleDef(NoMods, moduleName, moduleBody) // package { ... } diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 13f608ed4e..906932f591 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -31,7 +31,6 @@ abstract class TreeBuilder { def scalaDot(name: Name) = gen.scalaDot(name) def scalaAnyRefConstr = gen.scalaAnyRefConstr def scalaUnitConstr = gen.scalaUnitConstr - def scalaScalaObjectConstr = gen.scalaScalaObjectConstr def productConstr = gen.productConstr def productConstrN(n: Int) = scalaDot(newTypeName("Product" + n)) def serializableConstr = gen.serializableConstr diff --git a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala index 7eb8c393f3..ec9f705f5a 100644 --- a/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala +++ b/src/compiler/scala/tools/nsc/doc/model/ModelFactory.scala @@ -20,7 +20,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { thisFactory: ModelFactory with CommentFactory with TreeFactory => import global._ - import definitions.{ ObjectClass, ScalaObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyValClass, AnyRefClass } + import definitions.{ ObjectClass, RootPackage, EmptyPackage, NothingClass, AnyClass, AnyValClass, AnyRefClass } private var droppedPackages = 0 def templatesCount = templatesCache.size - droppedPackages @@ -42,7 +42,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { memberSym.isOmittablePrefix || (closestPackage(memberSym) == closestPackage(templateSym)) } - private lazy val noSubclassCache = Set(AnyClass, AnyRefClass, ObjectClass, ScalaObjectClass) + private lazy val noSubclassCache = Set(AnyClass, AnyRefClass, ObjectClass) /** */ def makeModel: Option[Universe] = { @@ -217,13 +217,12 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { } def parentType = { if (sym.isPackage || sym == AnyClass) None else { - val tps = - (sym.tpe.parents filter (_ != ScalaObjectClass.tpe)) map { _.asSeenFrom(sym.thisType, sym) } + val tps = sym.tpe.parents map { _.asSeenFrom(sym.thisType, sym) } Some(makeType(RefinedType(tps, EmptyScope), inTpl)) } } val linearization: List[(TemplateEntity, TypeEntity)] = { - sym.ancestors filter (_ != ScalaObjectClass) map { ancestor => + sym.ancestors map { ancestor => val typeEntity = makeType(sym.info.baseType(ancestor), this) val tmplEntity = makeTemplate(ancestor) match { case tmpl: DocTemplateImpl => tmpl registerSubClass this ; tmpl @@ -316,7 +315,7 @@ class ModelFactory(val global: Global, val settings: doc.Settings) { def normalizeTemplate(aSym: Symbol): Symbol = aSym match { case null | EmptyPackage | NoSymbol => normalizeTemplate(RootPackage) - case ScalaObjectClass | ObjectClass => + case ObjectClass => normalizeTemplate(AnyRefClass) case _ if aSym.isPackageObject => aSym diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index e01bbccf13..89dfbfd317 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -298,7 +298,7 @@ abstract class AddInterfaces extends InfoTransform { } val mixinConstructorCalls: List[Tree] = { for (mc <- clazz.mixinClasses.reverse - if mc.hasFlag(lateINTERFACE) && mc != ScalaObjectClass) + if mc.hasFlag(lateINTERFACE)) yield mixinConstructorCall(implClass(mc)) } (tree: @unchecked) match { diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index d1c71faf1e..256f13b3fb 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -445,7 +445,7 @@ abstract class Constructors extends Transform with ast.TreeDSL { localTyper.typed { atPos(impl.pos) { val closureClass = clazz.newClass(nme.delayedInitArg.toTypeName, impl.pos, SYNTHETIC | FINAL) - val closureParents = List(AbstractFunctionClass(0).tpe, ScalaObjectClass.tpe) + val closureParents = List(AbstractFunctionClass(0).tpe) closureClass setInfoAndEnter new ClassInfoType(closureParents, newScope, closureClass) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 740acbd10f..b5afd681d2 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -43,8 +43,7 @@ trait Contexts { self: Analyzer => * - if option `-Yno-imports` is given, nothing is imported * - if the unit is java defined, only `java.lang` is imported * - if option `-Yno-predef` is given, if the unit body has an import of Predef - * among its leading imports, or if the tree is [[scala.ScalaObject]] - * or [[scala.Predef]], `Predef` is not imported. + * among its leading imports, or if the tree is [[scala.Predef]], `Predef` is not imported. */ protected def rootImports(unit: CompilationUnit): List[Symbol] = { import definitions._ diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 5f156b98e8..7bb9ab2fc9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -705,13 +705,6 @@ trait Namers extends MethodSynthesis { if (needsCycleCheck && !typer.checkNonCyclic(tree.pos, tp)) sym setInfo ErrorType } - tree match { - case cdef: ClassDef => - if (!treeInfo.isInterface(sym, cdef.impl.body) && sym != ArrayClass && - (sym.info.parents forall (_.typeSymbol != AnyValClass))) - ensureParent(sym, ScalaObjectClass) - case _ => - } } def moduleClassTypeCompleter(tree: Tree) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 376488d4ef..21c1b8aa11 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1114,7 +1114,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // warn only if they have no common supertype below Object else { val common = global.lub(List(actual.tpe, receiver.tpe)) - if (common.typeSymbol == ScalaObjectClass || (ObjectClass.tpe <:< common)) + if (ObjectClass.tpe <:< common) unrelatedTypes() } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 5f555f6697..f6cc71c0ca 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -4614,6 +4614,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { // AnyRef, but the AnyRef type alias is entered after the scala package is // loaded and completed, so that ScalaObject is unpickled while AnyRef is not // yet defined ) + // !!! TODO - revisit now that ScalaObject is gone. result setType(restpe) } else { // must not normalize: type application must be (bounds-)checked (during RefChecks), see #2208 // during uncurry (after refchecks), all types are normalized diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index 19b8632ed7..b8bc0946c1 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -151,11 +151,10 @@ trait Unapplies extends ast.TreeDSL } def companionModuleDef(cdef: ClassDef, parents: List[Tree] = Nil, body: List[Tree] = Nil): ModuleDef = atPos(cdef.pos.focus) { - val allParents = parents :+ gen.scalaScalaObjectConstr ModuleDef( Modifiers(cdef.mods.flags & AccessFlags | SYNTHETIC, cdef.mods.privateWithin), cdef.name.toTermName, - Template(allParents, emptyValDef, NoMods, Nil, List(Nil), body, cdef.impl.pos.focus)) + Template(parents, emptyValDef, NoMods, Nil, List(Nil), body, cdef.impl.pos.focus)) } private val caseMods = Modifiers(SYNTHETIC | CASE) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 622b4db2a2..ce10ee34a2 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -23,7 +23,7 @@ import java.net.MalformedURLException * @author Stepan Koltsov */ object ClassPath { - def scalaLibrary = locate[ScalaObject] + def scalaLibrary = locate[Option[_]] def scalaCompiler = locate[Global] def infoFor[T](value: T) = info(value.getClass) diff --git a/src/detach/plugin/scala/tools/detach/Detach.scala b/src/detach/plugin/scala/tools/detach/Detach.scala index fee2c5a273..546041844e 100644 --- a/src/detach/plugin/scala/tools/detach/Detach.scala +++ b/src/detach/plugin/scala/tools/detach/Detach.scala @@ -734,7 +734,7 @@ abstract class Detach extends PluginComponent proxyOwner.newClass(clazz.pos, encode(clazz.name.decode + PROXY_SUFFIX)) iface.sourceFile = clazz.sourceFile iface setFlag (ABSTRACT | TRAIT | INTERFACE) // Java interface - val iparents = List(ObjectClass.tpe, RemoteClass.tpe, ScalaObjectClass.tpe) + val iparents = List(ObjectClass.tpe, RemoteClass.tpe) iface setInfo ClassInfoType(iparents, newScope, iface) // methods must throw RemoteException iface addAnnotation remoteAnnotationInfo @@ -744,8 +744,7 @@ abstract class Detach extends PluginComponent iclaz.sourceFile = clazz.sourceFile iclaz setFlag (SYNTHETIC | FINAL) // Variant 1: rebind/unbind - val cparents = List(UnicastRemoteObjectClass.tpe, iface.tpe, - UnreferencedClass.tpe, ScalaObjectClass.tpe) + val cparents = List(UnicastRemoteObjectClass.tpe, iface.tpe, UnreferencedClass.tpe) // Variant 2: un-/exportObject //val cparents = List(ObjectClass.tpe, iface.tpe, // UnreferencedClass.tpe, ScalaObjectClass.tpe) diff --git a/src/library/scala/ScalaObject.scala b/src/library/scala/ScalaObject.scala deleted file mode 100644 index 8da0ab2cba..0000000000 --- a/src/library/scala/ScalaObject.scala +++ /dev/null @@ -1,13 +0,0 @@ -/* __ *\ -** ________ ___ / / ___ Scala API ** -** / __/ __// _ | / / / _ | (c) 2002-2011, LAMP/EPFL ** -** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** -** /____/\___/_/ |_/____/_/ | | ** -** |/ ** -\* */ - - - -package scala - -trait ScalaObject extends java.lang.Object diff --git a/src/library/scala/util/Properties.scala b/src/library/scala/util/Properties.scala index 22de5544a8..df1c68ced4 100644 --- a/src/library/scala/util/Properties.scala +++ b/src/library/scala/util/Properties.scala @@ -15,7 +15,7 @@ import java.util.jar.Attributes.{ Name => AttributeName } /** Loads `library.properties` from the jar. */ object Properties extends PropertiesTrait { protected def propCategory = "library" - protected def pickJarBasedOn = classOf[ScalaObject] + protected def pickJarBasedOn = classOf[Option[_]] /** Scala manifest attributes. */ -- cgit v1.2.3 From 8c7005fc90008b6874431d318b482c2ad985181a Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 3 Feb 2012 10:36:17 -0800 Subject: Eliminated ScalaObject. "This too shall pass." --- src/compiler/scala/reflect/internal/TreeGen.scala | 8 ++++---- src/compiler/scala/tools/nsc/transform/UnCurry.scala | 2 +- src/compiler/scala/tools/nsc/typechecker/Namers.scala | 11 +++++++++++ src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 5 ++++- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 2 +- src/library/scala/Proxy.scala | 3 ++- 6 files changed, 23 insertions(+), 8 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala index d0c5bc8e5b..def1350187 100644 --- a/src/compiler/scala/reflect/internal/TreeGen.scala +++ b/src/compiler/scala/reflect/internal/TreeGen.scala @@ -10,10 +10,10 @@ abstract class TreeGen { def rootId(name: Name) = Select(Ident(nme.ROOTPKG), name) def rootScalaDot(name: Name) = Select(rootId(nme.scala_) setSymbol ScalaPackage, name) def scalaDot(name: Name) = Select(Ident(nme.scala_) setSymbol ScalaPackage, name) - def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) - def scalaUnitConstr = scalaDot(tpnme.Unit) - def productConstr = scalaDot(tpnme.Product) - def serializableConstr = scalaDot(tpnme.Serializable) + def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) setSymbol AnyRefClass + def scalaUnitConstr = scalaDot(tpnme.Unit) setSymbol UnitClass + def productConstr = scalaDot(tpnme.Product) setSymbol ProductRootClass + def serializableConstr = scalaDot(tpnme.Serializable) setSymbol SerializableClass def scalaFunctionConstr(argtpes: List[Tree], restpe: Tree, abstractFun: Boolean = false): Tree = { val cls = if (abstractFun) diff --git a/src/compiler/scala/tools/nsc/transform/UnCurry.scala b/src/compiler/scala/tools/nsc/transform/UnCurry.scala index ab4a2141a9..adbb7bc7f1 100644 --- a/src/compiler/scala/tools/nsc/transform/UnCurry.scala +++ b/src/compiler/scala/tools/nsc/transform/UnCurry.scala @@ -633,7 +633,7 @@ abstract class UnCurry extends InfoTransform tree1 } } setType { - assert(tree.tpe != null, tree + " tpe is null") + assert(tree.tpe != null, "tpe is null at " + tree.pos + " for " + tree.summaryString + " / " + tree) uncurryTreeType(tree.tpe) } diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 7bb9ab2fc9..35ee46363c 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -705,6 +705,17 @@ trait Namers extends MethodSynthesis { if (needsCycleCheck && !typer.checkNonCyclic(tree.pos, tp)) sym setInfo ErrorType } + tree match { + case ClassDef(_, _, _, impl) => + val parentsOK = ( + treeInfo.isInterface(sym, impl.body) + || (sym eq ArrayClass) + || (sym isSubClass AnyValClass) + ) + if (!parentsOK) + ensureParent(sym, AnyRefClass) + case _ => () + } } def moduleClassTypeCompleter(tree: Tree) = { diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 21c1b8aa11..04213cfda7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1482,7 +1482,10 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R if (settings.Xmigration28.value) checkMigration(sym, tree.pos) - if (currentClass != sym.owner && sym.hasLocalFlag) { + if (sym eq NoSymbol) { + unit.warning(tree.pos, "Select node has NoSymbol! " + tree + " / " + tree.tpe) + } + else if (currentClass != sym.owner && sym.hasLocalFlag) { var o = currentClass var hidden = false while (!hidden && o != sym.owner && o != sym.owner.moduleClass && !o.isPackage) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index f6cc71c0ca..a20e78a81f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1196,7 +1196,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } def parentTypes(templ: Template): List[Tree] = - if (templ.parents.isEmpty) List() + if (templ.parents.isEmpty) List(TypeTree(AnyRefClass.tpe)) else try { val clazz = context.owner // Normalize supertype and mixins so that supertype is always a class, not a trait. diff --git a/src/library/scala/Proxy.scala b/src/library/scala/Proxy.scala index 16c3c3fa56..7102ed0db2 100644 --- a/src/library/scala/Proxy.scala +++ b/src/library/scala/Proxy.scala @@ -22,7 +22,8 @@ package scala * @author Matthias Zenger * @version 1.0, 26/04/2004 */ -trait Proxy extends Any { +// trait Proxy extends Any { +trait Proxy { def self: Any override def hashCode: Int = self.hashCode -- cgit v1.2.3 From de82b3723271c5ca3655cfd76eea0638f0d18eb1 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Fri, 3 Feb 2012 11:57:47 -0800 Subject: Disabled all things MSIL. It's a huge drag when making fundamental changes. --- build.xml | 12 +- src/compiler/scala/tools/nsc/Global.scala | 9 +- .../scala/tools/nsc/backend/MSILPlatform.scala | 130 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 322 +- .../scala/tools/nsc/backend/icode/Opcodes.scala | 114 +- .../scala/tools/nsc/backend/icode/TypeKinds.scala | 13 +- .../scala/tools/nsc/backend/msil/GenMSIL.scala | 4714 ++++++++++---------- src/compiler/scala/tools/nsc/io/MsilFile.scala | 36 +- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 32 +- .../scala/tools/nsc/symtab/clr/CLRTypes.scala | 274 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 1702 +++---- .../scala/tools/nsc/util/MsilClassPath.scala | 338 +- 12 files changed, 3848 insertions(+), 3848 deletions(-) (limited to 'src/compiler') diff --git a/build.xml b/build.xml index 57d2eed1c0..f50d51e80a 100644 --- a/build.xml +++ b/build.xml @@ -281,7 +281,7 @@ INITIALISATION - + @@ -490,7 +490,7 @@ PACKED LOCKER BUILD (PALO) - + @@ -640,12 +640,12 @@ QUICK BUILD (QUICK) - + - + @@ -968,7 +968,7 @@ PACKED QUICK BUILD (PACK) - + @@ -1901,7 +1901,7 @@ STABLE REFERENCE (STARR) - + diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 8e5ca2156a..31269829bf 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -27,7 +27,8 @@ import typechecker._ import transform._ import backend.icode.{ ICodes, GenICode, ICodeCheckers } -import backend.{ ScalaPrimitives, Platform, MSILPlatform, JavaPlatform } +// import backend.{ ScalaPrimitives, Platform, MSILPlatform, JavaPlatform } +import backend.{ ScalaPrimitives, Platform, JavaPlatform } import backend.jvm.GenJVM import backend.opt.{ Inliners, InlineExceptionHandlers, ClosureElimination, DeadCodeElimination } import backend.icode.analysis._ @@ -65,9 +66,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb type ThisPlatform = Platform { val global: Global.this.type } - lazy val platform: ThisPlatform = - if (forMSIL) new { val global: Global.this.type = Global.this } with MSILPlatform - else new { val global: Global.this.type = Global.this } with JavaPlatform + lazy val platform: ThisPlatform = new { val global: Global.this.type = Global.this } with JavaPlatform + // if (forMSIL) new { val global: Global.this.type = Global.this } with MSILPlatform + // else new { val global: Global.this.type = Global.this } with JavaPlatform def classPath: ClassPath[platform.BinaryRepr] = platform.classPath def rootLoader: LazyType = platform.rootLoader diff --git a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala index 65b1fbc229..a86528d492 100644 --- a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala @@ -1,65 +1,65 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package backend - -import ch.epfl.lamp.compiler.{ msil => msillib } -import util.{ ClassPath, MsilClassPath } -import msil.GenMSIL -import io.{ AbstractFile, MsilFile } - -trait MSILPlatform extends Platform { - import global._ - import definitions.{ ComparatorClass, BoxedNumberClass, getMember } - - type BinaryRepr = MsilFile - - if (settings.verbose.value) - inform("[AssemRefs = " + settings.assemrefs.value + "]") - - // phaseName = "msil" - object genMSIL extends { - val global: MSILPlatform.this.global.type = MSILPlatform.this.global - val runsAfter = List[String]("dce") - val runsRightAfter = None - } with GenMSIL - - lazy val classPath = MsilClassPath.fromSettings(settings) - def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]]) - // See discussion in JavaPlatForm for why we need a cast here. - - def platformPhases = List( - genMSIL // generate .msil files - ) - - lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_) - def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass - - def newClassLoader(bin: MsilFile): loaders.SymbolLoader = new loaders.MsilFileLoader(bin) - - /** - * Tells whether a class should be loaded and entered into the package - * scope. On .NET, this method returns `false` for all synthetic classes - * (anonymous classes, implementation classes, module classes), their - * symtab is encoded in the pickle of another class. - */ - def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = { - if (cls.binary.isDefined) { - val typ = cls.binary.get.msilType - if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) { - val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false) - assert(attrs.length == 1, attrs.length) - val a = attrs(0).asInstanceOf[msillib.Attribute] - // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle. - // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic. - a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR - } else true // always load non-scala types - } else true // always load source - } - - def needCompile(bin: MsilFile, src: AbstractFile) = - false // always use compiled file on .net -} +// /* NSC -- new Scala compiler +// * Copyright 2005-2011 LAMP/EPFL +// * @author Paul Phillips +// */ +// +// package scala.tools.nsc +// package backend +// +// import ch.epfl.lamp.compiler.{ msil => msillib } +// import util.{ ClassPath, MsilClassPath } +// import msil.GenMSIL +// import io.{ AbstractFile, MsilFile } +// +// trait MSILPlatform extends Platform { +// import global._ +// import definitions.{ ComparatorClass, BoxedNumberClass, getMember } +// +// type BinaryRepr = MsilFile +// +// if (settings.verbose.value) +// inform("[AssemRefs = " + settings.assemrefs.value + "]") +// +// // phaseName = "msil" +// object genMSIL extends { +// val global: MSILPlatform.this.global.type = MSILPlatform.this.global +// val runsAfter = List[String]("dce") +// val runsRightAfter = None +// } with GenMSIL +// +// lazy val classPath = MsilClassPath.fromSettings(settings) +// def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]]) +// // See discussion in JavaPlatForm for why we need a cast here. +// +// def platformPhases = List( +// genMSIL // generate .msil files +// ) +// +// lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_) +// def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass +// +// def newClassLoader(bin: MsilFile): loaders.SymbolLoader = new loaders.MsilFileLoader(bin) +// +// /** +// * Tells whether a class should be loaded and entered into the package +// * scope. On .NET, this method returns `false` for all synthetic classes +// * (anonymous classes, implementation classes, module classes), their +// * symtab is encoded in the pickle of another class. +// */ +// def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = { +// if (cls.binary.isDefined) { +// val typ = cls.binary.get.msilType +// if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) { +// val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false) +// assert(attrs.length == 1, attrs.length) +// val a = attrs(0).asInstanceOf[msillib.Attribute] +// // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle. +// // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic. +// a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR +// } else true // always load non-scala types +// } else true // always load source +// } +// +// def needCompile(bin: MsilFile, src: AbstractFile) = +// false // always use compiled file on .net +// } diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 3baff7da9e..acb20b4627 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -160,8 +160,8 @@ abstract class GenICode extends SubComponent { case Assign(lhs @ Select(_, _), rhs) => val isStatic = lhs.symbol.isStaticMember var ctx1 = if (isStatic) ctx - else if (forMSIL && msil_IsValuetypeInstField(lhs.symbol)) - msil_genLoadQualifierAddress(lhs, ctx) + // else if (forMSIL && msil_IsValuetypeInstField(lhs.symbol)) + // msil_genLoadQualifierAddress(lhs, ctx) else genLoadQualifier(lhs, ctx) ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info)) @@ -460,132 +460,132 @@ abstract class GenICode extends SubComponent { fun.symbol.simpleName + ") " + " at: " + (tree.pos) ) } - - /** - * forMSIL - */ - private def msil_IsValuetypeInstMethod(msym: Symbol) = ( - loaders.clrTypes.methods get msym exists (mMSIL => - mMSIL.IsInstance && mMSIL.DeclaringType.IsValueType - ) - ) - private def msil_IsValuetypeInstField(fsym: Symbol) = ( - loaders.clrTypes.fields get fsym exists (fMSIL => - !fMSIL.IsStatic && fMSIL.DeclaringType.IsValueType - ) - ) - - /** - * forMSIL: Adds a local var, the emitted code requires one more slot on the stack as on entry - */ - private def msil_genLoadZeroOfNonEnumValuetype(ctx: Context, kind: TypeKind, pos: Position, leaveAddressOnStackInstead: Boolean) { - val REFERENCE(clssym) = kind - assert(loaders.clrTypes.isNonEnumValuetype(clssym), clssym) - val local = ctx.makeLocal(pos, clssym.tpe, "tmp") - ctx.method.addLocal(local) - ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(local), pos) - ctx.bb.emit(CIL_INITOBJ(kind), pos) - val instr = if (leaveAddressOnStackInstead) - CIL_LOAD_LOCAL_ADDRESS(local) - else - LOAD_LOCAL(local) - ctx.bb.emit(instr, pos) - } - - /** - * forMSIL - */ - private def msil_genLoadAddressOf(tree: Tree, ctx: Context, expectedType: TypeKind, butRawValueIsAlsoGoodEnough: Boolean): Context = { - var generatedType = expectedType - var addressTaken = false - debuglog("at line: " + (if (tree.pos.isDefined) tree.pos.line else tree.pos)) - - var resCtx: Context = tree match { - - // emits CIL_LOAD_FIELD_ADDRESS - case Select(qualifier, selector) if (!tree.symbol.isModule) => - addressTaken = true - val sym = tree.symbol - generatedType = toTypeKind(sym.info) - - if (sym.isStaticMember) { - ctx.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, true), tree.pos) - ctx - } else { - val ctx1 = genLoadQualifier(tree, ctx) - ctx1.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, false), tree.pos) - ctx1 - } - - // emits CIL_LOAD_LOCAL_ADDRESS - case Ident(name) if (!tree.symbol.isPackage && !tree.symbol.isModule)=> - addressTaken = true - val sym = tree.symbol - try { - val Some(l) = ctx.method.lookupLocal(sym) - ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(l), tree.pos) - generatedType = l.kind // actually, should be "V&" but the callsite is aware of this - } catch { - case ex: MatchError => - abort("symbol " + sym + " does not exist in " + ctx.method) - } - ctx - - // emits CIL_LOAD_ARRAY_ITEM_ADDRESS - case Apply(fun, args) => - if (isPrimitive(fun.symbol)) { - - val sym = tree.symbol - val Apply(fun @ Select(receiver, _), args) = tree - val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) - - if (isArrayOp(code)) { - val arrayObj = receiver - val k = toTypeKind(arrayObj.tpe) - val ARRAY(elementType) = k - if (scalaPrimitives.isArrayGet(code)) { - var ctx1 = genLoad(arrayObj, ctx, k) - // load argument on stack - debugassert(args.length == 1, "Too many arguments for array get operation: " + tree) - ctx1 = genLoad(args.head, ctx1, INT) - generatedType = elementType // actually "managed pointer to element type" but the callsite is aware of this - ctx1.bb.emit(CIL_LOAD_ARRAY_ITEM_ADDRESS(elementType), tree.pos) - addressTaken = true - ctx1 - } else null - } else null - } else null - - case This(qual) => - /* TODO: this case handler is a placeholder for the time when Level 2 support for valuetypes is in place, - in particular when invoking other methods on this where this is a valuetype value (boxed or not). - As receiver, a managed pointer is expected, and a plain ldarg.0 achieves just that. */ - addressTaken = true - genLoad(tree, ctx, expectedType) - - case _ => - null /* A method returning ByRef won't pass peverify, so I guess this case handler is dead code. - Even if it's not, the code below to handler !addressTaken below. */ - } - - if (!addressTaken) { - resCtx = genLoad(tree, ctx, expectedType) - if (!butRawValueIsAlsoGoodEnough) { - // raw value on stack (must be an intermediate result, e.g. returned by method call), take address - addressTaken = true - val boxType = expectedType // toTypeKind(expectedType /* TODO FIXME */) - resCtx.bb.emit(BOX(boxType), tree.pos) - resCtx.bb.emit(CIL_UNBOX(boxType), tree.pos) - } - } - - // emit conversion - if (generatedType != expectedType) - abort("Unexpected tree in msil_genLoadAddressOf: " + tree + " at: " + tree.pos) - - resCtx - } - + // + // /** + // * forMSIL + // */ + // private def msil_IsValuetypeInstMethod(msym: Symbol) = ( + // loaders.clrTypes.methods get msym exists (mMSIL => + // mMSIL.IsInstance && mMSIL.DeclaringType.IsValueType + // ) + // ) + // private def msil_IsValuetypeInstField(fsym: Symbol) = ( + // loaders.clrTypes.fields get fsym exists (fMSIL => + // !fMSIL.IsStatic && fMSIL.DeclaringType.IsValueType + // ) + // ) + // + // /** + // * forMSIL: Adds a local var, the emitted code requires one more slot on the stack as on entry + // */ + // private def msil_genLoadZeroOfNonEnumValuetype(ctx: Context, kind: TypeKind, pos: Position, leaveAddressOnStackInstead: Boolean) { + // val REFERENCE(clssym) = kind + // assert(loaders.clrTypes.isNonEnumValuetype(clssym), clssym) + // val local = ctx.makeLocal(pos, clssym.tpe, "tmp") + // ctx.method.addLocal(local) + // ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(local), pos) + // ctx.bb.emit(CIL_INITOBJ(kind), pos) + // val instr = if (leaveAddressOnStackInstead) + // CIL_LOAD_LOCAL_ADDRESS(local) + // else + // LOAD_LOCAL(local) + // ctx.bb.emit(instr, pos) + // } + // + // /** + // * forMSIL + // */ + // private def msil_genLoadAddressOf(tree: Tree, ctx: Context, expectedType: TypeKind, butRawValueIsAlsoGoodEnough: Boolean): Context = { + // var generatedType = expectedType + // var addressTaken = false + // debuglog("at line: " + (if (tree.pos.isDefined) tree.pos.line else tree.pos)) + // + // var resCtx: Context = tree match { + // + // // emits CIL_LOAD_FIELD_ADDRESS + // case Select(qualifier, selector) if (!tree.symbol.isModule) => + // addressTaken = true + // val sym = tree.symbol + // generatedType = toTypeKind(sym.info) + // + // if (sym.isStaticMember) { + // ctx.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, true), tree.pos) + // ctx + // } else { + // val ctx1 = genLoadQualifier(tree, ctx) + // ctx1.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, false), tree.pos) + // ctx1 + // } + // + // // emits CIL_LOAD_LOCAL_ADDRESS + // case Ident(name) if (!tree.symbol.isPackage && !tree.symbol.isModule)=> + // addressTaken = true + // val sym = tree.symbol + // try { + // val Some(l) = ctx.method.lookupLocal(sym) + // ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(l), tree.pos) + // generatedType = l.kind // actually, should be "V&" but the callsite is aware of this + // } catch { + // case ex: MatchError => + // abort("symbol " + sym + " does not exist in " + ctx.method) + // } + // ctx + // + // // emits CIL_LOAD_ARRAY_ITEM_ADDRESS + // case Apply(fun, args) => + // if (isPrimitive(fun.symbol)) { + // + // val sym = tree.symbol + // val Apply(fun @ Select(receiver, _), args) = tree + // val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) + // + // if (isArrayOp(code)) { + // val arrayObj = receiver + // val k = toTypeKind(arrayObj.tpe) + // val ARRAY(elementType) = k + // if (scalaPrimitives.isArrayGet(code)) { + // var ctx1 = genLoad(arrayObj, ctx, k) + // // load argument on stack + // debugassert(args.length == 1, "Too many arguments for array get operation: " + tree) + // ctx1 = genLoad(args.head, ctx1, INT) + // generatedType = elementType // actually "managed pointer to element type" but the callsite is aware of this + // ctx1.bb.emit(CIL_LOAD_ARRAY_ITEM_ADDRESS(elementType), tree.pos) + // addressTaken = true + // ctx1 + // } else null + // } else null + // } else null + // + // case This(qual) => + // /* TODO: this case handler is a placeholder for the time when Level 2 support for valuetypes is in place, + // in particular when invoking other methods on this where this is a valuetype value (boxed or not). + // As receiver, a managed pointer is expected, and a plain ldarg.0 achieves just that. */ + // addressTaken = true + // genLoad(tree, ctx, expectedType) + // + // case _ => + // null /* A method returning ByRef won't pass peverify, so I guess this case handler is dead code. + // Even if it's not, the code below to handler !addressTaken below. */ + // } + // + // if (!addressTaken) { + // resCtx = genLoad(tree, ctx, expectedType) + // if (!butRawValueIsAlsoGoodEnough) { + // // raw value on stack (must be an intermediate result, e.g. returned by method call), take address + // addressTaken = true + // val boxType = expectedType // toTypeKind(expectedType /* TODO FIXME */) + // resCtx.bb.emit(BOX(boxType), tree.pos) + // resCtx.bb.emit(CIL_UNBOX(boxType), tree.pos) + // } + // } + // + // // emit conversion + // if (generatedType != expectedType) + // abort("Unexpected tree in msil_genLoadAddressOf: " + tree + " at: " + tree.pos) + // + // resCtx + // } + // /** * Generate code for trees that produce values on the stack @@ -793,19 +793,19 @@ abstract class GenICode extends SubComponent { debugassert(ctor.owner == cls, "Symbol " + ctor.owner.fullName + " is different than " + tpt) - val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) { - /* parameterful constructors are the only possible custom constructors, - a default constructor can't be defined for valuetypes, CLR dixit */ - val isDefaultConstructor = args.isEmpty - if (isDefaultConstructor) { - msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false) - ctx - } else { - val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx) - ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos) - ctx1 - } - } else { + // val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) { + // /* parameterful constructors are the only possible custom constructors, + // a default constructor can't be defined for valuetypes, CLR dixit */ + // val isDefaultConstructor = args.isEmpty + // if (isDefaultConstructor) { + // msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false) + // ctx + // } else { + // val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx) + // ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos) + // ctx1 + // } + // } else { val nw = NEW(rt) ctx.bb.emit(nw, tree.pos) ctx.bb.emit(DUP(generatedType)) @@ -815,8 +815,8 @@ abstract class GenICode extends SubComponent { nw.init = init ctx1.bb.emit(init, tree.pos) ctx1 - } - ctx2 + // } + // ctx2 case _ => abort("Cannot instantiate " + tpt + "of kind: " + generatedType) @@ -845,12 +845,12 @@ abstract class GenICode extends SubComponent { generatedType = boxType ctx1.bb.emit(UNBOX(boxType), expr.pos) ctx1 - - case Apply(fun @ _, List(expr)) if (forMSIL && loaders.clrTypes.isAddressOf(fun.symbol)) => - debuglog("ADDRESSOF : " + fun.symbol.fullName); - val ctx1 = msil_genLoadAddressOf(expr, ctx, toTypeKind(expr.tpe), butRawValueIsAlsoGoodEnough = false) - generatedType = toTypeKind(fun.symbol.tpe.resultType) - ctx1 + // + // case Apply(fun @ _, List(expr)) if (forMSIL && loaders.clrTypes.isAddressOf(fun.symbol)) => + // debuglog("ADDRESSOF : " + fun.symbol.fullName); + // val ctx1 = msil_genLoadAddressOf(expr, ctx, toTypeKind(expr.tpe), butRawValueIsAlsoGoodEnough = false) + // generatedType = toTypeKind(fun.symbol.tpe.resultType) + // ctx1 case app @ Apply(fun, args) => val sym = fun.symbol @@ -887,9 +887,9 @@ abstract class GenICode extends SubComponent { var ctx1 = if (invokeStyle.hasInstance) { - if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym)) - msil_genLoadQualifierAddress(fun, ctx) - else + // if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym)) + // msil_genLoadQualifierAddress(fun, ctx) + // else genLoadQualifier(fun, ctx) } else ctx @@ -1150,15 +1150,15 @@ abstract class GenICode extends SubComponent { case _ => abort("Unknown qualifier " + tree) } - - /** forMSIL */ - private def msil_genLoadQualifierAddress(tree: Tree, ctx: Context): Context = - tree match { - case Select(qualifier, _) => - msil_genLoadAddressOf(qualifier, ctx, toTypeKind(qualifier.tpe), butRawValueIsAlsoGoodEnough = false) - case _ => - abort("Unknown qualifier " + tree) - } + // + // /** forMSIL */ + // private def msil_genLoadQualifierAddress(tree: Tree, ctx: Context): Context = + // tree match { + // case Select(qualifier, _) => + // msil_genLoadAddressOf(qualifier, ctx, toTypeKind(qualifier.tpe), butRawValueIsAlsoGoodEnough = false) + // case _ => + // abort("Unknown qualifier " + tree) + // } /** * Generate code that loads args into label parameters. diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index 2bcfb9d4a9..bf8580b903 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -636,63 +636,63 @@ trait Opcodes { self: ICodes => // CLR backend - - case class CIL_LOAD_LOCAL_ADDRESS(local: Local) extends Instruction { - /** Returns a string representation of this instruction */ - override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local //+isArgument?" (argument)":""; - - override def consumed = 0 - override def produced = 1 - - override def producedTypes = List(msil_mgdptr(local.kind)) - } - - case class CIL_LOAD_FIELD_ADDRESS(field: Symbol, isStatic: Boolean) extends Instruction { - /** Returns a string representation of this instruction */ - override def toString(): String = - "CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString) - - override def consumed = if (isStatic) 0 else 1 - override def produced = 1 - - override def consumedTypes = if (isStatic) Nil else List(REFERENCE(field.owner)); - override def producedTypes = List(msil_mgdptr(REFERENCE(field.owner))); -} - - case class CIL_LOAD_ARRAY_ITEM_ADDRESS(kind: TypeKind) extends Instruction { - /** Returns a string representation of this instruction */ - override def toString(): String = "CIL_LOAD_ARRAY_ITEM_ADDRESS (" + kind + ")" - - override def consumed = 2 - override def produced = 1 - - override def consumedTypes = List(ARRAY(kind), INT) - override def producedTypes = List(msil_mgdptr(kind)) - } - - case class CIL_UNBOX(valueType: TypeKind) extends Instruction { - override def toString(): String = "CIL_UNBOX " + valueType - override def consumed = 1 - override def consumedTypes = ObjectReference :: Nil // actually consumes a 'boxed valueType' - override def produced = 1 - override def producedTypes = List(msil_mgdptr(valueType)) - } - - case class CIL_INITOBJ(valueType: TypeKind) extends Instruction { - override def toString(): String = "CIL_INITOBJ " + valueType - override def consumed = 1 - override def consumedTypes = ObjectReference :: Nil // actually consumes a managed pointer - override def produced = 0 - } - - case class CIL_NEWOBJ(method: Symbol) extends Instruction { - override def toString(): String = "CIL_NEWOBJ " + hostClass.fullName + method.fullName - var hostClass: Symbol = method.owner; - override def consumed = method.tpe.paramTypes.length - override def consumedTypes = method.tpe.paramTypes map toTypeKind - override def produced = 1 - override def producedTypes = List(toTypeKind(method.tpe.resultType)) - } +// +// case class CIL_LOAD_LOCAL_ADDRESS(local: Local) extends Instruction { +// /** Returns a string representation of this instruction */ +// override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local //+isArgument?" (argument)":""; +// +// override def consumed = 0 +// override def produced = 1 +// +// override def producedTypes = List(msil_mgdptr(local.kind)) +// } +// +// case class CIL_LOAD_FIELD_ADDRESS(field: Symbol, isStatic: Boolean) extends Instruction { +// /** Returns a string representation of this instruction */ +// override def toString(): String = +// "CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString) +// +// override def consumed = if (isStatic) 0 else 1 +// override def produced = 1 +// +// override def consumedTypes = if (isStatic) Nil else List(REFERENCE(field.owner)); +// override def producedTypes = List(msil_mgdptr(REFERENCE(field.owner))); +// } +// +// case class CIL_LOAD_ARRAY_ITEM_ADDRESS(kind: TypeKind) extends Instruction { +// /** Returns a string representation of this instruction */ +// override def toString(): String = "CIL_LOAD_ARRAY_ITEM_ADDRESS (" + kind + ")" +// +// override def consumed = 2 +// override def produced = 1 +// +// override def consumedTypes = List(ARRAY(kind), INT) +// override def producedTypes = List(msil_mgdptr(kind)) +// } +// +// case class CIL_UNBOX(valueType: TypeKind) extends Instruction { +// override def toString(): String = "CIL_UNBOX " + valueType +// override def consumed = 1 +// override def consumedTypes = ObjectReference :: Nil // actually consumes a 'boxed valueType' +// override def produced = 1 +// override def producedTypes = List(msil_mgdptr(valueType)) +// } +// +// case class CIL_INITOBJ(valueType: TypeKind) extends Instruction { +// override def toString(): String = "CIL_INITOBJ " + valueType +// override def consumed = 1 +// override def consumedTypes = ObjectReference :: Nil // actually consumes a managed pointer +// override def produced = 0 +// } +// +// case class CIL_NEWOBJ(method: Symbol) extends Instruction { +// override def toString(): String = "CIL_NEWOBJ " + hostClass.fullName + method.fullName +// var hostClass: Symbol = method.owner; +// override def consumed = method.tpe.paramTypes.length +// override def consumedTypes = method.tpe.paramTypes map toTypeKind +// override def produced = 1 +// override def producedTypes = List(toTypeKind(method.tpe.resultType)) +// } } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index a485272ca6..998ac90778 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -423,11 +423,10 @@ trait TypeKinds { self: ICodes => primitiveTypeMap.getOrElse(sym, newReference(sym)) private def primitiveOrClassType(sym: Symbol, targs: List[Type]) = primitiveTypeMap.getOrElse(sym, arrayOrClassType(sym, targs)) - - def msil_mgdptr(tk: TypeKind): TypeKind = (tk: @unchecked) match { - case REFERENCE(cls) => REFERENCE(loaders.clrTypes.mdgptrcls4clssym(cls)) - // TODO have ready class-symbols for the by-ref versions of built-in valuetypes - case _ => abort("cannot obtain a managed pointer for " + tk) - } - + // + // def msil_mgdptr(tk: TypeKind): TypeKind = (tk: @unchecked) match { + // case REFERENCE(cls) => REFERENCE(loaders.clrTypes.mdgptrcls4clssym(cls)) + // // TODO have ready class-symbols for the by-ref versions of built-in valuetypes + // case _ => abort("cannot obtain a managed pointer for " + tk) + // } } diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index d2e54ff3f1..ab07f2e4fc 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -1,2357 +1,2357 @@ -/* NSC -- new scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Nikolay Mihaylov - */ - - -package scala.tools.nsc -package backend.msil - -import java.io.{File, IOException} -import java.nio.{ByteBuffer, ByteOrder} -import scala.collection.{ mutable, immutable } -import scala.tools.nsc.symtab._ - -import ch.epfl.lamp.compiler.msil.{Type => MsilType, _} -import ch.epfl.lamp.compiler.msil.emit._ -import ch.epfl.lamp.compiler.msil.util.PECustomMod - -abstract class GenMSIL extends SubComponent { - import global._ - import loaders.clrTypes - import clrTypes.{types, constructors, methods, fields} - import icodes._ - import icodes.opcodes._ - - val x = loaders - - /** Create a new phase */ - override def newPhase(p: Phase) = new MsilPhase(p) - - val phaseName = "msil" - /** MSIL code generation phase - */ - class MsilPhase(prev: Phase) extends GlobalPhase(prev) { - def name = phaseName - override def newFlags = phaseNewFlags - - override def erasedTypes = true - - override def run() { - if (settings.debug.value) inform("[running phase " + name + " on icode]") - - val codeGenerator = new BytecodeGenerator - - //classes is ICodes.classes, a HashMap[Symbol, IClass] - classes.values foreach codeGenerator.findEntryPoint - if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead - val entryclass = opt.showClass.get.toString - warning("Couldn't find entry class " + entryclass) - } - - codeGenerator.initAssembly - - val classesSorted = classes.values.toList.sortBy(c => c.symbol.id) // simplifies comparing cross-compiler vs. .exe output - classesSorted foreach codeGenerator.createTypeBuilder - classesSorted foreach codeGenerator.createClassMembers - - try { - classesSorted foreach codeGenerator.genClass - } finally { - codeGenerator.writeAssembly - } - } - - override def apply(unit: CompilationUnit) { - abort("MSIL works on icode classes, not on compilation units!") - } - } - - /** - * MSIL bytecode generator. - * - */ - class BytecodeGenerator { - - val MODULE_INSTANCE_NAME = "MODULE$" - - import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, BYTE => MBYTE, SHORT => MSHORT, - CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT, - DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING, - STRING_ARRAY => MSTRING_ARRAY, - SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR, - SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR} - - val EXCEPTION = clrTypes.getType("System.Exception") - val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE) - - val ICLONEABLE = clrTypes.getType("System.ICloneable") - val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes) - - val MMONITOR = clrTypes.getType("System.Threading.Monitor") - val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT)) - val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT)) - - val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder") - val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes) - val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString", - MsilType.EmptyTypes) - - val TYPE_FROM_HANDLE = - clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle"))) - - val INT_PTR = clrTypes.getType("System.IntPtr") - - val JOBJECT = definitions.ObjectClass - val JSTRING = definitions.StringClass - - val SystemConvert = clrTypes.getType("System.Convert") - - val objParam = Array(MOBJECT) - - val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam) // see comment in emitUnbox - val toSByte: MethodInfo = SystemConvert.GetMethod("ToSByte", objParam) - val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam) - val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam) - val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam) - val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam) - val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam) - val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam) - - //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT") - val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT) - - // Scala attributes - // symtab.Definitions -> object (singleton..) - val SerializableAttr = definitions.SerializableAttr.tpe - val CloneableAttr = definitions.CloneableAttr.tpe - val TransientAtt = definitions.TransientAttr.tpe - // remoting: the architectures are too different, no mapping (no portable code - // possible) - - // java instance methods that are mapped to static methods in .net - // these will need to be called with OpCodes.Call (not Callvirt) - val dynToStatMapped = mutable.HashSet[Symbol]() - - initMappings() - - /** Create the mappings between java and .net classes and methods */ - private def initMappings() { - mapType(definitions.AnyClass, MOBJECT) - mapType(definitions.AnyRefClass, MOBJECT) - //mapType(definitions.NullClass, clrTypes.getType("scala.AllRef$")) - //mapType(definitions.NothingClass, clrTypes.getType("scala.All$")) - // FIXME: for some reason the upper two lines map to null - mapType(definitions.NullClass, EXCEPTION) - mapType(definitions.NothingClass, EXCEPTION) - - mapType(definitions.BooleanClass, MBOOL) - mapType(definitions.ByteClass, MBYTE) - mapType(definitions.ShortClass, MSHORT) - mapType(definitions.CharClass, MCHAR) - mapType(definitions.IntClass, MINT) - mapType(definitions.LongClass, MLONG) - mapType(definitions.FloatClass, MFLOAT) - mapType(definitions.DoubleClass, MDOUBLE) - } - - var clasz: IClass = _ - var method: IMethod = _ - - var massembly: AssemblyBuilder = _ - var mmodule: ModuleBuilder = _ - var mcode: ILGenerator = _ - - var assemName: String = _ - var firstSourceName = "" - var outDir: File = _ - var srcPath: File = _ - var moduleName: String = _ - - def initAssembly() { - - assemName = settings.assemname.value - - if (assemName == "") { - if (entryPoint != null) { - assemName = msilName(entryPoint.enclClass) - // remove the $ at the end (from module-name) - assemName = assemName.substring(0, assemName.length() - 1) - } else { - // assuming filename of first source file - assert(firstSourceName.endsWith(".scala"), firstSourceName) - assemName = firstSourceName.substring(0, firstSourceName.length() - 6) - } - } else { - if (assemName.endsWith(".msil")) - assemName = assemName.substring(0, assemName.length()-5) - if (assemName.endsWith(".il")) - assemName = assemName.substring(0, assemName.length()-3) - val f: File = new File(assemName) - assemName = f.getName() - } - - outDir = new File(settings.outdir.value) - - srcPath = new File(settings.sourcedir.value) - - val assemblyName = new AssemblyName() - assemblyName.Name = assemName - massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName) - - moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe") - // filename here: .dll or .exe (in both parameters), second: give absolute-path - mmodule = massembly.DefineDynamicModule(moduleName, - new File(outDir, moduleName).getAbsolutePath()) - assert (mmodule != null) - } - - - /** - * Form of the custom Attribute parameter (Ecma-335.pdf) - * - p. 163 for CustomAttrib Form, - * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!) - * !! least significant byte first if values longer than one byte !! - * - * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00 - * 2: FixedArgs (directly the data, get number and types from related constructor) - * 2.1: length of the array (unsigned int32, 4 bytes, least significant first) - * 2.2: the byte array data - * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000) - */ - def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) { - def addMarker() { - val markerSymtab = new Array[Byte](4) - markerSymtab(0) = 1.toByte - tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR, markerSymtab) - } - - // both conditions are needed (why exactly..?) - if (tBuilder.Name.endsWith("$") || sym.isModuleClass) { - addMarker() - } else { - currentRun.symData.get(sym) match { - case Some(pickle) => - var size = pickle.writeIndex - val symtab = new Array[Byte](size + 8) - symtab(0) = 1.toByte - for (i <- 2 until 6) { - symtab(i) = (size & 0xff).toByte - size = size >> 8 - } - java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) - - tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) - - currentRun.symData -= sym - currentRun.symData -= sym.companionSymbol - - case _ => - addMarker() - } - } - } - - /** - * Mutates `member` adding CLR attributes (if any) based on sym.annotations. - * Please notice that CLR custom modifiers are a different beast (see customModifiers below) - * and thus shouldn't be added by this method. - */ - def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) { - val attributes = annotations.map(_.atp.typeSymbol).collect { - case definitions.TransientAttr => null // TODO this is just an example - } - return // TODO: implement at some point - } - - /** - * What's a CLR custom modifier? Intro available as source comments in compiler.msil.CustomModifier. - * It's basically a marker associated with a location (think of FieldInfo, ParameterInfo, and PropertyInfo) - * and thus that marker (be it optional or required) becomes part of the signature of that location. - * Some annotations will become CLR attributes (see addAttributes above), others custom modifiers (this method). - */ - def customModifiers(annotations: List[AnnotationInfo]): Array[CustomModifier] = { - annotations.map(_.atp.typeSymbol).collect { - case definitions.VolatileAttr => new CustomModifier(true, CustomModifier.VolatileMarker) - } toArray - } - - - - /* - debuglog("creating annotations: " + annotations + " for member : " + member) - for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ; - if annot.isConstant) - //!typ.typeSymbol.isJavaDefined - { -// assert(consts.length <= 1, -// "too many constant arguments for annotations; "+consts.toString()) - - // Problem / TODO having the symbol of the annotations type would be nicer - // (i hope that type.typeSymbol is the same as the one in types2create) - // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder) - // when this is solved, types2create will be the same as icodes.classes, thus superfluous - val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder] -// val annType: MsilType = getType(typ.typeSymbol) - - // Problem / TODO: i have no idea which constructor is used. This - // information should be available in AnnotationInfo. - annType.CreateType() // else, GetConstructors can't be used - val constr: ConstructorInfo = annType.GetConstructors()(0) - // prevent a second call of CreateType, only needed because there's no - // other way than GetConstructors()(0) to get the constructor, if there's - // no constructor symbol available. - - val args: Array[Byte] = - getAttributeArgs( - annArgs map (_.constant.get), - (for((n,v) <- nvPairs) yield (n, v.constant.get))) - member.SetCustomAttribute(constr, args) - } - } */ - -/* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { - val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough! - buf.order(ByteOrder.LITTLE_ENDIAN) - buf.putShort(1.toShort) // signature - - def emitSerString(str: String) = { - // this is wrong, it has to be the length of the UTF-8 byte array, which - // may be longer (see clr-book on page 302) -// val length: Int = str.length - val strBytes: Array[Byte] = try { - str.getBytes("UTF-8") - } catch { - case _: Error => abort("could not get byte-array for string: " + str) - } - val length: Int = strBytes.length //this length is stored big-endian - if (length < 128) - buf.put(length.toByte) - else if (length < (1<<14)) { - buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0' - buf.put((length | 0xff).toByte) - } else if (length < (1 << 29)) { - buf.put(((length >> 24) | 0xc0).toByte) - buf.put(((length >> 16) & 0xff).toByte) - buf.put(((length >> 8) & 0xff).toByte) - buf.put(((length ) & 0xff).toByte) - } else - abort("string too long for attribute parameter: " + length) - buf.put(strBytes) - } - - def emitConst(const: Constant): Unit = const.tag match { - case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte) - case ByteTag => buf.put(const.byteValue) - case ShortTag => buf.putShort(const.shortValue) - case CharTag => buf.putChar(const.charValue) - case IntTag => buf.putInt(const.intValue) - case LongTag => buf.putLong(const.longValue) - case FloatTag => buf.putFloat(const.floatValue) - case DoubleTag => buf.putDouble(const.doubleValue) - case StringTag => - val str: String = const.stringValue - if (str == null) { - buf.put(0xff.toByte) - } else { - emitSerString(str) - } - case ArrayTag => - val arr: Array[Constant] = const.arrayValue - if (arr == null) { - buf.putInt(0xffffffff) - } else { - buf.putInt(arr.length) - arr.foreach(emitConst) - } - - // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ??? - - case _ => abort("could not handle attribute argument: " + const) - } - - consts foreach emitConst - buf.putShort(nvPairs.length.toShort) - def emitNamedArg(nvPair: (Name, Constant)) { - // the named argument is a property of the attribute (it can't be a field, since - // all fields in scala are private) - buf.put(0x54.toByte) - - def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151 - case BooleanTag => buf.put(0x02.toByte) - case ByteTag => buf.put(0x05.toByte) - case ShortTag => buf.put(0x06.toByte) - case CharTag => buf.put(0x07.toByte) - case IntTag => buf.put(0x08.toByte) - case LongTag => buf.put(0x0a.toByte) - case FloatTag => buf.put(0x0c.toByte) - case DoubleTag => buf.put(0x0d.toByte) - case StringTag => buf.put(0x0e.toByte) - - // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ??? - - // ArrayTag falls in here - case _ => abort("could not handle attribute argument: " + c) - } - - val cnst: Constant = nvPair._2 - if (cnst.tag == ArrayTag) { - buf.put(0x1d.toByte) - emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0 - } else if (cnst.tag == EnumTag) { - buf.put(0x55.toByte) - // TODO: put a SerString (don't know what exactly, names of the enums somehow..) - } else { - buf.put(0x51.toByte) - emitType(cnst) - } - - emitSerString(nvPair._1.toString) - emitConst(nvPair._2) - } - - val length = buf.position() - buf.array().slice(0, length) - } */ - - def writeAssembly() { - if (entryPoint != null) { - assert(entryPoint.enclClass.isModuleClass, entryPoint.enclClass) - val mainMethod = methods(entryPoint) - val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY) - val globalMain = mmodule.DefineGlobalMethod( - "Main", MethodAttributes.Public | MethodAttributes.Static, - MVOID, stringArrayTypes) - globalMain.DefineParameter(0, ParameterAttributes.None, "args") - massembly.SetEntryPoint(globalMain) - val code = globalMain.GetILGenerator() - val moduleField = getModuleInstanceField(entryPoint.enclClass) - code.Emit(OpCodes.Ldsfld, moduleField) - code.Emit(OpCodes.Ldarg_0) - code.Emit(OpCodes.Callvirt, mainMethod) - code.Emit(OpCodes.Ret) - } - createTypes() - var outDirName: String = null - try { - if (settings.Ygenjavap.isDefault) { // we reuse the JVM-sounding setting because it's conceptually similar - outDirName = outDir.getPath() - massembly.Save(outDirName + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */ - } else { - outDirName = srcPath.getPath() - massembly.Save(settings.Ygenjavap.value, outDirName) /* use MultipleFilesILPrinterVisitor */ - } - } catch { - case e:IOException => abort("Could not write to " + outDirName + ": " + e.getMessage()) - } - } - - private def createTypes() { - for (sym <- classes.keys) { - val iclass = classes(sym) - val tBuilder = types(sym).asInstanceOf[TypeBuilder] - - debuglog("Calling CreatType for " + sym + ", " + tBuilder.toString) - - tBuilder.CreateType() - tBuilder.setSourceFilepath(iclass.cunit.source.file.path) - } - } - - private[GenMSIL] def ilasmFileName(iclass: IClass) : String = { - // method.sourceFile contains just the filename - iclass.cunit.source.file.toString.replace("\\", "\\\\") - } - - private[GenMSIL] def genClass(iclass: IClass) { - val sym = iclass.symbol - debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags)) - clasz = iclass - - val tBuilder = getType(sym).asInstanceOf[TypeBuilder] - if (isCloneable(sym)) { - // FIXME: why there's no nme.clone_ ? - // "Clone": if the code is non-portable, "Clone" is defined, not "clone" - // TODO: improve condition (should override AnyRef.clone) - if (iclass.methods.forall(m => { - !((m.symbol.name.toString != "clone" || m.symbol.name.toString != "Clone") && - m.symbol.tpe.paramTypes.length != 0) - })) { - debuglog("auto-generating cloneable method for " + sym) - val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual | - MethodAttributes.HideBySig).toShort - val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT, - MsilType.EmptyTypes) - val clCode = cloneMethod.GetILGenerator() - clCode.Emit(OpCodes.Ldarg_0) - clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE) - clCode.Emit(OpCodes.Ret) - } - } - - val line = sym.pos.line - tBuilder.setPosition(line, ilasmFileName(iclass)) - - if (isTopLevelModule(sym)) { - if (sym.companionClass == NoSymbol) - generateMirrorClass(sym) - else - log("No mirror class for module with linked class: " + - sym.fullName) - } - - addSymtabAttribute(sym, tBuilder) - addAttributes(tBuilder, sym.annotations) - - if (iclass.symbol != definitions.ArrayClass) - iclass.methods foreach genMethod - - } //genClass - - - private def genMethod(m: IMethod) { - debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + - " owner: " + m.symbol.owner) - method = m - localBuilders.clear - computeLocalVarsIndex(m) - - if (m.symbol.isClassConstructor) { - mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator() - } else { - val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder] - if (!mBuilder.IsAbstract()) - try { - mcode = mBuilder.GetILGenerator() - } catch { - case e: Exception => - java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) - java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner) - java.lang.System.out.println("mBuilder = " + mBuilder) - java.lang.System.out.println("mBuilder.DeclaringType = " + - TypeAttributes.toString(mBuilder.DeclaringType.Attributes) + - "::" + mBuilder.DeclaringType) - throw e - } - else - mcode = null - } - - if (mcode != null) { - for (local <- m.locals ; if !(m.params contains local)) { - debuglog("add local var: " + local + ", of kind " + local.kind) - val t: MsilType = msilType(local.kind) - val localBuilder = mcode.DeclareLocal(t) - localBuilder.SetLocalSymInfo(msilName(local.sym)) - localBuilders(local) = localBuilder - } - genCode(m) - } - - } - - /** Special linearizer for methods with at least one exception handler. This - * linearizer brings all basic blocks in the right order so that nested - * try-catch and try-finally blocks can be emitted. - */ - val msilLinearizer = new MSILLinearizer() - - val labels = mutable.HashMap[BasicBlock, Label]() - - /* when emitting .line, it's enough to include the full filename just once per method, thus reducing filesize. - * this scheme relies on the fact that the entry block is emitted first. */ - var dbFilenameSeen = false - - def genCode(m: IMethod) { - - def makeLabels(blocks: List[BasicBlock]) = { - debuglog("Making labels for: " + method) - for (bb <- blocks) labels(bb) = mcode.DefineLabel() - } - - labels.clear - - var linearization = if(!m.exh.isEmpty) msilLinearizer.linearize(m) - else linearizer.linearize(m) - - if (!m.exh.isEmpty) - linearization = computeExceptionMaps(linearization, m) - - makeLabels(linearization) - - // debug val blocksInM = m.code.blocks.toList.sortBy(bb => bb.label) - // debug val blocksInL = linearization.sortBy(bb => bb.label) - // debug val MButNotL = (blocksInM.toSet) diff (blocksInL.toSet) // if non-empty, a jump to B fails to find a label for B (case CJUMP, case CZJUMP) - // debug if(!MButNotL.isEmpty) { } - - dbFilenameSeen = false - genBlocks(linearization) - - // RETURN inside exception blocks are replaced by Leave. The target of the - // leave is a `Ret` outside any exception block (generated here). - if (handlerReturnMethod == m) { - mcode.MarkLabel(handlerReturnLabel) - if (handlerReturnKind != UNIT) - mcode.Emit(OpCodes.Ldloc, handlerReturnLocal) - mcode.Emit(OpCodes.Ret) - } - - beginExBlock.clear() - beginCatchBlock.clear() - endExBlock.clear() - endFinallyLabels.clear() - } - - def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) { - blocks match { - case Nil => () - case x :: Nil => genBlock(x, prev = previous, next = null) - case x :: y :: ys => genBlock(x, prev = previous, next = y); genBlocks(y :: ys, previous = x) - } - } - - // the try blocks starting at a certain BasicBlock - val beginExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() - - // the catch blocks starting / endling at a certain BasicBlock - val beginCatchBlock = mutable.HashMap[BasicBlock, ExceptionHandler]() - val endExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() - - /** When emitting the code (genBlock), the number of currently active try / catch - * blocks. When seeing a `RETURN` inside a try / catch, we need to - * - store the result in a local (if it's not UNIT) - * - emit `Leave handlerReturnLabel` instead of the Return - * - emit code at the end: load the local and return its value - */ - var currentHandlers = new mutable.Stack[ExceptionHandler] - // The IMethod the Local/Label/Kind below belong to - var handlerReturnMethod: IMethod = _ - // Stores the result when returning inside an exception block - var handlerReturnLocal: LocalBuilder = _ - // Label for a return instruction outside any exception block - var handlerReturnLabel: Label = _ - // The result kind. - var handlerReturnKind: TypeKind = _ - def returnFromHandler(kind: TypeKind): (LocalBuilder, Label) = { - if (handlerReturnMethod != method) { - handlerReturnMethod = method - if (kind != UNIT) { - handlerReturnLocal = mcode.DeclareLocal(msilType(kind)) - handlerReturnLocal.SetLocalSymInfo("$handlerReturn") - } - handlerReturnLabel = mcode.DefineLabel() - handlerReturnKind = kind - } - (handlerReturnLocal, handlerReturnLabel) - } - - /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the - * Leave target has to be inside the finally (and it has to be the `endfinally` instruction). - * So for every finalizer, we have a label which marks the place of the `endfinally`, - * nested try/catch blocks will leave there. - */ - val endFinallyLabels = mutable.HashMap[ExceptionHandler, Label]() - - /** Computes which blocks are the beginning / end of a try or catch block */ - private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = { - val visitedBlocks = new mutable.HashSet[BasicBlock]() - - // handlers which have not been introduced so far - var openHandlers = m.exh - - - /** Example - * try { - * try { - * // *1* - * } catch { - * case h1 => - * } - * } catch { - * case h2 => - * case h3 => - * try { - * - * } catch { - * case h4 => // *2* - * case h5 => - * } - * } - */ - - // Stack of nested try blocks. Each bloc has a List of ExceptionHandler (multiple - // catch statements). Example *1*: Stack(List(h2, h3), List(h1)) - val currentTryHandlers = new mutable.Stack[List[ExceptionHandler]]() - - // Stack of nested catch blocks. The head of the list is the current catch block. The - // tail is all following catch blocks. Example *2*: Stack(List(h3), List(h4, h5)) - val currentCatchHandlers = new mutable.Stack[List[ExceptionHandler]]() - - for (b <- blocks) { - - // are we past the current catch blocks? - def endHandlers(): List[ExceptionHandler] = { - var res: List[ExceptionHandler] = Nil - if (!currentCatchHandlers.isEmpty) { - val handler = currentCatchHandlers.top.head - if (!handler.blocks.contains(b)) { - // all blocks of the handler are either visited, or not part of the linearization (i.e. dead) - assert(handler.blocks.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), - "Bad linearization of basic blocks inside catch. Found block not part of the handler\n"+ - b.fullString +"\nwhile in catch-part of\n"+ handler) - - val rest = currentCatchHandlers.pop.tail - if (rest.isEmpty) { - // all catch blocks of that exception handler are covered - res = handler :: endHandlers() - } else { - // there are more catch blocks for that try (handlers covering the same) - currentCatchHandlers.push(rest) - beginCatchBlock(b) = rest.head - } - } - } - res - } - val end = endHandlers() - if (!end.isEmpty) endExBlock(b) = end - - // are we past the current try block? - if (!currentTryHandlers.isEmpty) { - val handler = currentTryHandlers.top.head - if (!handler.covers(b)) { - // all of the covered blocks are visited, or not part of the linearization - assert(handler.covered.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), - "Bad linearization of basic blocks inside try. Found non-covered block\n"+ - b.fullString +"\nwhile in try-part of\n"+ handler) - - assert(handler.startBlock == b, - "Bad linearization of basic blocks. The entry block of a catch does not directly follow the try\n"+ - b.fullString +"\n"+ handler) - - val handlers = currentTryHandlers.pop - currentCatchHandlers.push(handlers) - beginCatchBlock(b) = handler - } - } - - // are there try blocks starting at b? - val (newHandlers, stillOpen) = openHandlers.partition(_.covers(b)) - openHandlers = stillOpen - - val newHandlersBySize = newHandlers.groupBy(_.covered.size) - // big handlers first, smaller ones are nested inside the try of the big one - // (checked by the assertions below) - val sizes = newHandlersBySize.keys.toList.sortWith(_ > _) - - val beginHandlers = new mutable.ListBuffer[ExceptionHandler] - for (s <- sizes) { - val sHandlers = newHandlersBySize(s) - for (h <- sHandlers) { - assert(h.covered == sHandlers.head.covered, - "bad nesting of exception handlers. same size, but not covering same blocks\n"+ - h +"\n"+ sHandlers.head) - assert(h.resultKind == sHandlers.head.resultKind, - "bad nesting of exception handlers. same size, but the same resultKind\n"+ - h +"\n"+ sHandlers.head) - } - for (bigger <- beginHandlers; h <- sHandlers) { - assert(h.covered.subsetOf(bigger.covered), - "bad nesting of exception handlers. try blocks of smaller handler are not nested in bigger one.\n"+ - h +"\n"+ bigger) - assert(h.blocks.toSet.subsetOf(bigger.covered), - "bad nesting of exception handlers. catch blocks of smaller handler are not nested in bigger one.\n"+ - h +"\n"+ bigger) - } - beginHandlers += sHandlers.head - currentTryHandlers.push(sHandlers) - } - beginExBlock(b) = beginHandlers.toList - visitedBlocks += b - } - - // if there handlers left (i.e. handlers covering nothing, or a - // non-existent (dead) block), remove their catch-blocks. - val liveBlocks = if (openHandlers.isEmpty) blocks else { - blocks.filter(b => openHandlers.forall(h => !h.blocks.contains(b))) - } - - /** There might be open handlers, but no more blocks. happens when try/catch end - * with `throw` or `return` - * def foo() { try { .. throw } catch { _ => .. throw } } - * - * In this case we need some code after the catch block for the auto-generated - * `leave` instruction. So we're adding a (dead) `throw new Exception`. - */ - val rest = currentCatchHandlers.map(handlers => { - assert(handlers.length == 1, handlers) - handlers.head - }).toList - - if (rest.isEmpty) { - liveBlocks - } else { - val b = m.code.newBlock - b.emit(Seq( - NEW(REFERENCE(definitions.ThrowableClass)), - DUP(REFERENCE(definitions.ObjectClass)), - CALL_METHOD(definitions.ThrowableClass.primaryConstructor, Static(true)), - THROW(definitions.ThrowableClass) - )) - b.close - endExBlock(b) = rest - liveBlocks ::: List(b) - } - } - - /** - * @param block the BasicBlock to emit code for - * @param next the following BasicBlock, `null` if `block` is the last one - */ - def genBlock(block: BasicBlock, prev: BasicBlock, next: BasicBlock) { - - def loadLocalOrAddress(local: Local, msg : String , loadAddr : Boolean) { - debuglog(msg + " for " + local) - val isArg = local.arg - val i = local.index - if (isArg) - loadArg(mcode, loadAddr)(i) - else - loadLocal(i, local, mcode, loadAddr) - } - - def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) { - debuglog(msg + " with owner: " + field.owner + - " flags: " + Flags.flagsToString(field.owner.flags)) - var fieldInfo = fields.get(field) match { - case Some(fInfo) => fInfo - case None => - val fInfo = getType(field.owner).GetField(msilName(field)) - fields(field) = fInfo - fInfo - } - if (fieldInfo.IsVolatile) { - mcode.Emit(OpCodes.Volatile) - } - if (!fieldInfo.IsLiteral) { - if (loadAddr) { - mcode.Emit(if (isStatic) OpCodes.Ldsflda else OpCodes.Ldflda, fieldInfo) - } else { - mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) - } - } else { - assert(!loadAddr, "can't take AddressOf a literal field (not even with readonly. prefix) because no memory was allocated to such field ...") - // TODO the above can be overcome by loading the value, boxing, and finally unboxing. An address to a copy of the raw value will be on the stack. - /* We perform `field inlining' as required by CLR. - * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available - * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type - * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case, - * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */ - val value = fieldInfo.getValue() - if (value == null) { - mcode.Emit(OpCodes.Ldnull) - } else { - val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType - else fieldInfo.FieldType - if (typ == clrTypes.STRING) { - mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String]) - } else if (typ == clrTypes.BOOLEAN) { - mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1 - else OpCodes.Ldc_I4_0) - } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) { - loadI4(value.asInstanceOf[Byte], mcode) - } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) { - loadI4(value.asInstanceOf[Int], mcode) - } else if (typ == clrTypes.CHAR) { - loadI4(value.asInstanceOf[Char], mcode) - } else if (typ == clrTypes.INT || typ == clrTypes.UINT) { - loadI4(value.asInstanceOf[Int], mcode) - } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) { - mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long]) - } else if (typ == clrTypes.FLOAT) { - mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float]) - } else if (typ == clrTypes.DOUBLE) { - mcode.Emit(OpCodes.Ldc_R8, value.asInstanceOf[Double]) - } else { - /* TODO one more case is described in Partition II, 16.2: bytearray(...) */ - abort("Unknown type for static literal field: " + fieldInfo) - } - } - } - } - - /** Creating objects works differently on .NET. On the JVM - * - NEW(type) => reference on Stack - * - DUP, load arguments, CALL_METHOD(constructor) - * - * On .NET, the NEW and DUP are ignored, but we emit a special method call - * - load arguments - * - NewObj(constructor) => reference on stack - * - * This variable tells whether the previous instruction was a NEW, - * we expect a DUP which is not emitted. */ - var previousWasNEW = false - - var lastLineNr: Int = 0 - var lastPos: Position = NoPosition - - - // EndExceptionBlock must happen before MarkLabel because it adds the - // Leave instruction. Otherwise, labels(block) points to the Leave - // (inside the catch) instead of the instruction afterwards. - for (handlers <- endExBlock.get(block); exh <- handlers) { - currentHandlers.pop() - for (l <- endFinallyLabels.get(exh)) - mcode.MarkLabel(l) - mcode.EndExceptionBlock() - } - - mcode.MarkLabel(labels(block)) - debuglog("Generating code for block: " + block) - - for (handler <- beginCatchBlock.get(block)) { - if (!currentHandlers.isEmpty && currentHandlers.top.covered == handler.covered) { - currentHandlers.pop() - currentHandlers.push(handler) - } - if (handler.cls == NoSymbol) { - // `finally` blocks are represented the same as `catch`, but with no catch-type - mcode.BeginFinallyBlock() - } else { - val t = getType(handler.cls) - mcode.BeginCatchBlock(t) - } - } - for (handlers <- beginExBlock.get(block); exh <- handlers) { - currentHandlers.push(exh) - mcode.BeginExceptionBlock() - } - - for (instr <- block) { - try { - val currentLineNr = instr.pos.line - val skip = if(instr.pos.isRange) instr.pos.sameRange(lastPos) else (currentLineNr == lastLineNr); - if(!skip || !dbFilenameSeen) { - val fileName = if(dbFilenameSeen) "" else {dbFilenameSeen = true; ilasmFileName(clasz)}; - if(instr.pos.isRange) { - val startLine = instr.pos.focusStart.line - val endLine = instr.pos.focusEnd.line - val startCol = instr.pos.focusStart.column - val endCol = instr.pos.focusEnd.column - mcode.setPosition(startLine, endLine, startCol, endCol, fileName) - } else { - mcode.setPosition(instr.pos.line, fileName) - } - lastLineNr = currentLineNr - lastPos = instr.pos - } - } catch { case _: UnsupportedOperationException => () } - - if (previousWasNEW) - assert(instr.isInstanceOf[DUP], block) - - instr match { - case THIS(clasz) => - mcode.Emit(OpCodes.Ldarg_0) - - case CONSTANT(const) => - const.tag match { - case UnitTag => () - case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1 - else OpCodes.Ldc_I4_0) - case ByteTag => loadI4(const.byteValue, mcode) - case ShortTag => loadI4(const.shortValue, mcode) - case CharTag => loadI4(const.charValue, mcode) - case IntTag => loadI4(const.intValue, mcode) - case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue) - case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue) - case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue) - case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue) - case NullTag => mcode.Emit(OpCodes.Ldnull) - case ClassTag => - mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue)) - mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE) - case _ => abort("Unknown constant value: " + const) - } - - case LOAD_ARRAY_ITEM(kind) => - (kind: @unchecked) match { - case BOOL => mcode.Emit(OpCodes.Ldelem_I1) - case BYTE => mcode.Emit(OpCodes.Ldelem_I1) // I1 for System.SByte, i.e. a scala.Byte - case SHORT => mcode.Emit(OpCodes.Ldelem_I2) - case CHAR => mcode.Emit(OpCodes.Ldelem_U2) - case INT => mcode.Emit(OpCodes.Ldelem_I4) - case LONG => mcode.Emit(OpCodes.Ldelem_I8) - case FLOAT => mcode.Emit(OpCodes.Ldelem_R4) - case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8) - case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref) - case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref) - - // case UNIT is not possible: an Array[Unit] will be an - // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) - } - - case LOAD_LOCAL(local) => loadLocalOrAddress(local, "load_local", false) - - case CIL_LOAD_LOCAL_ADDRESS(local) => loadLocalOrAddress(local, "cil_load_local_address", true) - - case LOAD_FIELD(field, isStatic) => loadFieldOrAddress(field, isStatic, "load_field", false) - - case CIL_LOAD_FIELD_ADDRESS(field, isStatic) => loadFieldOrAddress(field, isStatic, "cil_load_field_address", true) - - case CIL_LOAD_ARRAY_ITEM_ADDRESS(kind) => mcode.Emit(OpCodes.Ldelema, msilType(kind)) - - case CIL_NEWOBJ(msym) => - assert(msym.isClassConstructor) - val constructorInfo: ConstructorInfo = getConstructor(msym) - mcode.Emit(OpCodes.Newobj, constructorInfo) - - case LOAD_MODULE(module) => - debuglog("Generating LOAD_MODULE for: " + showsym(module)) - mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module)) - - case STORE_ARRAY_ITEM(kind) => - (kind: @unchecked) match { - case BOOL => mcode.Emit(OpCodes.Stelem_I1) - case BYTE => mcode.Emit(OpCodes.Stelem_I1) - case SHORT => mcode.Emit(OpCodes.Stelem_I2) - case CHAR => mcode.Emit(OpCodes.Stelem_I2) - case INT => mcode.Emit(OpCodes.Stelem_I4) - case LONG => mcode.Emit(OpCodes.Stelem_I8) - case FLOAT => mcode.Emit(OpCodes.Stelem_R4) - case DOUBLE => mcode.Emit(OpCodes.Stelem_R8) - case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref) - case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method) - - // case UNIT not possible (see comment at LOAD_ARRAY_ITEM) - } - - case STORE_LOCAL(local) => - val isArg = local.arg - val i = local.index - debuglog("store_local for " + local + ", index " + i) - - // there are some locals defined by the compiler that - // are isArg and are need to be stored. - if (isArg) { - if (i >= -128 && i <= 127) - mcode.Emit(OpCodes.Starg_S, i) - else - mcode.Emit(OpCodes.Starg, i) - } else { - i match { - case 0 => mcode.Emit(OpCodes.Stloc_0) - case 1 => mcode.Emit(OpCodes.Stloc_1) - case 2 => mcode.Emit(OpCodes.Stloc_2) - case 3 => mcode.Emit(OpCodes.Stloc_3) - case _ => - if (i >= -128 && i <= 127) - mcode.Emit(OpCodes.Stloc_S, localBuilders(local)) - else - mcode.Emit(OpCodes.Stloc, localBuilders(local)) - } - } - - case STORE_THIS(_) => - // this only works for impl classes because the self parameter comes first - // in the method signature. If that changes, this code has to be revisited. - mcode.Emit(OpCodes.Starg_S, 0) - - case STORE_FIELD(field, isStatic) => - val fieldInfo = fields.get(field) match { - case Some(fInfo) => fInfo - case None => - val fInfo = getType(field.owner).GetField(msilName(field)) - fields(field) = fInfo - fInfo - } - mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo) - - case CALL_PRIMITIVE(primitive) => - genPrimitive(primitive, instr.pos) - - case CALL_METHOD(msym, style) => - if (msym.isClassConstructor) { - val constructorInfo: ConstructorInfo = getConstructor(msym) - (style: @unchecked) match { - // normal constructor calls are Static.. - case Static(_) => - if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner) - // we're generating a constructor (method: IMethod is a constructor), and we're - // calling another constructor of the same class. - - // @LUC TODO: this can probably break, namely when having: class A { def this() { new A() } } - // instead, we should instruct the CALL_METHOD with additional information, know whether it's - // an instance creation constructor call or not. - mcode.Emit(OpCodes.Call, constructorInfo) - else - mcode.Emit(OpCodes.Newobj, constructorInfo) - case SuperCall(_) => - mcode.Emit(OpCodes.Call, constructorInfo) - if (isStaticModule(clasz.symbol) && - notInitializedModules.contains(clasz.symbol) && - method.symbol.isClassConstructor) - { - notInitializedModules -= clasz.symbol - mcode.Emit(OpCodes.Ldarg_0) - mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) - } - } - - } else { - - var doEmit = true - getTypeOpt(msym.owner) match { - case Some(typ) if (typ.IsEnum) => { - def negBool() = { - mcode.Emit(OpCodes.Ldc_I4_0) - mcode.Emit(OpCodes.Ceq) - } - doEmit = false - val name = msym.name - if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) } - else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool } - else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) } - else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool } - else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) } - else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool } - else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) } - else if (name eq nme.AND) { mcode.Emit(OpCodes.And) } - else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) } - else - doEmit = true - } - case _ => () - } - - // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType - val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase) { - msym.tpe match { - case MethodType(params, resultType) - if (params.length == 1 && msym.name == nme.view_) => - val paramType = params(0).tpe - val isDel = definitions.isCorrespondingDelegate(resultType, paramType) - (isDel, paramType, resultType) - case _ => (false, null, null) - } - } - if (doEmit && isDelegateView) { - doEmit = false - createDelegateCaller(paramType, resType) - } - - if (doEmit && - (msym.name == nme.PLUS || msym.name == nme.MINUS) - && clrTypes.isDelegateType(msilType(msym.owner.tpe))) - { - doEmit = false - val methodInfo: MethodInfo = getMethod(msym) - // call it as a static method, even if the compiler (symbol) thinks it's virtual - mcode.Emit(OpCodes.Call, methodInfo) - mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe)) - } - - if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) { - doEmit = false - val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym) - val delegateType: Type = msym.tpe match { - case MethodType(_, retType) => retType - case _ => abort("not a method type: " + msym.tpe) - } - val methodInfo: MethodInfo = getMethod(methodSym) - val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) - if (methodSym.isStatic) { - mcode.Emit(OpCodes.Ldftn, methodInfo) - } else { - mcode.Emit(OpCodes.Dup) - mcode.Emit(OpCodes.Ldvirtftn, methodInfo) - } - mcode.Emit(OpCodes.Newobj, delegCtor) - } - - if (doEmit) { - val methodInfo: MethodInfo = getMethod(msym) - (style: @unchecked) match { - case SuperCall(_) => - mcode.Emit(OpCodes.Call, methodInfo) - case Dynamic => - // methodInfo.DeclaringType is null for global methods - val isValuetypeMethod = (methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType) - val isValuetypeVirtualMethod = isValuetypeMethod && (methodInfo.IsVirtual) - if (dynToStatMapped(msym)) { - mcode.Emit(OpCodes.Call, methodInfo) - } else if (isValuetypeVirtualMethod) { - mcode.Emit(OpCodes.Constrained, methodInfo.DeclaringType) - mcode.Emit(OpCodes.Callvirt, methodInfo) - } else if (isValuetypeMethod) { - // otherwise error "Callvirt on a value type method" ensues - mcode.Emit(OpCodes.Call, methodInfo) - } else { - mcode.Emit(OpCodes.Callvirt, methodInfo) - } - case Static(_) => - if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) { - mcode.Emit(OpCodes.Callvirt, methodInfo) - } else mcode.Emit(OpCodes.Call, methodInfo) - } - } - } - - case BOX(boxType) => - emitBox(mcode, boxType) - - case UNBOX(boxType) => - emitUnbox(mcode, boxType) - - case CIL_UNBOX(boxType) => - mcode.Emit(OpCodes.Unbox, msilType(boxType)) - - case CIL_INITOBJ(valueType) => - mcode.Emit(OpCodes.Initobj, msilType(valueType)) - - case NEW(REFERENCE(cls)) => - // the next instruction must be a DUP, see comment on `var previousWasNEW` - previousWasNEW = true - - // works also for arrays and reference-types - case CREATE_ARRAY(elem, dims) => - // TODO: handle multi dimensional arrays - assert(dims == 1, "Can't handle multi dimensional arrays") - mcode.Emit(OpCodes.Newarr, msilType(elem)) - - // works for arrays and reference-types - case IS_INSTANCE(tpe) => - mcode.Emit(OpCodes.Isinst, msilType(tpe)) - mcode.Emit(OpCodes.Ldnull) - mcode.Emit(OpCodes.Ceq) - mcode.Emit(OpCodes.Ldc_I4_0) - mcode.Emit(OpCodes.Ceq) - - // works for arrays and reference-types - // part from the scala reference: "S <: T does not imply - // Array[S] <: Array[T] in Scala. However, it is possible - // to cast an array of S to an array of T if such a cast - // is permitted in the host environment." - case CHECK_CAST(tpknd) => - val tMSIL = msilType(tpknd) - mcode.Emit(OpCodes.Castclass, tMSIL) - - // no SWITCH is generated when there's - // - a default case ("case _ => ...") in the matching expr - // - OR is used ("case 1 | 2 => ...") - case SWITCH(tags, branches) => - // tags is List[List[Int]]; a list of integers for every label. - // if the int on stack is 4, and 4 is in the second list => jump - // to second label - // branches is List[BasicBlock] - // the labels to jump to (the last one is the default one) - - val switchLocal = mcode.DeclareLocal(MINT) - // several switch variables will appear with the same name in the - // assembly code, but this makes no truble - switchLocal.SetLocalSymInfo("$switch_var") - - mcode.Emit(OpCodes.Stloc, switchLocal) - var i = 0 - for (l <- tags) { - var targetLabel = labels(branches(i)) - for (i <- l) { - mcode.Emit(OpCodes.Ldloc, switchLocal) - loadI4(i, mcode) - mcode.Emit(OpCodes.Beq, targetLabel) - } - i += 1 - } - val defaultTarget = labels(branches(i)) - if (next != branches(i)) - mcode.Emit(OpCodes.Br, defaultTarget) - - case JUMP(whereto) => - val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto) - if (leaveHandler) { - if (leaveFinally) { - if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get) - else mcode.Emit(OpCodes.Endfinally) - } else - mcode.Emit(OpCodes.Leave, labels(whereto)) - } else if (next != whereto) - mcode.Emit(OpCodes.Br, labels(whereto)) - - case CJUMP(success, failure, cond, kind) => - // cond is TestOp (see Primitives.scala), and can take - // values EQ, NE, LT, GE LE, GT - // kind is TypeKind - val isFloat = kind == FLOAT || kind == DOUBLE - val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat) - emitCondBr(block, cond, success, failure, next, emit) - - case CZJUMP(success, failure, cond, kind) => - emitCondBr(block, cond, success, failure, next, emitBrBool(_, _)) - - case RETURN(kind) => - if (currentHandlers.isEmpty) - mcode.Emit(OpCodes.Ret) - else { - val (local, label) = returnFromHandler(kind) - if (kind != UNIT) - mcode.Emit(OpCodes.Stloc, local) - mcode.Emit(OpCodes.Leave, label) - } - - case THROW(_) => - mcode.Emit(OpCodes.Throw) - - case DROP(kind) => - mcode.Emit(OpCodes.Pop) - - case DUP(kind) => - // see comment on `var previousWasNEW` - if (!previousWasNEW) - mcode.Emit(OpCodes.Dup) - else - previousWasNEW = false - - case MONITOR_ENTER() => - mcode.Emit(OpCodes.Call, MMONITOR_ENTER) - - case MONITOR_EXIT() => - mcode.Emit(OpCodes.Call, MMONITOR_EXIT) - - case SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION(_) => - () - } - - } // end for (instr <- b) { .. } - } // end genBlock - - def genPrimitive(primitive: Primitive, pos: Position) { - primitive match { - case Negation(kind) => - kind match { - // CHECK: is ist possible to get this for BOOL? in this case, verify. - case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE => - mcode.Emit(OpCodes.Neg) - - case _ => abort("Impossible to negate a " + kind) - } - - case Arithmetic(op, kind) => - op match { - case ADD => mcode.Emit(OpCodes.Add) - case SUB => mcode.Emit(OpCodes.Sub) - case MUL => mcode.Emit(OpCodes.Mul) - case DIV => mcode.Emit(OpCodes.Div) - case REM => mcode.Emit(OpCodes.Rem) - case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement) - case _ => abort("Unknown arithmetic primitive " + primitive ) - } - - case Logical(op, kind) => op match { - case AND => mcode.Emit(OpCodes.And) - case OR => mcode.Emit(OpCodes.Or) - case XOR => mcode.Emit(OpCodes.Xor) - } - - case Shift(op, kind) => op match { - case LSL => mcode.Emit(OpCodes.Shl) - case ASR => mcode.Emit(OpCodes.Shr) - case LSR => mcode.Emit(OpCodes.Shr_Un) - } - - case Conversion(src, dst) => - debuglog("Converting from: " + src + " to: " + dst) - - dst match { - case BYTE => mcode.Emit(OpCodes.Conv_I1) // I1 for System.SByte, i.e. a scala.Byte - case SHORT => mcode.Emit(OpCodes.Conv_I2) - case CHAR => mcode.Emit(OpCodes.Conv_U2) - case INT => mcode.Emit(OpCodes.Conv_I4) - case LONG => mcode.Emit(OpCodes.Conv_I8) - case FLOAT => mcode.Emit(OpCodes.Conv_R4) - case DOUBLE => mcode.Emit(OpCodes.Conv_R8) - case _ => - Console.println("Illegal conversion at: " + clasz + - " at: " + pos.source + ":" + pos.line) - } - - case ArrayLength(_) => - mcode.Emit(OpCodes.Ldlen) - - case StartConcat => - mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR) - - - case StringConcat(el) => - val elemType : MsilType = el match { - case REFERENCE(_) | ARRAY(_) => MOBJECT - case _ => msilType(el) - } - - val argTypes:Array[MsilType] = Array(elemType) - val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes ) - mcode.Emit(OpCodes.Callvirt, stringBuilderAppend) - - case EndConcat => - mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING) - - case _ => - abort("Unimplemented primitive " + primitive) - } - } // end genPrimitive - - - ////////////////////// loading /////////////////////// - - def loadI4(value: Int, code: ILGenerator): Unit = value match { - case -1 => code.Emit(OpCodes.Ldc_I4_M1) - case 0 => code.Emit(OpCodes.Ldc_I4_0) - case 1 => code.Emit(OpCodes.Ldc_I4_1) - case 2 => code.Emit(OpCodes.Ldc_I4_2) - case 3 => code.Emit(OpCodes.Ldc_I4_3) - case 4 => code.Emit(OpCodes.Ldc_I4_4) - case 5 => code.Emit(OpCodes.Ldc_I4_5) - case 6 => code.Emit(OpCodes.Ldc_I4_6) - case 7 => code.Emit(OpCodes.Ldc_I4_7) - case 8 => code.Emit(OpCodes.Ldc_I4_8) - case _ => - if (value >= -128 && value <= 127) - code.Emit(OpCodes.Ldc_I4_S, value) - else - code.Emit(OpCodes.Ldc_I4, value) - } - - def loadArg(code: ILGenerator, loadAddr: Boolean)(i: Int) = - if (loadAddr) { - if (i >= -128 && i <= 127) - code.Emit(OpCodes.Ldarga_S, i) - else - code.Emit(OpCodes.Ldarga, i) - } else { - i match { - case 0 => code.Emit(OpCodes.Ldarg_0) - case 1 => code.Emit(OpCodes.Ldarg_1) - case 2 => code.Emit(OpCodes.Ldarg_2) - case 3 => code.Emit(OpCodes.Ldarg_3) - case _ => - if (i >= -128 && i <= 127) - code.Emit(OpCodes.Ldarg_S, i) - else - code.Emit(OpCodes.Ldarg, i) - } - } - - def loadLocal(i: Int, local: Local, code: ILGenerator, loadAddr: Boolean) = - if (loadAddr) { - if (i >= -128 && i <= 127) - code.Emit(OpCodes.Ldloca_S, localBuilders(local)) - else - code.Emit(OpCodes.Ldloca, localBuilders(local)) - } else { - i match { - case 0 => code.Emit(OpCodes.Ldloc_0) - case 1 => code.Emit(OpCodes.Ldloc_1) - case 2 => code.Emit(OpCodes.Ldloc_2) - case 3 => code.Emit(OpCodes.Ldloc_3) - case _ => - if (i >= -128 && i <= 127) - code.Emit(OpCodes.Ldloc_S, localBuilders(local)) - else - code.Emit(OpCodes.Ldloc, localBuilders(local)) - } - } - - ////////////////////// branches /////////////////////// - - /** Returns a Triple (Boolean, Boolean, Option[Label]) - * - whether the jump leaves some exception block (try / catch / finally) - * - whether it leaves a finally handler (finally block, but not it's try / catch) - * - a label where to jump for leaving the finally handler - * . None to leave directly using `endfinally` - * . Some(label) to emit `leave label` (for try / catch inside a finally handler) - */ - def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) = - if (currentHandlers.isEmpty) (false, false, None) - else { - val h = currentHandlers.head - val leaveHead = { h.covers(from) != h.covers(to) || - h.blocks.contains(from) != h.blocks.contains(to) } - if (leaveHead) { - // we leave the innermost exception block. - // find out if we also leave som e `finally` handler - currentHandlers.find(e => { - e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to) - }) match { - case Some(finallyHandler) => - if (h == finallyHandler) { - // the finally handler is the innermost, so we can emit `endfinally` directly - (true, true, None) - } else { - // we need to `Leave` to the `endfinally` of the next outer finally handler - val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel()) - (true, true, Some(l)) - } - case None => - (true, false, None) - } - } else (false, false, None) - } - - def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock, - next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) { - val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success) - val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure) - - if (sLeaveHandler || fLeaveHandler) { - val sLabelOpt = if (sLeaveHandler) { - val leaveSLabel = mcode.DefineLabel() - emitBrFun(cond, leaveSLabel) - Some(leaveSLabel) - } else { - emitBrFun(cond, labels(success)) - None - } - - if (fLeaveHandler) { - if (fLeaveFinally) { - if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get) - else mcode.Emit(OpCodes.Endfinally) - } else - mcode.Emit(OpCodes.Leave, labels(failure)) - } else - mcode.Emit(OpCodes.Br, labels(failure)) - - sLabelOpt.map(l => { - mcode.MarkLabel(l) - if (sLeaveFinally) { - if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get) - else mcode.Emit(OpCodes.Endfinally) - } else - mcode.Emit(OpCodes.Leave, labels(success)) - }) - } else { - if (next == success) { - emitBrFun(cond.negate, labels(failure)) - } else { - emitBrFun(cond, labels(success)) - if (next != failure) { - mcode.Emit(OpCodes.Br, labels(failure)) - } - } - } - } - - def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) { - condition match { - case EQ => mcode.Emit(OpCodes.Beq, dest) - case NE => mcode.Emit(OpCodes.Bne_Un, dest) - case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest) - case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest) - case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest) - case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest) - } - } - - def emitBrBool(cond: TestOp, dest: Label) { - cond match { - // EQ -> Brfalse, NE -> Brtrue; this is because we come from - // a CZJUMP. If the value on the stack is 0 (e.g. a boolean - // method returned false), and we are in the case EQ, then - // we need to emit Brfalse (EQ Zero means false). vice versa - case EQ => mcode.Emit(OpCodes.Brfalse, dest) - case NE => mcode.Emit(OpCodes.Brtrue, dest) - } - } - - ////////////////////// local vars /////////////////////// - - /** - * Compute the indexes of each local variable of the given - * method. - */ - def computeLocalVarsIndex(m: IMethod) { - var idx = if (m.symbol.isStaticMember) 0 else 1 - - val params = m.params - for (l <- params) { - debuglog("Index value for parameter " + l + ": " + idx) - l.index = idx - idx += 1 // sizeOf(l.kind) - } - - val locvars = m.locals filterNot (params contains) - idx = 0 - - for (l <- locvars) { - debuglog("Index value for local variable " + l + ": " + idx) - l.index = idx - idx += 1 // sizeOf(l.kind) - } - - } - - ////////////////////// Utilities //////////////////////// - - /** Return the a name of this symbol that can be used on the .NET - * platform. It removes spaces from names. - * - * Special handling: scala.All and scala.AllRef are 'erased' to - * scala.All$ and scala.AllRef$. This is needed because they are - * not real classes, and they mean 'abrupt termination upon evaluation - * of that expression' or 'null' respectively. This handling is - * done already in GenICode, but here we need to remove references - * from method signatures to these types, because such classes can - * not exist in the classpath: the type checker will be very confused. - */ - def msilName(sym: Symbol): String = { - val suffix = sym.moduleSuffix - // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class) - - if (sym == definitions.NothingClass) - return "scala.runtime.Nothing$" - else if (sym == definitions.NullClass) - return "scala.runtime.Null$" - - (if (sym.isClass || (sym.isModule && !sym.isMethod)) { - if (sym.isNestedClass) sym.simpleName - else sym.fullName - } else - sym.simpleName.toString.trim()) + suffix - } - - - ////////////////////// flags /////////////////////// - - def msilTypeFlags(sym: Symbol): Int = { - var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass - - if(sym.isNestedClass) { - mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NestedPrivate else TypeAttributes.NestedPublic) - } else { - mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public) - } - mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0) - mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class) - mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) - - sym.annotations foreach { a => a match { - case AnnotationInfo(SerializableAttr, _, _) => - // TODO: add the Serializable TypeAttribute also if the annotation - // System.SerializableAttribute is present (.net annotation, not scala) - // Best way to do it: compare with - // definitions.getClass("System.SerializableAttribute").tpe - // when frontend available - mf = mf | TypeAttributes.Serializable - case _ => () - }} - - mf - // static: not possible (or?) - } - - def msilMethodFlags(sym: Symbol): Short = { - var mf: Int = MethodAttributes.HideBySig | - (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private - else MethodAttributes.Public) - - if (!sym.isClassConstructor) { - if (sym.isStaticMember) - mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ... - else { - mf = mf | MethodAttributes.Virtual - if (sym.isFinal && !getType(sym.owner).IsInterface) - mf = mf | MethodAttributes.Final - if (sym.isDeferred || getType(sym.owner).IsInterface) - mf = mf | MethodAttributes.Abstract - } - } - - if (sym.isStaticMember) { - mf = mf | MethodAttributes.Static - } - - // constructors of module classes should be private - if (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) { - mf |= MethodAttributes.Private - mf &= ~(MethodAttributes.Public) - } - - mf.toShort - } - - def msilFieldFlags(sym: Symbol): Short = { - var mf: Int = - if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private - else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem - else FieldAttributes.Public - - if (sym hasFlag Flags.FINAL) - mf = mf | FieldAttributes.InitOnly - - if (sym.isStaticMember) - mf = mf | FieldAttributes.Static - - // TRANSIENT: "not serialized", VOLATILE: doesn't exist on .net - // TODO: add this annotation also if the class has the custom attribute - // System.NotSerializedAttribute - sym.annotations.foreach( a => a match { - case AnnotationInfo(TransientAtt, _, _) => - mf = mf | FieldAttributes.NotSerialized - case _ => () - }) - - mf.toShort - } - - ////////////////////// builders, types /////////////////////// - - var entryPoint: Symbol = _ - - val notInitializedModules = mutable.HashSet[Symbol]() - - // TODO: create fields also in def createType, and not in genClass, - // add a getField method (it only works as it is because fields never - // accessed from outside a class) - - val localBuilders = mutable.HashMap[Local, LocalBuilder]() - - private[GenMSIL] def findEntryPoint(cls: IClass) { - - def isEntryPoint(sym: Symbol):Boolean = { - if (isStaticModule(sym.owner) && msilName(sym) == "main") - if (sym.tpe.paramTypes.length == 1) { - toTypeKind(sym.tpe.paramTypes(0)) match { - case ARRAY(elem) => - if (elem.toType.typeSymbol == definitions.StringClass) { - return true - } - case _ => () - } - } - false - } - - if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead - val entryclass = opt.showClass.get.toString - val cfn = cls.symbol.fullName - if(cfn == entryclass) { - for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol } - if(entryPoint == null) { warning("Couldn't find main method in class " + cfn) } - } - } - - if (firstSourceName == "") - if (cls.symbol.sourceFile != null) // is null for nested classes - firstSourceName = cls.symbol.sourceFile.name - } - - // ##################################################################### - // get and create types - - private def msilType(t: TypeKind): MsilType = (t: @unchecked) match { - case UNIT => MVOID - case BOOL => MBOOL - case BYTE => MBYTE - case SHORT => MSHORT - case CHAR => MCHAR - case INT => MINT - case LONG => MLONG - case FLOAT => MFLOAT - case DOUBLE => MDOUBLE - case REFERENCE(cls) => getType(cls) - case ARRAY(elem) => - msilType(elem) match { - // For type builders, cannot call "clrTypes.mkArrayType" because this looks up - // the type "tp" in the assembly (not in the HashMap "types" of the backend). - // This can fail for nested types because the builders are not complete yet. - case tb: TypeBuilder => tb.MakeArrayType() - case tp: MsilType => clrTypes.mkArrayType(tp) - } - } - - private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe)) - - private def msilParamTypes(sym: Symbol): Array[MsilType] = { - sym.tpe.paramTypes.map(msilType).toArray - } - - def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym))) - - /** - * Get an MSIL type from a symbol. First look in the clrTypes.types map, then - * lookup the name using clrTypes.getType - */ - def getTypeOpt(sym: Symbol): Option[MsilType] = { - val tmp = types.get(sym) - tmp match { - case typ @ Some(_) => typ - case None => - def typeString(sym: Symbol): String = { - val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName - else sym.fullName - if (sym.isModuleClass && !sym.isTrait) s + "$" else s - } - val name = typeString(sym) - val typ = clrTypes.getType(name) - if (typ == null) - None - else { - types(sym) = typ - Some(typ) - } - } - } - - def mapType(sym: Symbol, mType: MsilType) { - assert(mType != null, showsym(sym)) - types(sym) = mType - } - - def createTypeBuilder(iclass: IClass) { - /** - * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise - * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)). - */ - def msilTypeFromSym(sym: Symbol): MsilType = { - types.get(sym).getOrElse { - classes.get(sym) match { - case Some(iclass) => - msilTypeBuilderFromSym(sym) - case None => - getType(sym) - } - } - } - - def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = { - if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){ - val iclass = classes(sym) - assert(iclass != null) - createTypeBuilder(iclass) - } - types(sym).asInstanceOf[TypeBuilder] - } - - val sym = iclass.symbol - if (types.contains(sym) && types(sym).isInstanceOf[TypeBuilder]) - return - - def isInterface(s: Symbol) = s.isTrait && !s.isImplClass - val parents: List[Type] = - if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe) - else sym.info.parents.distinct - - val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol) - debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType) - - val interfaces: Array[MsilType] = - parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray - if (parents.length > 1) { - if (settings.debug.value) { - log("interfaces:") - for (i <- 0.until(interfaces.length)) { - log(" type: " + parents(i + 1).typeSymbol + ", msil type: " + interfaces(i)) - } - } - } - - val tBuilder = if (sym.isNestedClass) { - val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder] - ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces) - } else { - mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces) - } - mapType(sym, tBuilder) - } // createTypeBuilder - - def createClassMembers(iclass: IClass) { - try { - createClassMembers0(iclass) - } - catch { - case e: Throwable => - java.lang.System.err.println(showsym(iclass.symbol)) - java.lang.System.err.println("with methods = " + iclass.methods) - throw e - } - } - - def createClassMembers0(iclass: IClass) { - - val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder] - - for (ifield <- iclass.fields) { - val sym = ifield.symbol - debuglog("Adding field: " + sym.fullName) - - var attributes = msilFieldFlags(sym) - val fieldTypeWithCustomMods = - new PECustomMod(msilType(sym.tpe), - customModifiers(sym.annotations)) - val fBuilder = mtype.DefineField(msilName(sym), - fieldTypeWithCustomMods, - attributes) - fields(sym) = fBuilder - addAttributes(fBuilder, sym.annotations) - } // all iclass.fields iterated over - - if (isStaticModule(iclass.symbol)) { - val sc = iclass.lookupStaticCtor - if (sc.isDefined) { - val m = sc.get - val oldLastBlock = m.lastBlock - val lastBlock = m.newBlock() - oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock)) - // call object's private ctor from static ctor - lastBlock.emit(CIL_NEWOBJ(iclass.symbol.primaryConstructor)) - lastBlock.emit(DROP(toTypeKind(iclass.symbol.tpe))) - lastBlock emit RETURN(UNIT) - lastBlock.close - } - } - - if (iclass.symbol != definitions.ArrayClass) { - for (m: IMethod <- iclass.methods) { - val sym = m.symbol - debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " + - sym.owner.fullName + "::" + sym.name) - - val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder] - assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType) - var paramTypes = msilParamTypes(sym) - val attr = msilMethodFlags(sym) - - if (m.symbol.isClassConstructor) { - val constr = - ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes) - for (i <- 0.until(paramTypes.length)) { - constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) - } - mapConstructor(sym, constr) - addAttributes(constr, sym.annotations) - } else { - var resType = msilType(m.returnType) - val method = - ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes) - for (i <- 0.until(paramTypes.length)) { - method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) - } - if (!methods.contains(sym)) - mapMethod(sym, method) - addAttributes(method, sym.annotations) - debuglog("\t created MethodBuilder " + method) - } - } - } // method builders created for non-array iclass - - if (isStaticModule(iclass.symbol)) { - addModuleInstanceField(iclass.symbol) - notInitializedModules += iclass.symbol - if (iclass.lookupStaticCtor.isEmpty) { - addStaticInit(iclass.symbol) - } - } - - } // createClassMembers0 - - private def isTopLevelModule(sym: Symbol): Boolean = - atPhase (currentRun.refchecksPhase) { - sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass - } - - // if the module is lifted it does not need to be initialized in - // its static constructor, and the MODULE$ field is not required. - // the outer class will care about it. - private def isStaticModule(sym: Symbol): Boolean = { - // .net inner classes: removed '!sym.hasFlag(Flags.LIFTED)', added - // 'sym.isStatic'. -> no longer compatible without skipping flatten! - sym.isModuleClass && sym.isStatic && !sym.isImplClass - } - - private def isCloneable(sym: Symbol): Boolean = { - !sym.annotations.forall( a => a match { - case AnnotationInfo(CloneableAttr, _, _) => false - case _ => true - }) - } - - private def addModuleInstanceField(sym: Symbol) { - debuglog("Adding Module-Instance Field for " + showsym(sym)) - val tBuilder = getType(sym).asInstanceOf[TypeBuilder] - val fb = tBuilder.DefineField(MODULE_INSTANCE_NAME, - tBuilder, - (FieldAttributes.Public | - //FieldAttributes.InitOnly | - FieldAttributes.Static).toShort) - fields(sym) = fb - } - - - // the symbol may be a object-symbol (module-symbol), or a module-class-symbol - private def getModuleInstanceField(sym: Symbol): FieldInfo = { - assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym)) - - // when called by LOAD_MODULE, the corresponding type maybe doesn't - // exist yet -> make a getType - val moduleClassSym = if (sym.isModule) sym.moduleClass else sym - - // TODO: get module field for modules not defined in the - // source currently compiling (e.g. Console) - - fields get moduleClassSym match { - case Some(sym) => sym - case None => - //val mclass = types(moduleClassSym) - val nameInMetadata = nestingAwareFullClassname(moduleClassSym) - val mClass = clrTypes.getType(nameInMetadata) - val mfield = mClass.GetField("MODULE$") - assert(mfield ne null, "module not found " + showsym(moduleClassSym)) - fields(moduleClassSym) = mfield - mfield - } - - //fields(moduleClassSym) - } - - def nestingAwareFullClassname(csym: Symbol) : String = { - val suffix = csym.moduleSuffix - val res = if (csym.isNestedClass) - nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName - else - csym.fullName - res + suffix - } - - /** Adds a static initializer which creates an instance of the module - * class (calls the primary constructor). A special primary constructor - * will be generated (notInitializedModules) which stores the new instance - * in the MODULE$ field right after the super call. - */ - private def addStaticInit(sym: Symbol) { - val tBuilder = getType(sym).asInstanceOf[TypeBuilder] - - val staticInit = tBuilder.DefineConstructor( - (MethodAttributes.Static | MethodAttributes.Public).toShort, - CallingConventions.Standard, - MsilType.EmptyTypes) - - val sicode = staticInit.GetILGenerator() - - val instanceConstructor = constructors(sym.primaryConstructor) - - // there are no constructor parameters. assuming the constructor takes no parameter - // is fine: we call (in the static constructor) the constructor of the module class, - // which takes no arguments - an object definition cannot take constructor arguments. - sicode.Emit(OpCodes.Newobj, instanceConstructor) - // the stsfld is done in the instance constructor, just after the super call. - sicode.Emit(OpCodes.Pop) - - sicode.Emit(OpCodes.Ret) - } - - private def generateMirrorClass(sym: Symbol) { - val tBuilder = getType(sym) - assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym) - debuglog("Dumping mirror class for object: " + sym) - val moduleName = msilName(sym) - val mirrorName = moduleName.substring(0, moduleName.length() - 1) - val mirrorTypeBuilder = mmodule.DefineType(mirrorName, - TypeAttributes.Class | - TypeAttributes.Public | - TypeAttributes.Sealed, - MOBJECT, - MsilType.EmptyTypes) - - val iclass = classes(sym) - - for (m <- sym.tpe.nonPrivateMembers - if m.owner != definitions.ObjectClass && !m.isProtected && - m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase && - !m.isDeferred) - { - debuglog(" Mirroring method: " + m) - val paramTypes = msilParamTypes(m) - val paramNames: Array[String] = new Array[String](paramTypes.length) - for (i <- 0 until paramTypes.length) - paramNames(i) = "x_" + i - - // CHECK: verify if getMethodName is better than msilName - val mirrorMethod = mirrorTypeBuilder.DefineMethod(msilName(m), - (MethodAttributes.Public | - MethodAttributes.Static).toShort, - msilType(m.tpe.resultType), - paramTypes) - - var i = 0 - while (i < paramTypes.length) { - mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i)) - i += 1 - } - - val mirrorCode = mirrorMethod.GetILGenerator() - mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym)) - val mInfo = getMethod(m) - for (paramidx <- 0.until(paramTypes.length)) { - val mInfoParams = mInfo.GetParameters - val loadAddr = mInfoParams(paramidx).ParameterType.IsByRef - loadArg(mirrorCode, loadAddr)(paramidx) - } - - mirrorCode.Emit(OpCodes.Callvirt, getMethod(m)) - mirrorCode.Emit(OpCodes.Ret) - } - - addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder) - - mirrorTypeBuilder.CreateType() - mirrorTypeBuilder.setSourceFilepath(iclass.cunit.source.file.path) - } - - - // ##################################################################### - // delegate callers - - var delegateCallers: TypeBuilder = _ - var nbDelegateCallers: Int = 0 - - private def initDelegateCallers() = { - delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public | - TypeAttributes.Sealed) - } - - private def createDelegateCaller(functionType: Type, delegateType: Type) = { - if (delegateCallers == null) - initDelegateCallers() - // create a field an store the function-object - val mFunctionType: MsilType = msilType(functionType) - val anonfunField: FieldBuilder = delegateCallers.DefineField( - "$anonfunField$$" + nbDelegateCallers, mFunctionType, - (FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static).toShort) - mcode.Emit(OpCodes.Stsfld, anonfunField) - - - // create the static caller method and the delegate object - val (params, returnType) = delegateType.member(nme.apply).tpe match { - case MethodType(delParams, delReturn) => (delParams, delReturn) - case _ => abort("not a delegate type: " + delegateType) - } - val caller: MethodBuilder = delegateCallers.DefineMethod( - "$delegateCaller$$" + nbDelegateCallers, - (MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static).toShort, - msilType(returnType), (params map (_.tpe)).map(msilType).toArray) - for (i <- 0 until params.length) - caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol - val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) - mcode.Emit(OpCodes.Ldnull) - mcode.Emit(OpCodes.Ldftn, caller) - mcode.Emit(OpCodes.Newobj, delegCtor) - - - // create the static caller method body - val functionApply: MethodInfo = getMethod(functionType.member(nme.apply)) - val dcode: ILGenerator = caller.GetILGenerator() - dcode.Emit(OpCodes.Ldsfld, anonfunField) - for (i <- 0 until params.length) { - loadArg(dcode, false /* TODO confirm whether passing actual as-is to formal is correct wrt the ByRef attribute of the param */)(i) - emitBox(dcode, toTypeKind(params(i).tpe)) - } - dcode.Emit(OpCodes.Callvirt, functionApply) - emitUnbox(dcode, toTypeKind(returnType)) - dcode.Emit(OpCodes.Ret) - - nbDelegateCallers = nbDelegateCallers + 1 - - } //def createDelegateCaller - - def emitBox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { - // doesn't make sense, unit as parameter.. - case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit) - case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE => - code.Emit(OpCodes.Box, msilType(boxType)) - case REFERENCE(cls) if clrTypes.isValueType(cls) => - code.Emit(OpCodes.Box, (msilType(boxType))) - case REFERENCE(_) | ARRAY(_) => - warning("Tried to BOX a non-valuetype.") - () - } - - def emitUnbox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { - case UNIT => code.Emit(OpCodes.Pop) - /* (1) it's essential to keep the code emitted here (as of now plain calls to System.Convert.ToBlaBla methods) - behaviorally.equiv.wrt. BoxesRunTime.unboxToBlaBla methods - (case null: that's easy, case boxed: track changes to unboxBlaBla) - (2) See also: asInstanceOf to cast from Any to number, - tracked in http://lampsvn.epfl.ch/trac/scala/ticket/4437 */ - case BOOL => code.Emit(OpCodes.Call, toBool) - case BYTE => code.Emit(OpCodes.Call, toSByte) - case SHORT => code.Emit(OpCodes.Call, toShort) - case CHAR => code.Emit(OpCodes.Call, toChar) - case INT => code.Emit(OpCodes.Call, toInt) - case LONG => code.Emit(OpCodes.Call, toLong) - case FLOAT => code.Emit(OpCodes.Call, toFloat) - case DOUBLE => code.Emit(OpCodes.Call, toDouble) - case REFERENCE(cls) if clrTypes.isValueType(cls) => - code.Emit(OpCodes.Unbox, msilType(boxType)) - code.Emit(OpCodes.Ldobj, msilType(boxType)) - case REFERENCE(_) | ARRAY(_) => - warning("Tried to UNBOX a non-valuetype.") - () - } - - // ##################################################################### - // get and create methods / constructors - - def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match { - case Some(constr) => constr - case None => - val mClass = getType(sym.owner) - val constr = mClass.GetConstructor(msilParamTypes(sym)) - if (constr eq null) { - java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name) - java.lang.System.out.println("scope = " + sym.owner.tpe.decls) - abort(sym.fullName) - } - else { - mapConstructor(sym, constr) - constr - } - } - - def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = { - constructors(sym) = cInfo - } - - private def getMethod(sym: Symbol): MethodInfo = { - - methods.get(sym) match { - case Some(method) => method - case None => - val mClass = getType(sym.owner) - try { - val method = mClass.GetMethod(msilName(sym), msilParamTypes(sym), - msilType(sym.tpe.resultType)) - if (method eq null) { - java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym)) - java.lang.System.out.println("scope = " + sym.owner.tpe.decls) - abort(sym.fullName) - } - else { - mapMethod(sym, method) - method - } - } - catch { - case e: Exception => - Console.println("While looking up " + mClass + "::" + sym.nameString) - Console.println("\t" + showsym(sym)) - throw e - } - } - } - - /* - * add a mapping between sym and mInfo - */ - private def mapMethod(sym: Symbol, mInfo: MethodInfo) { - assert (mInfo != null, mInfo) - methods(sym) = mInfo - } - - /* - * add mapping between sym and method with newName, paramTypes of newClass - */ - private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) { - val methodInfo = newClass.GetMethod(newName, paramTypes) - assert(methodInfo != null, "Can't find mapping for " + sym + " -> " + - newName + "(" + paramTypes + ")") - mapMethod(sym, methodInfo) - if (methodInfo.IsStatic) - dynToStatMapped += sym - } - - /* - * add mapping between method with name and paramTypes of clazz to - * method with newName and newParamTypes of newClass (used for instance - * for "wait") - */ - private def mapMethod( - clazz: Symbol, name: Name, paramTypes: Array[Type], - newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) { - val methodSym = lookupMethod(clazz, name, paramTypes) - assert(methodSym != null, "cannot find method " + name + "(" + - paramTypes + ")" + " in class " + clazz) - mapMethod(methodSym, newClass, newName, newParamTypes) - } - - /* - * add mapping for member with name and paramTypes to member - * newName of newClass (same parameters) - */ - private def mapMethod( - clazz: Symbol, name: Name, paramTypes: Array[Type], - newClass: MsilType, newName: String) { - mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) - } - - /* - * add mapping for all methods with name of clazz to the corresponding - * method (same parameters) with newName of newClass - */ - private def mapMethod( - clazz: Symbol, name: Name, - newClass: MsilType, newName: String) { - val memberSym: Symbol = clazz.tpe.member(name) - memberSym.tpe match { - // alternatives: List[Symbol] - case OverloadedType(_, alternatives) => - alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s))) - - // paramTypes: List[Type], resType: Type - case MethodType(params, resType) => - mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) - - case _ => - abort("member not found: " + clazz + ", " + name) - } - } - - - /* - * find the method in clazz with name and paramTypes - */ - private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = { - val memberSym = clazz.tpe.member(name) - memberSym.tpe match { - case OverloadedType(_, alternatives) => - alternatives.find(s => { - var i: Int = 0 - var typesOK: Boolean = true - if (paramTypes.length == s.tpe.paramTypes.length) { - while(i < paramTypes.length) { - if (paramTypes(i) != s.tpe.paramTypes(i)) - typesOK = false - i += 1 - } - } else { - typesOK = false - } - typesOK - }) match { - case Some(sym) => sym - case None => abort("member of " + clazz + ", " + name + "(" + - paramTypes + ") not found") - } - - case MethodType(_, _) => memberSym - - case _ => abort("member not found: " + name + " of " + clazz) - } - } - - private def showsym(sym: Symbol): String = (sym.toString + - "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym + - "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner - ) - - } // class BytecodeGenerator - -} // class GenMSIL +// /* NSC -- new scala compiler +// * Copyright 2005-2011 LAMP/EPFL +// * @author Nikolay Mihaylov +// */ +// +// +// package scala.tools.nsc +// package backend.msil +// +// import java.io.{File, IOException} +// import java.nio.{ByteBuffer, ByteOrder} +// import scala.collection.{ mutable, immutable } +// import scala.tools.nsc.symtab._ +// +// import ch.epfl.lamp.compiler.msil.{Type => MsilType, _} +// import ch.epfl.lamp.compiler.msil.emit._ +// import ch.epfl.lamp.compiler.msil.util.PECustomMod +// +// abstract class GenMSIL extends SubComponent { +// import global._ +// import loaders.clrTypes +// import clrTypes.{types, constructors, methods, fields} +// import icodes._ +// import icodes.opcodes._ +// +// val x = loaders +// +// /** Create a new phase */ +// override def newPhase(p: Phase) = new MsilPhase(p) +// +// val phaseName = "msil" +// /** MSIL code generation phase +// */ +// class MsilPhase(prev: Phase) extends GlobalPhase(prev) { +// def name = phaseName +// override def newFlags = phaseNewFlags +// +// override def erasedTypes = true +// +// override def run() { +// if (settings.debug.value) inform("[running phase " + name + " on icode]") +// +// val codeGenerator = new BytecodeGenerator +// +// //classes is ICodes.classes, a HashMap[Symbol, IClass] +// classes.values foreach codeGenerator.findEntryPoint +// if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead +// val entryclass = opt.showClass.get.toString +// warning("Couldn't find entry class " + entryclass) +// } +// +// codeGenerator.initAssembly +// +// val classesSorted = classes.values.toList.sortBy(c => c.symbol.id) // simplifies comparing cross-compiler vs. .exe output +// classesSorted foreach codeGenerator.createTypeBuilder +// classesSorted foreach codeGenerator.createClassMembers +// +// try { +// classesSorted foreach codeGenerator.genClass +// } finally { +// codeGenerator.writeAssembly +// } +// } +// +// override def apply(unit: CompilationUnit) { +// abort("MSIL works on icode classes, not on compilation units!") +// } +// } +// +// /** +// * MSIL bytecode generator. +// * +// */ +// class BytecodeGenerator { +// +// val MODULE_INSTANCE_NAME = "MODULE$" +// +// import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, BYTE => MBYTE, SHORT => MSHORT, +// CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT, +// DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING, +// STRING_ARRAY => MSTRING_ARRAY, +// SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR, +// SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR} +// +// val EXCEPTION = clrTypes.getType("System.Exception") +// val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE) +// +// val ICLONEABLE = clrTypes.getType("System.ICloneable") +// val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes) +// +// val MMONITOR = clrTypes.getType("System.Threading.Monitor") +// val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT)) +// val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT)) +// +// val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder") +// val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes) +// val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString", +// MsilType.EmptyTypes) +// +// val TYPE_FROM_HANDLE = +// clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle"))) +// +// val INT_PTR = clrTypes.getType("System.IntPtr") +// +// val JOBJECT = definitions.ObjectClass +// val JSTRING = definitions.StringClass +// +// val SystemConvert = clrTypes.getType("System.Convert") +// +// val objParam = Array(MOBJECT) +// +// val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam) // see comment in emitUnbox +// val toSByte: MethodInfo = SystemConvert.GetMethod("ToSByte", objParam) +// val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam) +// val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam) +// val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam) +// val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam) +// val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam) +// val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam) +// +// //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT") +// val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT) +// +// // Scala attributes +// // symtab.Definitions -> object (singleton..) +// val SerializableAttr = definitions.SerializableAttr.tpe +// val CloneableAttr = definitions.CloneableAttr.tpe +// val TransientAtt = definitions.TransientAttr.tpe +// // remoting: the architectures are too different, no mapping (no portable code +// // possible) +// +// // java instance methods that are mapped to static methods in .net +// // these will need to be called with OpCodes.Call (not Callvirt) +// val dynToStatMapped = mutable.HashSet[Symbol]() +// +// initMappings() +// +// /** Create the mappings between java and .net classes and methods */ +// private def initMappings() { +// mapType(definitions.AnyClass, MOBJECT) +// mapType(definitions.AnyRefClass, MOBJECT) +// //mapType(definitions.NullClass, clrTypes.getType("scala.AllRef$")) +// //mapType(definitions.NothingClass, clrTypes.getType("scala.All$")) +// // FIXME: for some reason the upper two lines map to null +// mapType(definitions.NullClass, EXCEPTION) +// mapType(definitions.NothingClass, EXCEPTION) +// +// mapType(definitions.BooleanClass, MBOOL) +// mapType(definitions.ByteClass, MBYTE) +// mapType(definitions.ShortClass, MSHORT) +// mapType(definitions.CharClass, MCHAR) +// mapType(definitions.IntClass, MINT) +// mapType(definitions.LongClass, MLONG) +// mapType(definitions.FloatClass, MFLOAT) +// mapType(definitions.DoubleClass, MDOUBLE) +// } +// +// var clasz: IClass = _ +// var method: IMethod = _ +// +// var massembly: AssemblyBuilder = _ +// var mmodule: ModuleBuilder = _ +// var mcode: ILGenerator = _ +// +// var assemName: String = _ +// var firstSourceName = "" +// var outDir: File = _ +// var srcPath: File = _ +// var moduleName: String = _ +// +// def initAssembly() { +// +// assemName = settings.assemname.value +// +// if (assemName == "") { +// if (entryPoint != null) { +// assemName = msilName(entryPoint.enclClass) +// // remove the $ at the end (from module-name) +// assemName = assemName.substring(0, assemName.length() - 1) +// } else { +// // assuming filename of first source file +// assert(firstSourceName.endsWith(".scala"), firstSourceName) +// assemName = firstSourceName.substring(0, firstSourceName.length() - 6) +// } +// } else { +// if (assemName.endsWith(".msil")) +// assemName = assemName.substring(0, assemName.length()-5) +// if (assemName.endsWith(".il")) +// assemName = assemName.substring(0, assemName.length()-3) +// val f: File = new File(assemName) +// assemName = f.getName() +// } +// +// outDir = new File(settings.outdir.value) +// +// srcPath = new File(settings.sourcedir.value) +// +// val assemblyName = new AssemblyName() +// assemblyName.Name = assemName +// massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName) +// +// moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe") +// // filename here: .dll or .exe (in both parameters), second: give absolute-path +// mmodule = massembly.DefineDynamicModule(moduleName, +// new File(outDir, moduleName).getAbsolutePath()) +// assert (mmodule != null) +// } +// +// +// /** +// * Form of the custom Attribute parameter (Ecma-335.pdf) +// * - p. 163 for CustomAttrib Form, +// * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!) +// * !! least significant byte first if values longer than one byte !! +// * +// * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00 +// * 2: FixedArgs (directly the data, get number and types from related constructor) +// * 2.1: length of the array (unsigned int32, 4 bytes, least significant first) +// * 2.2: the byte array data +// * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000) +// */ +// def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) { +// def addMarker() { +// val markerSymtab = new Array[Byte](4) +// markerSymtab(0) = 1.toByte +// tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR, markerSymtab) +// } +// +// // both conditions are needed (why exactly..?) +// if (tBuilder.Name.endsWith("$") || sym.isModuleClass) { +// addMarker() +// } else { +// currentRun.symData.get(sym) match { +// case Some(pickle) => +// var size = pickle.writeIndex +// val symtab = new Array[Byte](size + 8) +// symtab(0) = 1.toByte +// for (i <- 2 until 6) { +// symtab(i) = (size & 0xff).toByte +// size = size >> 8 +// } +// java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) +// +// tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) +// +// currentRun.symData -= sym +// currentRun.symData -= sym.companionSymbol +// +// case _ => +// addMarker() +// } +// } +// } +// +// /** +// * Mutates `member` adding CLR attributes (if any) based on sym.annotations. +// * Please notice that CLR custom modifiers are a different beast (see customModifiers below) +// * and thus shouldn't be added by this method. +// */ +// def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) { +// val attributes = annotations.map(_.atp.typeSymbol).collect { +// case definitions.TransientAttr => null // TODO this is just an example +// } +// return // TODO: implement at some point +// } +// +// /** +// * What's a CLR custom modifier? Intro available as source comments in compiler.msil.CustomModifier. +// * It's basically a marker associated with a location (think of FieldInfo, ParameterInfo, and PropertyInfo) +// * and thus that marker (be it optional or required) becomes part of the signature of that location. +// * Some annotations will become CLR attributes (see addAttributes above), others custom modifiers (this method). +// */ +// def customModifiers(annotations: List[AnnotationInfo]): Array[CustomModifier] = { +// annotations.map(_.atp.typeSymbol).collect { +// case definitions.VolatileAttr => new CustomModifier(true, CustomModifier.VolatileMarker) +// } toArray +// } +// +// +// +// /* +// debuglog("creating annotations: " + annotations + " for member : " + member) +// for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ; +// if annot.isConstant) +// //!typ.typeSymbol.isJavaDefined +// { +// // assert(consts.length <= 1, +// // "too many constant arguments for annotations; "+consts.toString()) +// +// // Problem / TODO having the symbol of the annotations type would be nicer +// // (i hope that type.typeSymbol is the same as the one in types2create) +// // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder) +// // when this is solved, types2create will be the same as icodes.classes, thus superfluous +// val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder] +// // val annType: MsilType = getType(typ.typeSymbol) +// +// // Problem / TODO: i have no idea which constructor is used. This +// // information should be available in AnnotationInfo. +// annType.CreateType() // else, GetConstructors can't be used +// val constr: ConstructorInfo = annType.GetConstructors()(0) +// // prevent a second call of CreateType, only needed because there's no +// // other way than GetConstructors()(0) to get the constructor, if there's +// // no constructor symbol available. +// +// val args: Array[Byte] = +// getAttributeArgs( +// annArgs map (_.constant.get), +// (for((n,v) <- nvPairs) yield (n, v.constant.get))) +// member.SetCustomAttribute(constr, args) +// } +// } */ +// +// /* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { +// val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough! +// buf.order(ByteOrder.LITTLE_ENDIAN) +// buf.putShort(1.toShort) // signature +// +// def emitSerString(str: String) = { +// // this is wrong, it has to be the length of the UTF-8 byte array, which +// // may be longer (see clr-book on page 302) +// // val length: Int = str.length +// val strBytes: Array[Byte] = try { +// str.getBytes("UTF-8") +// } catch { +// case _: Error => abort("could not get byte-array for string: " + str) +// } +// val length: Int = strBytes.length //this length is stored big-endian +// if (length < 128) +// buf.put(length.toByte) +// else if (length < (1<<14)) { +// buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0' +// buf.put((length | 0xff).toByte) +// } else if (length < (1 << 29)) { +// buf.put(((length >> 24) | 0xc0).toByte) +// buf.put(((length >> 16) & 0xff).toByte) +// buf.put(((length >> 8) & 0xff).toByte) +// buf.put(((length ) & 0xff).toByte) +// } else +// abort("string too long for attribute parameter: " + length) +// buf.put(strBytes) +// } +// +// def emitConst(const: Constant): Unit = const.tag match { +// case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte) +// case ByteTag => buf.put(const.byteValue) +// case ShortTag => buf.putShort(const.shortValue) +// case CharTag => buf.putChar(const.charValue) +// case IntTag => buf.putInt(const.intValue) +// case LongTag => buf.putLong(const.longValue) +// case FloatTag => buf.putFloat(const.floatValue) +// case DoubleTag => buf.putDouble(const.doubleValue) +// case StringTag => +// val str: String = const.stringValue +// if (str == null) { +// buf.put(0xff.toByte) +// } else { +// emitSerString(str) +// } +// case ArrayTag => +// val arr: Array[Constant] = const.arrayValue +// if (arr == null) { +// buf.putInt(0xffffffff) +// } else { +// buf.putInt(arr.length) +// arr.foreach(emitConst) +// } +// +// // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ??? +// +// case _ => abort("could not handle attribute argument: " + const) +// } +// +// consts foreach emitConst +// buf.putShort(nvPairs.length.toShort) +// def emitNamedArg(nvPair: (Name, Constant)) { +// // the named argument is a property of the attribute (it can't be a field, since +// // all fields in scala are private) +// buf.put(0x54.toByte) +// +// def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151 +// case BooleanTag => buf.put(0x02.toByte) +// case ByteTag => buf.put(0x05.toByte) +// case ShortTag => buf.put(0x06.toByte) +// case CharTag => buf.put(0x07.toByte) +// case IntTag => buf.put(0x08.toByte) +// case LongTag => buf.put(0x0a.toByte) +// case FloatTag => buf.put(0x0c.toByte) +// case DoubleTag => buf.put(0x0d.toByte) +// case StringTag => buf.put(0x0e.toByte) +// +// // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ??? +// +// // ArrayTag falls in here +// case _ => abort("could not handle attribute argument: " + c) +// } +// +// val cnst: Constant = nvPair._2 +// if (cnst.tag == ArrayTag) { +// buf.put(0x1d.toByte) +// emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0 +// } else if (cnst.tag == EnumTag) { +// buf.put(0x55.toByte) +// // TODO: put a SerString (don't know what exactly, names of the enums somehow..) +// } else { +// buf.put(0x51.toByte) +// emitType(cnst) +// } +// +// emitSerString(nvPair._1.toString) +// emitConst(nvPair._2) +// } +// +// val length = buf.position() +// buf.array().slice(0, length) +// } */ +// +// def writeAssembly() { +// if (entryPoint != null) { +// assert(entryPoint.enclClass.isModuleClass, entryPoint.enclClass) +// val mainMethod = methods(entryPoint) +// val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY) +// val globalMain = mmodule.DefineGlobalMethod( +// "Main", MethodAttributes.Public | MethodAttributes.Static, +// MVOID, stringArrayTypes) +// globalMain.DefineParameter(0, ParameterAttributes.None, "args") +// massembly.SetEntryPoint(globalMain) +// val code = globalMain.GetILGenerator() +// val moduleField = getModuleInstanceField(entryPoint.enclClass) +// code.Emit(OpCodes.Ldsfld, moduleField) +// code.Emit(OpCodes.Ldarg_0) +// code.Emit(OpCodes.Callvirt, mainMethod) +// code.Emit(OpCodes.Ret) +// } +// createTypes() +// var outDirName: String = null +// try { +// if (settings.Ygenjavap.isDefault) { // we reuse the JVM-sounding setting because it's conceptually similar +// outDirName = outDir.getPath() +// massembly.Save(outDirName + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */ +// } else { +// outDirName = srcPath.getPath() +// massembly.Save(settings.Ygenjavap.value, outDirName) /* use MultipleFilesILPrinterVisitor */ +// } +// } catch { +// case e:IOException => abort("Could not write to " + outDirName + ": " + e.getMessage()) +// } +// } +// +// private def createTypes() { +// for (sym <- classes.keys) { +// val iclass = classes(sym) +// val tBuilder = types(sym).asInstanceOf[TypeBuilder] +// +// debuglog("Calling CreatType for " + sym + ", " + tBuilder.toString) +// +// tBuilder.CreateType() +// tBuilder.setSourceFilepath(iclass.cunit.source.file.path) +// } +// } +// +// private[GenMSIL] def ilasmFileName(iclass: IClass) : String = { +// // method.sourceFile contains just the filename +// iclass.cunit.source.file.toString.replace("\\", "\\\\") +// } +// +// private[GenMSIL] def genClass(iclass: IClass) { +// val sym = iclass.symbol +// debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags)) +// clasz = iclass +// +// val tBuilder = getType(sym).asInstanceOf[TypeBuilder] +// if (isCloneable(sym)) { +// // FIXME: why there's no nme.clone_ ? +// // "Clone": if the code is non-portable, "Clone" is defined, not "clone" +// // TODO: improve condition (should override AnyRef.clone) +// if (iclass.methods.forall(m => { +// !((m.symbol.name.toString != "clone" || m.symbol.name.toString != "Clone") && +// m.symbol.tpe.paramTypes.length != 0) +// })) { +// debuglog("auto-generating cloneable method for " + sym) +// val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual | +// MethodAttributes.HideBySig).toShort +// val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT, +// MsilType.EmptyTypes) +// val clCode = cloneMethod.GetILGenerator() +// clCode.Emit(OpCodes.Ldarg_0) +// clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE) +// clCode.Emit(OpCodes.Ret) +// } +// } +// +// val line = sym.pos.line +// tBuilder.setPosition(line, ilasmFileName(iclass)) +// +// if (isTopLevelModule(sym)) { +// if (sym.companionClass == NoSymbol) +// generateMirrorClass(sym) +// else +// log("No mirror class for module with linked class: " + +// sym.fullName) +// } +// +// addSymtabAttribute(sym, tBuilder) +// addAttributes(tBuilder, sym.annotations) +// +// if (iclass.symbol != definitions.ArrayClass) +// iclass.methods foreach genMethod +// +// } //genClass +// +// +// private def genMethod(m: IMethod) { +// debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + +// " owner: " + m.symbol.owner) +// method = m +// localBuilders.clear +// computeLocalVarsIndex(m) +// +// if (m.symbol.isClassConstructor) { +// mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator() +// } else { +// val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder] +// if (!mBuilder.IsAbstract()) +// try { +// mcode = mBuilder.GetILGenerator() +// } catch { +// case e: Exception => +// java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) +// java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner) +// java.lang.System.out.println("mBuilder = " + mBuilder) +// java.lang.System.out.println("mBuilder.DeclaringType = " + +// TypeAttributes.toString(mBuilder.DeclaringType.Attributes) + +// "::" + mBuilder.DeclaringType) +// throw e +// } +// else +// mcode = null +// } +// +// if (mcode != null) { +// for (local <- m.locals ; if !(m.params contains local)) { +// debuglog("add local var: " + local + ", of kind " + local.kind) +// val t: MsilType = msilType(local.kind) +// val localBuilder = mcode.DeclareLocal(t) +// localBuilder.SetLocalSymInfo(msilName(local.sym)) +// localBuilders(local) = localBuilder +// } +// genCode(m) +// } +// +// } +// +// /** Special linearizer for methods with at least one exception handler. This +// * linearizer brings all basic blocks in the right order so that nested +// * try-catch and try-finally blocks can be emitted. +// */ +// val msilLinearizer = new MSILLinearizer() +// +// val labels = mutable.HashMap[BasicBlock, Label]() +// +// /* when emitting .line, it's enough to include the full filename just once per method, thus reducing filesize. +// * this scheme relies on the fact that the entry block is emitted first. */ +// var dbFilenameSeen = false +// +// def genCode(m: IMethod) { +// +// def makeLabels(blocks: List[BasicBlock]) = { +// debuglog("Making labels for: " + method) +// for (bb <- blocks) labels(bb) = mcode.DefineLabel() +// } +// +// labels.clear +// +// var linearization = if(!m.exh.isEmpty) msilLinearizer.linearize(m) +// else linearizer.linearize(m) +// +// if (!m.exh.isEmpty) +// linearization = computeExceptionMaps(linearization, m) +// +// makeLabels(linearization) +// +// // debug val blocksInM = m.code.blocks.toList.sortBy(bb => bb.label) +// // debug val blocksInL = linearization.sortBy(bb => bb.label) +// // debug val MButNotL = (blocksInM.toSet) diff (blocksInL.toSet) // if non-empty, a jump to B fails to find a label for B (case CJUMP, case CZJUMP) +// // debug if(!MButNotL.isEmpty) { } +// +// dbFilenameSeen = false +// genBlocks(linearization) +// +// // RETURN inside exception blocks are replaced by Leave. The target of the +// // leave is a `Ret` outside any exception block (generated here). +// if (handlerReturnMethod == m) { +// mcode.MarkLabel(handlerReturnLabel) +// if (handlerReturnKind != UNIT) +// mcode.Emit(OpCodes.Ldloc, handlerReturnLocal) +// mcode.Emit(OpCodes.Ret) +// } +// +// beginExBlock.clear() +// beginCatchBlock.clear() +// endExBlock.clear() +// endFinallyLabels.clear() +// } +// +// def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) { +// blocks match { +// case Nil => () +// case x :: Nil => genBlock(x, prev = previous, next = null) +// case x :: y :: ys => genBlock(x, prev = previous, next = y); genBlocks(y :: ys, previous = x) +// } +// } +// +// // the try blocks starting at a certain BasicBlock +// val beginExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() +// +// // the catch blocks starting / endling at a certain BasicBlock +// val beginCatchBlock = mutable.HashMap[BasicBlock, ExceptionHandler]() +// val endExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() +// +// /** When emitting the code (genBlock), the number of currently active try / catch +// * blocks. When seeing a `RETURN` inside a try / catch, we need to +// * - store the result in a local (if it's not UNIT) +// * - emit `Leave handlerReturnLabel` instead of the Return +// * - emit code at the end: load the local and return its value +// */ +// var currentHandlers = new mutable.Stack[ExceptionHandler] +// // The IMethod the Local/Label/Kind below belong to +// var handlerReturnMethod: IMethod = _ +// // Stores the result when returning inside an exception block +// var handlerReturnLocal: LocalBuilder = _ +// // Label for a return instruction outside any exception block +// var handlerReturnLabel: Label = _ +// // The result kind. +// var handlerReturnKind: TypeKind = _ +// def returnFromHandler(kind: TypeKind): (LocalBuilder, Label) = { +// if (handlerReturnMethod != method) { +// handlerReturnMethod = method +// if (kind != UNIT) { +// handlerReturnLocal = mcode.DeclareLocal(msilType(kind)) +// handlerReturnLocal.SetLocalSymInfo("$handlerReturn") +// } +// handlerReturnLabel = mcode.DefineLabel() +// handlerReturnKind = kind +// } +// (handlerReturnLocal, handlerReturnLabel) +// } +// +// /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the +// * Leave target has to be inside the finally (and it has to be the `endfinally` instruction). +// * So for every finalizer, we have a label which marks the place of the `endfinally`, +// * nested try/catch blocks will leave there. +// */ +// val endFinallyLabels = mutable.HashMap[ExceptionHandler, Label]() +// +// /** Computes which blocks are the beginning / end of a try or catch block */ +// private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = { +// val visitedBlocks = new mutable.HashSet[BasicBlock]() +// +// // handlers which have not been introduced so far +// var openHandlers = m.exh +// +// +// /** Example +// * try { +// * try { +// * // *1* +// * } catch { +// * case h1 => +// * } +// * } catch { +// * case h2 => +// * case h3 => +// * try { +// * +// * } catch { +// * case h4 => // *2* +// * case h5 => +// * } +// * } +// */ +// +// // Stack of nested try blocks. Each bloc has a List of ExceptionHandler (multiple +// // catch statements). Example *1*: Stack(List(h2, h3), List(h1)) +// val currentTryHandlers = new mutable.Stack[List[ExceptionHandler]]() +// +// // Stack of nested catch blocks. The head of the list is the current catch block. The +// // tail is all following catch blocks. Example *2*: Stack(List(h3), List(h4, h5)) +// val currentCatchHandlers = new mutable.Stack[List[ExceptionHandler]]() +// +// for (b <- blocks) { +// +// // are we past the current catch blocks? +// def endHandlers(): List[ExceptionHandler] = { +// var res: List[ExceptionHandler] = Nil +// if (!currentCatchHandlers.isEmpty) { +// val handler = currentCatchHandlers.top.head +// if (!handler.blocks.contains(b)) { +// // all blocks of the handler are either visited, or not part of the linearization (i.e. dead) +// assert(handler.blocks.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), +// "Bad linearization of basic blocks inside catch. Found block not part of the handler\n"+ +// b.fullString +"\nwhile in catch-part of\n"+ handler) +// +// val rest = currentCatchHandlers.pop.tail +// if (rest.isEmpty) { +// // all catch blocks of that exception handler are covered +// res = handler :: endHandlers() +// } else { +// // there are more catch blocks for that try (handlers covering the same) +// currentCatchHandlers.push(rest) +// beginCatchBlock(b) = rest.head +// } +// } +// } +// res +// } +// val end = endHandlers() +// if (!end.isEmpty) endExBlock(b) = end +// +// // are we past the current try block? +// if (!currentTryHandlers.isEmpty) { +// val handler = currentTryHandlers.top.head +// if (!handler.covers(b)) { +// // all of the covered blocks are visited, or not part of the linearization +// assert(handler.covered.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), +// "Bad linearization of basic blocks inside try. Found non-covered block\n"+ +// b.fullString +"\nwhile in try-part of\n"+ handler) +// +// assert(handler.startBlock == b, +// "Bad linearization of basic blocks. The entry block of a catch does not directly follow the try\n"+ +// b.fullString +"\n"+ handler) +// +// val handlers = currentTryHandlers.pop +// currentCatchHandlers.push(handlers) +// beginCatchBlock(b) = handler +// } +// } +// +// // are there try blocks starting at b? +// val (newHandlers, stillOpen) = openHandlers.partition(_.covers(b)) +// openHandlers = stillOpen +// +// val newHandlersBySize = newHandlers.groupBy(_.covered.size) +// // big handlers first, smaller ones are nested inside the try of the big one +// // (checked by the assertions below) +// val sizes = newHandlersBySize.keys.toList.sortWith(_ > _) +// +// val beginHandlers = new mutable.ListBuffer[ExceptionHandler] +// for (s <- sizes) { +// val sHandlers = newHandlersBySize(s) +// for (h <- sHandlers) { +// assert(h.covered == sHandlers.head.covered, +// "bad nesting of exception handlers. same size, but not covering same blocks\n"+ +// h +"\n"+ sHandlers.head) +// assert(h.resultKind == sHandlers.head.resultKind, +// "bad nesting of exception handlers. same size, but the same resultKind\n"+ +// h +"\n"+ sHandlers.head) +// } +// for (bigger <- beginHandlers; h <- sHandlers) { +// assert(h.covered.subsetOf(bigger.covered), +// "bad nesting of exception handlers. try blocks of smaller handler are not nested in bigger one.\n"+ +// h +"\n"+ bigger) +// assert(h.blocks.toSet.subsetOf(bigger.covered), +// "bad nesting of exception handlers. catch blocks of smaller handler are not nested in bigger one.\n"+ +// h +"\n"+ bigger) +// } +// beginHandlers += sHandlers.head +// currentTryHandlers.push(sHandlers) +// } +// beginExBlock(b) = beginHandlers.toList +// visitedBlocks += b +// } +// +// // if there handlers left (i.e. handlers covering nothing, or a +// // non-existent (dead) block), remove their catch-blocks. +// val liveBlocks = if (openHandlers.isEmpty) blocks else { +// blocks.filter(b => openHandlers.forall(h => !h.blocks.contains(b))) +// } +// +// /** There might be open handlers, but no more blocks. happens when try/catch end +// * with `throw` or `return` +// * def foo() { try { .. throw } catch { _ => .. throw } } +// * +// * In this case we need some code after the catch block for the auto-generated +// * `leave` instruction. So we're adding a (dead) `throw new Exception`. +// */ +// val rest = currentCatchHandlers.map(handlers => { +// assert(handlers.length == 1, handlers) +// handlers.head +// }).toList +// +// if (rest.isEmpty) { +// liveBlocks +// } else { +// val b = m.code.newBlock +// b.emit(Seq( +// NEW(REFERENCE(definitions.ThrowableClass)), +// DUP(REFERENCE(definitions.ObjectClass)), +// CALL_METHOD(definitions.ThrowableClass.primaryConstructor, Static(true)), +// THROW(definitions.ThrowableClass) +// )) +// b.close +// endExBlock(b) = rest +// liveBlocks ::: List(b) +// } +// } +// +// /** +// * @param block the BasicBlock to emit code for +// * @param next the following BasicBlock, `null` if `block` is the last one +// */ +// def genBlock(block: BasicBlock, prev: BasicBlock, next: BasicBlock) { +// +// def loadLocalOrAddress(local: Local, msg : String , loadAddr : Boolean) { +// debuglog(msg + " for " + local) +// val isArg = local.arg +// val i = local.index +// if (isArg) +// loadArg(mcode, loadAddr)(i) +// else +// loadLocal(i, local, mcode, loadAddr) +// } +// +// def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) { +// debuglog(msg + " with owner: " + field.owner + +// " flags: " + Flags.flagsToString(field.owner.flags)) +// var fieldInfo = fields.get(field) match { +// case Some(fInfo) => fInfo +// case None => +// val fInfo = getType(field.owner).GetField(msilName(field)) +// fields(field) = fInfo +// fInfo +// } +// if (fieldInfo.IsVolatile) { +// mcode.Emit(OpCodes.Volatile) +// } +// if (!fieldInfo.IsLiteral) { +// if (loadAddr) { +// mcode.Emit(if (isStatic) OpCodes.Ldsflda else OpCodes.Ldflda, fieldInfo) +// } else { +// mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) +// } +// } else { +// assert(!loadAddr, "can't take AddressOf a literal field (not even with readonly. prefix) because no memory was allocated to such field ...") +// // TODO the above can be overcome by loading the value, boxing, and finally unboxing. An address to a copy of the raw value will be on the stack. +// /* We perform `field inlining' as required by CLR. +// * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available +// * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type +// * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case, +// * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */ +// val value = fieldInfo.getValue() +// if (value == null) { +// mcode.Emit(OpCodes.Ldnull) +// } else { +// val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType +// else fieldInfo.FieldType +// if (typ == clrTypes.STRING) { +// mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String]) +// } else if (typ == clrTypes.BOOLEAN) { +// mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1 +// else OpCodes.Ldc_I4_0) +// } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) { +// loadI4(value.asInstanceOf[Byte], mcode) +// } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) { +// loadI4(value.asInstanceOf[Int], mcode) +// } else if (typ == clrTypes.CHAR) { +// loadI4(value.asInstanceOf[Char], mcode) +// } else if (typ == clrTypes.INT || typ == clrTypes.UINT) { +// loadI4(value.asInstanceOf[Int], mcode) +// } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) { +// mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long]) +// } else if (typ == clrTypes.FLOAT) { +// mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float]) +// } else if (typ == clrTypes.DOUBLE) { +// mcode.Emit(OpCodes.Ldc_R8, value.asInstanceOf[Double]) +// } else { +// /* TODO one more case is described in Partition II, 16.2: bytearray(...) */ +// abort("Unknown type for static literal field: " + fieldInfo) +// } +// } +// } +// } +// +// /** Creating objects works differently on .NET. On the JVM +// * - NEW(type) => reference on Stack +// * - DUP, load arguments, CALL_METHOD(constructor) +// * +// * On .NET, the NEW and DUP are ignored, but we emit a special method call +// * - load arguments +// * - NewObj(constructor) => reference on stack +// * +// * This variable tells whether the previous instruction was a NEW, +// * we expect a DUP which is not emitted. */ +// var previousWasNEW = false +// +// var lastLineNr: Int = 0 +// var lastPos: Position = NoPosition +// +// +// // EndExceptionBlock must happen before MarkLabel because it adds the +// // Leave instruction. Otherwise, labels(block) points to the Leave +// // (inside the catch) instead of the instruction afterwards. +// for (handlers <- endExBlock.get(block); exh <- handlers) { +// currentHandlers.pop() +// for (l <- endFinallyLabels.get(exh)) +// mcode.MarkLabel(l) +// mcode.EndExceptionBlock() +// } +// +// mcode.MarkLabel(labels(block)) +// debuglog("Generating code for block: " + block) +// +// for (handler <- beginCatchBlock.get(block)) { +// if (!currentHandlers.isEmpty && currentHandlers.top.covered == handler.covered) { +// currentHandlers.pop() +// currentHandlers.push(handler) +// } +// if (handler.cls == NoSymbol) { +// // `finally` blocks are represented the same as `catch`, but with no catch-type +// mcode.BeginFinallyBlock() +// } else { +// val t = getType(handler.cls) +// mcode.BeginCatchBlock(t) +// } +// } +// for (handlers <- beginExBlock.get(block); exh <- handlers) { +// currentHandlers.push(exh) +// mcode.BeginExceptionBlock() +// } +// +// for (instr <- block) { +// try { +// val currentLineNr = instr.pos.line +// val skip = if(instr.pos.isRange) instr.pos.sameRange(lastPos) else (currentLineNr == lastLineNr); +// if(!skip || !dbFilenameSeen) { +// val fileName = if(dbFilenameSeen) "" else {dbFilenameSeen = true; ilasmFileName(clasz)}; +// if(instr.pos.isRange) { +// val startLine = instr.pos.focusStart.line +// val endLine = instr.pos.focusEnd.line +// val startCol = instr.pos.focusStart.column +// val endCol = instr.pos.focusEnd.column +// mcode.setPosition(startLine, endLine, startCol, endCol, fileName) +// } else { +// mcode.setPosition(instr.pos.line, fileName) +// } +// lastLineNr = currentLineNr +// lastPos = instr.pos +// } +// } catch { case _: UnsupportedOperationException => () } +// +// if (previousWasNEW) +// assert(instr.isInstanceOf[DUP], block) +// +// instr match { +// case THIS(clasz) => +// mcode.Emit(OpCodes.Ldarg_0) +// +// case CONSTANT(const) => +// const.tag match { +// case UnitTag => () +// case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1 +// else OpCodes.Ldc_I4_0) +// case ByteTag => loadI4(const.byteValue, mcode) +// case ShortTag => loadI4(const.shortValue, mcode) +// case CharTag => loadI4(const.charValue, mcode) +// case IntTag => loadI4(const.intValue, mcode) +// case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue) +// case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue) +// case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue) +// case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue) +// case NullTag => mcode.Emit(OpCodes.Ldnull) +// case ClassTag => +// mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue)) +// mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE) +// case _ => abort("Unknown constant value: " + const) +// } +// +// case LOAD_ARRAY_ITEM(kind) => +// (kind: @unchecked) match { +// case BOOL => mcode.Emit(OpCodes.Ldelem_I1) +// case BYTE => mcode.Emit(OpCodes.Ldelem_I1) // I1 for System.SByte, i.e. a scala.Byte +// case SHORT => mcode.Emit(OpCodes.Ldelem_I2) +// case CHAR => mcode.Emit(OpCodes.Ldelem_U2) +// case INT => mcode.Emit(OpCodes.Ldelem_I4) +// case LONG => mcode.Emit(OpCodes.Ldelem_I8) +// case FLOAT => mcode.Emit(OpCodes.Ldelem_R4) +// case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8) +// case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref) +// case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref) +// +// // case UNIT is not possible: an Array[Unit] will be an +// // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) +// } +// +// case LOAD_LOCAL(local) => loadLocalOrAddress(local, "load_local", false) +// +// case CIL_LOAD_LOCAL_ADDRESS(local) => loadLocalOrAddress(local, "cil_load_local_address", true) +// +// case LOAD_FIELD(field, isStatic) => loadFieldOrAddress(field, isStatic, "load_field", false) +// +// case CIL_LOAD_FIELD_ADDRESS(field, isStatic) => loadFieldOrAddress(field, isStatic, "cil_load_field_address", true) +// +// case CIL_LOAD_ARRAY_ITEM_ADDRESS(kind) => mcode.Emit(OpCodes.Ldelema, msilType(kind)) +// +// case CIL_NEWOBJ(msym) => +// assert(msym.isClassConstructor) +// val constructorInfo: ConstructorInfo = getConstructor(msym) +// mcode.Emit(OpCodes.Newobj, constructorInfo) +// +// case LOAD_MODULE(module) => +// debuglog("Generating LOAD_MODULE for: " + showsym(module)) +// mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module)) +// +// case STORE_ARRAY_ITEM(kind) => +// (kind: @unchecked) match { +// case BOOL => mcode.Emit(OpCodes.Stelem_I1) +// case BYTE => mcode.Emit(OpCodes.Stelem_I1) +// case SHORT => mcode.Emit(OpCodes.Stelem_I2) +// case CHAR => mcode.Emit(OpCodes.Stelem_I2) +// case INT => mcode.Emit(OpCodes.Stelem_I4) +// case LONG => mcode.Emit(OpCodes.Stelem_I8) +// case FLOAT => mcode.Emit(OpCodes.Stelem_R4) +// case DOUBLE => mcode.Emit(OpCodes.Stelem_R8) +// case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref) +// case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method) +// +// // case UNIT not possible (see comment at LOAD_ARRAY_ITEM) +// } +// +// case STORE_LOCAL(local) => +// val isArg = local.arg +// val i = local.index +// debuglog("store_local for " + local + ", index " + i) +// +// // there are some locals defined by the compiler that +// // are isArg and are need to be stored. +// if (isArg) { +// if (i >= -128 && i <= 127) +// mcode.Emit(OpCodes.Starg_S, i) +// else +// mcode.Emit(OpCodes.Starg, i) +// } else { +// i match { +// case 0 => mcode.Emit(OpCodes.Stloc_0) +// case 1 => mcode.Emit(OpCodes.Stloc_1) +// case 2 => mcode.Emit(OpCodes.Stloc_2) +// case 3 => mcode.Emit(OpCodes.Stloc_3) +// case _ => +// if (i >= -128 && i <= 127) +// mcode.Emit(OpCodes.Stloc_S, localBuilders(local)) +// else +// mcode.Emit(OpCodes.Stloc, localBuilders(local)) +// } +// } +// +// case STORE_THIS(_) => +// // this only works for impl classes because the self parameter comes first +// // in the method signature. If that changes, this code has to be revisited. +// mcode.Emit(OpCodes.Starg_S, 0) +// +// case STORE_FIELD(field, isStatic) => +// val fieldInfo = fields.get(field) match { +// case Some(fInfo) => fInfo +// case None => +// val fInfo = getType(field.owner).GetField(msilName(field)) +// fields(field) = fInfo +// fInfo +// } +// mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo) +// +// case CALL_PRIMITIVE(primitive) => +// genPrimitive(primitive, instr.pos) +// +// case CALL_METHOD(msym, style) => +// if (msym.isClassConstructor) { +// val constructorInfo: ConstructorInfo = getConstructor(msym) +// (style: @unchecked) match { +// // normal constructor calls are Static.. +// case Static(_) => +// if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner) +// // we're generating a constructor (method: IMethod is a constructor), and we're +// // calling another constructor of the same class. +// +// // @LUC TODO: this can probably break, namely when having: class A { def this() { new A() } } +// // instead, we should instruct the CALL_METHOD with additional information, know whether it's +// // an instance creation constructor call or not. +// mcode.Emit(OpCodes.Call, constructorInfo) +// else +// mcode.Emit(OpCodes.Newobj, constructorInfo) +// case SuperCall(_) => +// mcode.Emit(OpCodes.Call, constructorInfo) +// if (isStaticModule(clasz.symbol) && +// notInitializedModules.contains(clasz.symbol) && +// method.symbol.isClassConstructor) +// { +// notInitializedModules -= clasz.symbol +// mcode.Emit(OpCodes.Ldarg_0) +// mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) +// } +// } +// +// } else { +// +// var doEmit = true +// getTypeOpt(msym.owner) match { +// case Some(typ) if (typ.IsEnum) => { +// def negBool() = { +// mcode.Emit(OpCodes.Ldc_I4_0) +// mcode.Emit(OpCodes.Ceq) +// } +// doEmit = false +// val name = msym.name +// if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) } +// else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool } +// else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) } +// else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool } +// else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) } +// else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool } +// else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) } +// else if (name eq nme.AND) { mcode.Emit(OpCodes.And) } +// else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) } +// else +// doEmit = true +// } +// case _ => () +// } +// +// // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType +// val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase) { +// msym.tpe match { +// case MethodType(params, resultType) +// if (params.length == 1 && msym.name == nme.view_) => +// val paramType = params(0).tpe +// val isDel = definitions.isCorrespondingDelegate(resultType, paramType) +// (isDel, paramType, resultType) +// case _ => (false, null, null) +// } +// } +// if (doEmit && isDelegateView) { +// doEmit = false +// createDelegateCaller(paramType, resType) +// } +// +// if (doEmit && +// (msym.name == nme.PLUS || msym.name == nme.MINUS) +// && clrTypes.isDelegateType(msilType(msym.owner.tpe))) +// { +// doEmit = false +// val methodInfo: MethodInfo = getMethod(msym) +// // call it as a static method, even if the compiler (symbol) thinks it's virtual +// mcode.Emit(OpCodes.Call, methodInfo) +// mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe)) +// } +// +// if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) { +// doEmit = false +// val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym) +// val delegateType: Type = msym.tpe match { +// case MethodType(_, retType) => retType +// case _ => abort("not a method type: " + msym.tpe) +// } +// val methodInfo: MethodInfo = getMethod(methodSym) +// val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) +// if (methodSym.isStatic) { +// mcode.Emit(OpCodes.Ldftn, methodInfo) +// } else { +// mcode.Emit(OpCodes.Dup) +// mcode.Emit(OpCodes.Ldvirtftn, methodInfo) +// } +// mcode.Emit(OpCodes.Newobj, delegCtor) +// } +// +// if (doEmit) { +// val methodInfo: MethodInfo = getMethod(msym) +// (style: @unchecked) match { +// case SuperCall(_) => +// mcode.Emit(OpCodes.Call, methodInfo) +// case Dynamic => +// // methodInfo.DeclaringType is null for global methods +// val isValuetypeMethod = (methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType) +// val isValuetypeVirtualMethod = isValuetypeMethod && (methodInfo.IsVirtual) +// if (dynToStatMapped(msym)) { +// mcode.Emit(OpCodes.Call, methodInfo) +// } else if (isValuetypeVirtualMethod) { +// mcode.Emit(OpCodes.Constrained, methodInfo.DeclaringType) +// mcode.Emit(OpCodes.Callvirt, methodInfo) +// } else if (isValuetypeMethod) { +// // otherwise error "Callvirt on a value type method" ensues +// mcode.Emit(OpCodes.Call, methodInfo) +// } else { +// mcode.Emit(OpCodes.Callvirt, methodInfo) +// } +// case Static(_) => +// if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) { +// mcode.Emit(OpCodes.Callvirt, methodInfo) +// } else mcode.Emit(OpCodes.Call, methodInfo) +// } +// } +// } +// +// case BOX(boxType) => +// emitBox(mcode, boxType) +// +// case UNBOX(boxType) => +// emitUnbox(mcode, boxType) +// +// case CIL_UNBOX(boxType) => +// mcode.Emit(OpCodes.Unbox, msilType(boxType)) +// +// case CIL_INITOBJ(valueType) => +// mcode.Emit(OpCodes.Initobj, msilType(valueType)) +// +// case NEW(REFERENCE(cls)) => +// // the next instruction must be a DUP, see comment on `var previousWasNEW` +// previousWasNEW = true +// +// // works also for arrays and reference-types +// case CREATE_ARRAY(elem, dims) => +// // TODO: handle multi dimensional arrays +// assert(dims == 1, "Can't handle multi dimensional arrays") +// mcode.Emit(OpCodes.Newarr, msilType(elem)) +// +// // works for arrays and reference-types +// case IS_INSTANCE(tpe) => +// mcode.Emit(OpCodes.Isinst, msilType(tpe)) +// mcode.Emit(OpCodes.Ldnull) +// mcode.Emit(OpCodes.Ceq) +// mcode.Emit(OpCodes.Ldc_I4_0) +// mcode.Emit(OpCodes.Ceq) +// +// // works for arrays and reference-types +// // part from the scala reference: "S <: T does not imply +// // Array[S] <: Array[T] in Scala. However, it is possible +// // to cast an array of S to an array of T if such a cast +// // is permitted in the host environment." +// case CHECK_CAST(tpknd) => +// val tMSIL = msilType(tpknd) +// mcode.Emit(OpCodes.Castclass, tMSIL) +// +// // no SWITCH is generated when there's +// // - a default case ("case _ => ...") in the matching expr +// // - OR is used ("case 1 | 2 => ...") +// case SWITCH(tags, branches) => +// // tags is List[List[Int]]; a list of integers for every label. +// // if the int on stack is 4, and 4 is in the second list => jump +// // to second label +// // branches is List[BasicBlock] +// // the labels to jump to (the last one is the default one) +// +// val switchLocal = mcode.DeclareLocal(MINT) +// // several switch variables will appear with the same name in the +// // assembly code, but this makes no truble +// switchLocal.SetLocalSymInfo("$switch_var") +// +// mcode.Emit(OpCodes.Stloc, switchLocal) +// var i = 0 +// for (l <- tags) { +// var targetLabel = labels(branches(i)) +// for (i <- l) { +// mcode.Emit(OpCodes.Ldloc, switchLocal) +// loadI4(i, mcode) +// mcode.Emit(OpCodes.Beq, targetLabel) +// } +// i += 1 +// } +// val defaultTarget = labels(branches(i)) +// if (next != branches(i)) +// mcode.Emit(OpCodes.Br, defaultTarget) +// +// case JUMP(whereto) => +// val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto) +// if (leaveHandler) { +// if (leaveFinally) { +// if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get) +// else mcode.Emit(OpCodes.Endfinally) +// } else +// mcode.Emit(OpCodes.Leave, labels(whereto)) +// } else if (next != whereto) +// mcode.Emit(OpCodes.Br, labels(whereto)) +// +// case CJUMP(success, failure, cond, kind) => +// // cond is TestOp (see Primitives.scala), and can take +// // values EQ, NE, LT, GE LE, GT +// // kind is TypeKind +// val isFloat = kind == FLOAT || kind == DOUBLE +// val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat) +// emitCondBr(block, cond, success, failure, next, emit) +// +// case CZJUMP(success, failure, cond, kind) => +// emitCondBr(block, cond, success, failure, next, emitBrBool(_, _)) +// +// case RETURN(kind) => +// if (currentHandlers.isEmpty) +// mcode.Emit(OpCodes.Ret) +// else { +// val (local, label) = returnFromHandler(kind) +// if (kind != UNIT) +// mcode.Emit(OpCodes.Stloc, local) +// mcode.Emit(OpCodes.Leave, label) +// } +// +// case THROW(_) => +// mcode.Emit(OpCodes.Throw) +// +// case DROP(kind) => +// mcode.Emit(OpCodes.Pop) +// +// case DUP(kind) => +// // see comment on `var previousWasNEW` +// if (!previousWasNEW) +// mcode.Emit(OpCodes.Dup) +// else +// previousWasNEW = false +// +// case MONITOR_ENTER() => +// mcode.Emit(OpCodes.Call, MMONITOR_ENTER) +// +// case MONITOR_EXIT() => +// mcode.Emit(OpCodes.Call, MMONITOR_EXIT) +// +// case SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION(_) => +// () +// } +// +// } // end for (instr <- b) { .. } +// } // end genBlock +// +// def genPrimitive(primitive: Primitive, pos: Position) { +// primitive match { +// case Negation(kind) => +// kind match { +// // CHECK: is ist possible to get this for BOOL? in this case, verify. +// case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE => +// mcode.Emit(OpCodes.Neg) +// +// case _ => abort("Impossible to negate a " + kind) +// } +// +// case Arithmetic(op, kind) => +// op match { +// case ADD => mcode.Emit(OpCodes.Add) +// case SUB => mcode.Emit(OpCodes.Sub) +// case MUL => mcode.Emit(OpCodes.Mul) +// case DIV => mcode.Emit(OpCodes.Div) +// case REM => mcode.Emit(OpCodes.Rem) +// case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement) +// case _ => abort("Unknown arithmetic primitive " + primitive ) +// } +// +// case Logical(op, kind) => op match { +// case AND => mcode.Emit(OpCodes.And) +// case OR => mcode.Emit(OpCodes.Or) +// case XOR => mcode.Emit(OpCodes.Xor) +// } +// +// case Shift(op, kind) => op match { +// case LSL => mcode.Emit(OpCodes.Shl) +// case ASR => mcode.Emit(OpCodes.Shr) +// case LSR => mcode.Emit(OpCodes.Shr_Un) +// } +// +// case Conversion(src, dst) => +// debuglog("Converting from: " + src + " to: " + dst) +// +// dst match { +// case BYTE => mcode.Emit(OpCodes.Conv_I1) // I1 for System.SByte, i.e. a scala.Byte +// case SHORT => mcode.Emit(OpCodes.Conv_I2) +// case CHAR => mcode.Emit(OpCodes.Conv_U2) +// case INT => mcode.Emit(OpCodes.Conv_I4) +// case LONG => mcode.Emit(OpCodes.Conv_I8) +// case FLOAT => mcode.Emit(OpCodes.Conv_R4) +// case DOUBLE => mcode.Emit(OpCodes.Conv_R8) +// case _ => +// Console.println("Illegal conversion at: " + clasz + +// " at: " + pos.source + ":" + pos.line) +// } +// +// case ArrayLength(_) => +// mcode.Emit(OpCodes.Ldlen) +// +// case StartConcat => +// mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR) +// +// +// case StringConcat(el) => +// val elemType : MsilType = el match { +// case REFERENCE(_) | ARRAY(_) => MOBJECT +// case _ => msilType(el) +// } +// +// val argTypes:Array[MsilType] = Array(elemType) +// val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes ) +// mcode.Emit(OpCodes.Callvirt, stringBuilderAppend) +// +// case EndConcat => +// mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING) +// +// case _ => +// abort("Unimplemented primitive " + primitive) +// } +// } // end genPrimitive +// +// +// ////////////////////// loading /////////////////////// +// +// def loadI4(value: Int, code: ILGenerator): Unit = value match { +// case -1 => code.Emit(OpCodes.Ldc_I4_M1) +// case 0 => code.Emit(OpCodes.Ldc_I4_0) +// case 1 => code.Emit(OpCodes.Ldc_I4_1) +// case 2 => code.Emit(OpCodes.Ldc_I4_2) +// case 3 => code.Emit(OpCodes.Ldc_I4_3) +// case 4 => code.Emit(OpCodes.Ldc_I4_4) +// case 5 => code.Emit(OpCodes.Ldc_I4_5) +// case 6 => code.Emit(OpCodes.Ldc_I4_6) +// case 7 => code.Emit(OpCodes.Ldc_I4_7) +// case 8 => code.Emit(OpCodes.Ldc_I4_8) +// case _ => +// if (value >= -128 && value <= 127) +// code.Emit(OpCodes.Ldc_I4_S, value) +// else +// code.Emit(OpCodes.Ldc_I4, value) +// } +// +// def loadArg(code: ILGenerator, loadAddr: Boolean)(i: Int) = +// if (loadAddr) { +// if (i >= -128 && i <= 127) +// code.Emit(OpCodes.Ldarga_S, i) +// else +// code.Emit(OpCodes.Ldarga, i) +// } else { +// i match { +// case 0 => code.Emit(OpCodes.Ldarg_0) +// case 1 => code.Emit(OpCodes.Ldarg_1) +// case 2 => code.Emit(OpCodes.Ldarg_2) +// case 3 => code.Emit(OpCodes.Ldarg_3) +// case _ => +// if (i >= -128 && i <= 127) +// code.Emit(OpCodes.Ldarg_S, i) +// else +// code.Emit(OpCodes.Ldarg, i) +// } +// } +// +// def loadLocal(i: Int, local: Local, code: ILGenerator, loadAddr: Boolean) = +// if (loadAddr) { +// if (i >= -128 && i <= 127) +// code.Emit(OpCodes.Ldloca_S, localBuilders(local)) +// else +// code.Emit(OpCodes.Ldloca, localBuilders(local)) +// } else { +// i match { +// case 0 => code.Emit(OpCodes.Ldloc_0) +// case 1 => code.Emit(OpCodes.Ldloc_1) +// case 2 => code.Emit(OpCodes.Ldloc_2) +// case 3 => code.Emit(OpCodes.Ldloc_3) +// case _ => +// if (i >= -128 && i <= 127) +// code.Emit(OpCodes.Ldloc_S, localBuilders(local)) +// else +// code.Emit(OpCodes.Ldloc, localBuilders(local)) +// } +// } +// +// ////////////////////// branches /////////////////////// +// +// /** Returns a Triple (Boolean, Boolean, Option[Label]) +// * - whether the jump leaves some exception block (try / catch / finally) +// * - whether it leaves a finally handler (finally block, but not it's try / catch) +// * - a label where to jump for leaving the finally handler +// * . None to leave directly using `endfinally` +// * . Some(label) to emit `leave label` (for try / catch inside a finally handler) +// */ +// def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) = +// if (currentHandlers.isEmpty) (false, false, None) +// else { +// val h = currentHandlers.head +// val leaveHead = { h.covers(from) != h.covers(to) || +// h.blocks.contains(from) != h.blocks.contains(to) } +// if (leaveHead) { +// // we leave the innermost exception block. +// // find out if we also leave som e `finally` handler +// currentHandlers.find(e => { +// e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to) +// }) match { +// case Some(finallyHandler) => +// if (h == finallyHandler) { +// // the finally handler is the innermost, so we can emit `endfinally` directly +// (true, true, None) +// } else { +// // we need to `Leave` to the `endfinally` of the next outer finally handler +// val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel()) +// (true, true, Some(l)) +// } +// case None => +// (true, false, None) +// } +// } else (false, false, None) +// } +// +// def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock, +// next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) { +// val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success) +// val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure) +// +// if (sLeaveHandler || fLeaveHandler) { +// val sLabelOpt = if (sLeaveHandler) { +// val leaveSLabel = mcode.DefineLabel() +// emitBrFun(cond, leaveSLabel) +// Some(leaveSLabel) +// } else { +// emitBrFun(cond, labels(success)) +// None +// } +// +// if (fLeaveHandler) { +// if (fLeaveFinally) { +// if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get) +// else mcode.Emit(OpCodes.Endfinally) +// } else +// mcode.Emit(OpCodes.Leave, labels(failure)) +// } else +// mcode.Emit(OpCodes.Br, labels(failure)) +// +// sLabelOpt.map(l => { +// mcode.MarkLabel(l) +// if (sLeaveFinally) { +// if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get) +// else mcode.Emit(OpCodes.Endfinally) +// } else +// mcode.Emit(OpCodes.Leave, labels(success)) +// }) +// } else { +// if (next == success) { +// emitBrFun(cond.negate, labels(failure)) +// } else { +// emitBrFun(cond, labels(success)) +// if (next != failure) { +// mcode.Emit(OpCodes.Br, labels(failure)) +// } +// } +// } +// } +// +// def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) { +// condition match { +// case EQ => mcode.Emit(OpCodes.Beq, dest) +// case NE => mcode.Emit(OpCodes.Bne_Un, dest) +// case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest) +// case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest) +// case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest) +// case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest) +// } +// } +// +// def emitBrBool(cond: TestOp, dest: Label) { +// cond match { +// // EQ -> Brfalse, NE -> Brtrue; this is because we come from +// // a CZJUMP. If the value on the stack is 0 (e.g. a boolean +// // method returned false), and we are in the case EQ, then +// // we need to emit Brfalse (EQ Zero means false). vice versa +// case EQ => mcode.Emit(OpCodes.Brfalse, dest) +// case NE => mcode.Emit(OpCodes.Brtrue, dest) +// } +// } +// +// ////////////////////// local vars /////////////////////// +// +// /** +// * Compute the indexes of each local variable of the given +// * method. +// */ +// def computeLocalVarsIndex(m: IMethod) { +// var idx = if (m.symbol.isStaticMember) 0 else 1 +// +// val params = m.params +// for (l <- params) { +// debuglog("Index value for parameter " + l + ": " + idx) +// l.index = idx +// idx += 1 // sizeOf(l.kind) +// } +// +// val locvars = m.locals filterNot (params contains) +// idx = 0 +// +// for (l <- locvars) { +// debuglog("Index value for local variable " + l + ": " + idx) +// l.index = idx +// idx += 1 // sizeOf(l.kind) +// } +// +// } +// +// ////////////////////// Utilities //////////////////////// +// +// /** Return the a name of this symbol that can be used on the .NET +// * platform. It removes spaces from names. +// * +// * Special handling: scala.All and scala.AllRef are 'erased' to +// * scala.All$ and scala.AllRef$. This is needed because they are +// * not real classes, and they mean 'abrupt termination upon evaluation +// * of that expression' or 'null' respectively. This handling is +// * done already in GenICode, but here we need to remove references +// * from method signatures to these types, because such classes can +// * not exist in the classpath: the type checker will be very confused. +// */ +// def msilName(sym: Symbol): String = { +// val suffix = sym.moduleSuffix +// // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class) +// +// if (sym == definitions.NothingClass) +// return "scala.runtime.Nothing$" +// else if (sym == definitions.NullClass) +// return "scala.runtime.Null$" +// +// (if (sym.isClass || (sym.isModule && !sym.isMethod)) { +// if (sym.isNestedClass) sym.simpleName +// else sym.fullName +// } else +// sym.simpleName.toString.trim()) + suffix +// } +// +// +// ////////////////////// flags /////////////////////// +// +// def msilTypeFlags(sym: Symbol): Int = { +// var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass +// +// if(sym.isNestedClass) { +// mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NestedPrivate else TypeAttributes.NestedPublic) +// } else { +// mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public) +// } +// mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0) +// mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class) +// mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) +// +// sym.annotations foreach { a => a match { +// case AnnotationInfo(SerializableAttr, _, _) => +// // TODO: add the Serializable TypeAttribute also if the annotation +// // System.SerializableAttribute is present (.net annotation, not scala) +// // Best way to do it: compare with +// // definitions.getClass("System.SerializableAttribute").tpe +// // when frontend available +// mf = mf | TypeAttributes.Serializable +// case _ => () +// }} +// +// mf +// // static: not possible (or?) +// } +// +// def msilMethodFlags(sym: Symbol): Short = { +// var mf: Int = MethodAttributes.HideBySig | +// (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private +// else MethodAttributes.Public) +// +// if (!sym.isClassConstructor) { +// if (sym.isStaticMember) +// mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ... +// else { +// mf = mf | MethodAttributes.Virtual +// if (sym.isFinal && !getType(sym.owner).IsInterface) +// mf = mf | MethodAttributes.Final +// if (sym.isDeferred || getType(sym.owner).IsInterface) +// mf = mf | MethodAttributes.Abstract +// } +// } +// +// if (sym.isStaticMember) { +// mf = mf | MethodAttributes.Static +// } +// +// // constructors of module classes should be private +// if (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) { +// mf |= MethodAttributes.Private +// mf &= ~(MethodAttributes.Public) +// } +// +// mf.toShort +// } +// +// def msilFieldFlags(sym: Symbol): Short = { +// var mf: Int = +// if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private +// else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem +// else FieldAttributes.Public +// +// if (sym hasFlag Flags.FINAL) +// mf = mf | FieldAttributes.InitOnly +// +// if (sym.isStaticMember) +// mf = mf | FieldAttributes.Static +// +// // TRANSIENT: "not serialized", VOLATILE: doesn't exist on .net +// // TODO: add this annotation also if the class has the custom attribute +// // System.NotSerializedAttribute +// sym.annotations.foreach( a => a match { +// case AnnotationInfo(TransientAtt, _, _) => +// mf = mf | FieldAttributes.NotSerialized +// case _ => () +// }) +// +// mf.toShort +// } +// +// ////////////////////// builders, types /////////////////////// +// +// var entryPoint: Symbol = _ +// +// val notInitializedModules = mutable.HashSet[Symbol]() +// +// // TODO: create fields also in def createType, and not in genClass, +// // add a getField method (it only works as it is because fields never +// // accessed from outside a class) +// +// val localBuilders = mutable.HashMap[Local, LocalBuilder]() +// +// private[GenMSIL] def findEntryPoint(cls: IClass) { +// +// def isEntryPoint(sym: Symbol):Boolean = { +// if (isStaticModule(sym.owner) && msilName(sym) == "main") +// if (sym.tpe.paramTypes.length == 1) { +// toTypeKind(sym.tpe.paramTypes(0)) match { +// case ARRAY(elem) => +// if (elem.toType.typeSymbol == definitions.StringClass) { +// return true +// } +// case _ => () +// } +// } +// false +// } +// +// if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead +// val entryclass = opt.showClass.get.toString +// val cfn = cls.symbol.fullName +// if(cfn == entryclass) { +// for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol } +// if(entryPoint == null) { warning("Couldn't find main method in class " + cfn) } +// } +// } +// +// if (firstSourceName == "") +// if (cls.symbol.sourceFile != null) // is null for nested classes +// firstSourceName = cls.symbol.sourceFile.name +// } +// +// // ##################################################################### +// // get and create types +// +// private def msilType(t: TypeKind): MsilType = (t: @unchecked) match { +// case UNIT => MVOID +// case BOOL => MBOOL +// case BYTE => MBYTE +// case SHORT => MSHORT +// case CHAR => MCHAR +// case INT => MINT +// case LONG => MLONG +// case FLOAT => MFLOAT +// case DOUBLE => MDOUBLE +// case REFERENCE(cls) => getType(cls) +// case ARRAY(elem) => +// msilType(elem) match { +// // For type builders, cannot call "clrTypes.mkArrayType" because this looks up +// // the type "tp" in the assembly (not in the HashMap "types" of the backend). +// // This can fail for nested types because the builders are not complete yet. +// case tb: TypeBuilder => tb.MakeArrayType() +// case tp: MsilType => clrTypes.mkArrayType(tp) +// } +// } +// +// private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe)) +// +// private def msilParamTypes(sym: Symbol): Array[MsilType] = { +// sym.tpe.paramTypes.map(msilType).toArray +// } +// +// def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym))) +// +// /** +// * Get an MSIL type from a symbol. First look in the clrTypes.types map, then +// * lookup the name using clrTypes.getType +// */ +// def getTypeOpt(sym: Symbol): Option[MsilType] = { +// val tmp = types.get(sym) +// tmp match { +// case typ @ Some(_) => typ +// case None => +// def typeString(sym: Symbol): String = { +// val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName +// else sym.fullName +// if (sym.isModuleClass && !sym.isTrait) s + "$" else s +// } +// val name = typeString(sym) +// val typ = clrTypes.getType(name) +// if (typ == null) +// None +// else { +// types(sym) = typ +// Some(typ) +// } +// } +// } +// +// def mapType(sym: Symbol, mType: MsilType) { +// assert(mType != null, showsym(sym)) +// types(sym) = mType +// } +// +// def createTypeBuilder(iclass: IClass) { +// /** +// * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise +// * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)). +// */ +// def msilTypeFromSym(sym: Symbol): MsilType = { +// types.get(sym).getOrElse { +// classes.get(sym) match { +// case Some(iclass) => +// msilTypeBuilderFromSym(sym) +// case None => +// getType(sym) +// } +// } +// } +// +// def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = { +// if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){ +// val iclass = classes(sym) +// assert(iclass != null) +// createTypeBuilder(iclass) +// } +// types(sym).asInstanceOf[TypeBuilder] +// } +// +// val sym = iclass.symbol +// if (types.contains(sym) && types(sym).isInstanceOf[TypeBuilder]) +// return +// +// def isInterface(s: Symbol) = s.isTrait && !s.isImplClass +// val parents: List[Type] = +// if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe) +// else sym.info.parents.distinct +// +// val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol) +// debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType) +// +// val interfaces: Array[MsilType] = +// parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray +// if (parents.length > 1) { +// if (settings.debug.value) { +// log("interfaces:") +// for (i <- 0.until(interfaces.length)) { +// log(" type: " + parents(i + 1).typeSymbol + ", msil type: " + interfaces(i)) +// } +// } +// } +// +// val tBuilder = if (sym.isNestedClass) { +// val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder] +// ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces) +// } else { +// mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces) +// } +// mapType(sym, tBuilder) +// } // createTypeBuilder +// +// def createClassMembers(iclass: IClass) { +// try { +// createClassMembers0(iclass) +// } +// catch { +// case e: Throwable => +// java.lang.System.err.println(showsym(iclass.symbol)) +// java.lang.System.err.println("with methods = " + iclass.methods) +// throw e +// } +// } +// +// def createClassMembers0(iclass: IClass) { +// +// val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder] +// +// for (ifield <- iclass.fields) { +// val sym = ifield.symbol +// debuglog("Adding field: " + sym.fullName) +// +// var attributes = msilFieldFlags(sym) +// val fieldTypeWithCustomMods = +// new PECustomMod(msilType(sym.tpe), +// customModifiers(sym.annotations)) +// val fBuilder = mtype.DefineField(msilName(sym), +// fieldTypeWithCustomMods, +// attributes) +// fields(sym) = fBuilder +// addAttributes(fBuilder, sym.annotations) +// } // all iclass.fields iterated over +// +// if (isStaticModule(iclass.symbol)) { +// val sc = iclass.lookupStaticCtor +// if (sc.isDefined) { +// val m = sc.get +// val oldLastBlock = m.lastBlock +// val lastBlock = m.newBlock() +// oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock)) +// // call object's private ctor from static ctor +// lastBlock.emit(CIL_NEWOBJ(iclass.symbol.primaryConstructor)) +// lastBlock.emit(DROP(toTypeKind(iclass.symbol.tpe))) +// lastBlock emit RETURN(UNIT) +// lastBlock.close +// } +// } +// +// if (iclass.symbol != definitions.ArrayClass) { +// for (m: IMethod <- iclass.methods) { +// val sym = m.symbol +// debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " + +// sym.owner.fullName + "::" + sym.name) +// +// val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder] +// assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType) +// var paramTypes = msilParamTypes(sym) +// val attr = msilMethodFlags(sym) +// +// if (m.symbol.isClassConstructor) { +// val constr = +// ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes) +// for (i <- 0.until(paramTypes.length)) { +// constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) +// } +// mapConstructor(sym, constr) +// addAttributes(constr, sym.annotations) +// } else { +// var resType = msilType(m.returnType) +// val method = +// ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes) +// for (i <- 0.until(paramTypes.length)) { +// method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) +// } +// if (!methods.contains(sym)) +// mapMethod(sym, method) +// addAttributes(method, sym.annotations) +// debuglog("\t created MethodBuilder " + method) +// } +// } +// } // method builders created for non-array iclass +// +// if (isStaticModule(iclass.symbol)) { +// addModuleInstanceField(iclass.symbol) +// notInitializedModules += iclass.symbol +// if (iclass.lookupStaticCtor.isEmpty) { +// addStaticInit(iclass.symbol) +// } +// } +// +// } // createClassMembers0 +// +// private def isTopLevelModule(sym: Symbol): Boolean = +// atPhase (currentRun.refchecksPhase) { +// sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass +// } +// +// // if the module is lifted it does not need to be initialized in +// // its static constructor, and the MODULE$ field is not required. +// // the outer class will care about it. +// private def isStaticModule(sym: Symbol): Boolean = { +// // .net inner classes: removed '!sym.hasFlag(Flags.LIFTED)', added +// // 'sym.isStatic'. -> no longer compatible without skipping flatten! +// sym.isModuleClass && sym.isStatic && !sym.isImplClass +// } +// +// private def isCloneable(sym: Symbol): Boolean = { +// !sym.annotations.forall( a => a match { +// case AnnotationInfo(CloneableAttr, _, _) => false +// case _ => true +// }) +// } +// +// private def addModuleInstanceField(sym: Symbol) { +// debuglog("Adding Module-Instance Field for " + showsym(sym)) +// val tBuilder = getType(sym).asInstanceOf[TypeBuilder] +// val fb = tBuilder.DefineField(MODULE_INSTANCE_NAME, +// tBuilder, +// (FieldAttributes.Public | +// //FieldAttributes.InitOnly | +// FieldAttributes.Static).toShort) +// fields(sym) = fb +// } +// +// +// // the symbol may be a object-symbol (module-symbol), or a module-class-symbol +// private def getModuleInstanceField(sym: Symbol): FieldInfo = { +// assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym)) +// +// // when called by LOAD_MODULE, the corresponding type maybe doesn't +// // exist yet -> make a getType +// val moduleClassSym = if (sym.isModule) sym.moduleClass else sym +// +// // TODO: get module field for modules not defined in the +// // source currently compiling (e.g. Console) +// +// fields get moduleClassSym match { +// case Some(sym) => sym +// case None => +// //val mclass = types(moduleClassSym) +// val nameInMetadata = nestingAwareFullClassname(moduleClassSym) +// val mClass = clrTypes.getType(nameInMetadata) +// val mfield = mClass.GetField("MODULE$") +// assert(mfield ne null, "module not found " + showsym(moduleClassSym)) +// fields(moduleClassSym) = mfield +// mfield +// } +// +// //fields(moduleClassSym) +// } +// +// def nestingAwareFullClassname(csym: Symbol) : String = { +// val suffix = csym.moduleSuffix +// val res = if (csym.isNestedClass) +// nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName +// else +// csym.fullName +// res + suffix +// } +// +// /** Adds a static initializer which creates an instance of the module +// * class (calls the primary constructor). A special primary constructor +// * will be generated (notInitializedModules) which stores the new instance +// * in the MODULE$ field right after the super call. +// */ +// private def addStaticInit(sym: Symbol) { +// val tBuilder = getType(sym).asInstanceOf[TypeBuilder] +// +// val staticInit = tBuilder.DefineConstructor( +// (MethodAttributes.Static | MethodAttributes.Public).toShort, +// CallingConventions.Standard, +// MsilType.EmptyTypes) +// +// val sicode = staticInit.GetILGenerator() +// +// val instanceConstructor = constructors(sym.primaryConstructor) +// +// // there are no constructor parameters. assuming the constructor takes no parameter +// // is fine: we call (in the static constructor) the constructor of the module class, +// // which takes no arguments - an object definition cannot take constructor arguments. +// sicode.Emit(OpCodes.Newobj, instanceConstructor) +// // the stsfld is done in the instance constructor, just after the super call. +// sicode.Emit(OpCodes.Pop) +// +// sicode.Emit(OpCodes.Ret) +// } +// +// private def generateMirrorClass(sym: Symbol) { +// val tBuilder = getType(sym) +// assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym) +// debuglog("Dumping mirror class for object: " + sym) +// val moduleName = msilName(sym) +// val mirrorName = moduleName.substring(0, moduleName.length() - 1) +// val mirrorTypeBuilder = mmodule.DefineType(mirrorName, +// TypeAttributes.Class | +// TypeAttributes.Public | +// TypeAttributes.Sealed, +// MOBJECT, +// MsilType.EmptyTypes) +// +// val iclass = classes(sym) +// +// for (m <- sym.tpe.nonPrivateMembers +// if m.owner != definitions.ObjectClass && !m.isProtected && +// m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase && +// !m.isDeferred) +// { +// debuglog(" Mirroring method: " + m) +// val paramTypes = msilParamTypes(m) +// val paramNames: Array[String] = new Array[String](paramTypes.length) +// for (i <- 0 until paramTypes.length) +// paramNames(i) = "x_" + i +// +// // CHECK: verify if getMethodName is better than msilName +// val mirrorMethod = mirrorTypeBuilder.DefineMethod(msilName(m), +// (MethodAttributes.Public | +// MethodAttributes.Static).toShort, +// msilType(m.tpe.resultType), +// paramTypes) +// +// var i = 0 +// while (i < paramTypes.length) { +// mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i)) +// i += 1 +// } +// +// val mirrorCode = mirrorMethod.GetILGenerator() +// mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym)) +// val mInfo = getMethod(m) +// for (paramidx <- 0.until(paramTypes.length)) { +// val mInfoParams = mInfo.GetParameters +// val loadAddr = mInfoParams(paramidx).ParameterType.IsByRef +// loadArg(mirrorCode, loadAddr)(paramidx) +// } +// +// mirrorCode.Emit(OpCodes.Callvirt, getMethod(m)) +// mirrorCode.Emit(OpCodes.Ret) +// } +// +// addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder) +// +// mirrorTypeBuilder.CreateType() +// mirrorTypeBuilder.setSourceFilepath(iclass.cunit.source.file.path) +// } +// +// +// // ##################################################################### +// // delegate callers +// +// var delegateCallers: TypeBuilder = _ +// var nbDelegateCallers: Int = 0 +// +// private def initDelegateCallers() = { +// delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public | +// TypeAttributes.Sealed) +// } +// +// private def createDelegateCaller(functionType: Type, delegateType: Type) = { +// if (delegateCallers == null) +// initDelegateCallers() +// // create a field an store the function-object +// val mFunctionType: MsilType = msilType(functionType) +// val anonfunField: FieldBuilder = delegateCallers.DefineField( +// "$anonfunField$$" + nbDelegateCallers, mFunctionType, +// (FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static).toShort) +// mcode.Emit(OpCodes.Stsfld, anonfunField) +// +// +// // create the static caller method and the delegate object +// val (params, returnType) = delegateType.member(nme.apply).tpe match { +// case MethodType(delParams, delReturn) => (delParams, delReturn) +// case _ => abort("not a delegate type: " + delegateType) +// } +// val caller: MethodBuilder = delegateCallers.DefineMethod( +// "$delegateCaller$$" + nbDelegateCallers, +// (MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static).toShort, +// msilType(returnType), (params map (_.tpe)).map(msilType).toArray) +// for (i <- 0 until params.length) +// caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol +// val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) +// mcode.Emit(OpCodes.Ldnull) +// mcode.Emit(OpCodes.Ldftn, caller) +// mcode.Emit(OpCodes.Newobj, delegCtor) +// +// +// // create the static caller method body +// val functionApply: MethodInfo = getMethod(functionType.member(nme.apply)) +// val dcode: ILGenerator = caller.GetILGenerator() +// dcode.Emit(OpCodes.Ldsfld, anonfunField) +// for (i <- 0 until params.length) { +// loadArg(dcode, false /* TODO confirm whether passing actual as-is to formal is correct wrt the ByRef attribute of the param */)(i) +// emitBox(dcode, toTypeKind(params(i).tpe)) +// } +// dcode.Emit(OpCodes.Callvirt, functionApply) +// emitUnbox(dcode, toTypeKind(returnType)) +// dcode.Emit(OpCodes.Ret) +// +// nbDelegateCallers = nbDelegateCallers + 1 +// +// } //def createDelegateCaller +// +// def emitBox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { +// // doesn't make sense, unit as parameter.. +// case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit) +// case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE => +// code.Emit(OpCodes.Box, msilType(boxType)) +// case REFERENCE(cls) if clrTypes.isValueType(cls) => +// code.Emit(OpCodes.Box, (msilType(boxType))) +// case REFERENCE(_) | ARRAY(_) => +// warning("Tried to BOX a non-valuetype.") +// () +// } +// +// def emitUnbox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { +// case UNIT => code.Emit(OpCodes.Pop) +// /* (1) it's essential to keep the code emitted here (as of now plain calls to System.Convert.ToBlaBla methods) +// behaviorally.equiv.wrt. BoxesRunTime.unboxToBlaBla methods +// (case null: that's easy, case boxed: track changes to unboxBlaBla) +// (2) See also: asInstanceOf to cast from Any to number, +// tracked in http://lampsvn.epfl.ch/trac/scala/ticket/4437 */ +// case BOOL => code.Emit(OpCodes.Call, toBool) +// case BYTE => code.Emit(OpCodes.Call, toSByte) +// case SHORT => code.Emit(OpCodes.Call, toShort) +// case CHAR => code.Emit(OpCodes.Call, toChar) +// case INT => code.Emit(OpCodes.Call, toInt) +// case LONG => code.Emit(OpCodes.Call, toLong) +// case FLOAT => code.Emit(OpCodes.Call, toFloat) +// case DOUBLE => code.Emit(OpCodes.Call, toDouble) +// case REFERENCE(cls) if clrTypes.isValueType(cls) => +// code.Emit(OpCodes.Unbox, msilType(boxType)) +// code.Emit(OpCodes.Ldobj, msilType(boxType)) +// case REFERENCE(_) | ARRAY(_) => +// warning("Tried to UNBOX a non-valuetype.") +// () +// } +// +// // ##################################################################### +// // get and create methods / constructors +// +// def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match { +// case Some(constr) => constr +// case None => +// val mClass = getType(sym.owner) +// val constr = mClass.GetConstructor(msilParamTypes(sym)) +// if (constr eq null) { +// java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name) +// java.lang.System.out.println("scope = " + sym.owner.tpe.decls) +// abort(sym.fullName) +// } +// else { +// mapConstructor(sym, constr) +// constr +// } +// } +// +// def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = { +// constructors(sym) = cInfo +// } +// +// private def getMethod(sym: Symbol): MethodInfo = { +// +// methods.get(sym) match { +// case Some(method) => method +// case None => +// val mClass = getType(sym.owner) +// try { +// val method = mClass.GetMethod(msilName(sym), msilParamTypes(sym), +// msilType(sym.tpe.resultType)) +// if (method eq null) { +// java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym)) +// java.lang.System.out.println("scope = " + sym.owner.tpe.decls) +// abort(sym.fullName) +// } +// else { +// mapMethod(sym, method) +// method +// } +// } +// catch { +// case e: Exception => +// Console.println("While looking up " + mClass + "::" + sym.nameString) +// Console.println("\t" + showsym(sym)) +// throw e +// } +// } +// } +// +// /* +// * add a mapping between sym and mInfo +// */ +// private def mapMethod(sym: Symbol, mInfo: MethodInfo) { +// assert (mInfo != null, mInfo) +// methods(sym) = mInfo +// } +// +// /* +// * add mapping between sym and method with newName, paramTypes of newClass +// */ +// private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) { +// val methodInfo = newClass.GetMethod(newName, paramTypes) +// assert(methodInfo != null, "Can't find mapping for " + sym + " -> " + +// newName + "(" + paramTypes + ")") +// mapMethod(sym, methodInfo) +// if (methodInfo.IsStatic) +// dynToStatMapped += sym +// } +// +// /* +// * add mapping between method with name and paramTypes of clazz to +// * method with newName and newParamTypes of newClass (used for instance +// * for "wait") +// */ +// private def mapMethod( +// clazz: Symbol, name: Name, paramTypes: Array[Type], +// newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) { +// val methodSym = lookupMethod(clazz, name, paramTypes) +// assert(methodSym != null, "cannot find method " + name + "(" + +// paramTypes + ")" + " in class " + clazz) +// mapMethod(methodSym, newClass, newName, newParamTypes) +// } +// +// /* +// * add mapping for member with name and paramTypes to member +// * newName of newClass (same parameters) +// */ +// private def mapMethod( +// clazz: Symbol, name: Name, paramTypes: Array[Type], +// newClass: MsilType, newName: String) { +// mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) +// } +// +// /* +// * add mapping for all methods with name of clazz to the corresponding +// * method (same parameters) with newName of newClass +// */ +// private def mapMethod( +// clazz: Symbol, name: Name, +// newClass: MsilType, newName: String) { +// val memberSym: Symbol = clazz.tpe.member(name) +// memberSym.tpe match { +// // alternatives: List[Symbol] +// case OverloadedType(_, alternatives) => +// alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s))) +// +// // paramTypes: List[Type], resType: Type +// case MethodType(params, resType) => +// mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) +// +// case _ => +// abort("member not found: " + clazz + ", " + name) +// } +// } +// +// +// /* +// * find the method in clazz with name and paramTypes +// */ +// private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = { +// val memberSym = clazz.tpe.member(name) +// memberSym.tpe match { +// case OverloadedType(_, alternatives) => +// alternatives.find(s => { +// var i: Int = 0 +// var typesOK: Boolean = true +// if (paramTypes.length == s.tpe.paramTypes.length) { +// while(i < paramTypes.length) { +// if (paramTypes(i) != s.tpe.paramTypes(i)) +// typesOK = false +// i += 1 +// } +// } else { +// typesOK = false +// } +// typesOK +// }) match { +// case Some(sym) => sym +// case None => abort("member of " + clazz + ", " + name + "(" + +// paramTypes + ") not found") +// } +// +// case MethodType(_, _) => memberSym +// +// case _ => abort("member not found: " + name + " of " + clazz) +// } +// } +// +// private def showsym(sym: Symbol): String = (sym.toString + +// "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym + +// "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner +// ) +// +// } // class BytecodeGenerator +// +// } // class GenMSIL diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala index d970d0e9c9..2982812fdd 100644 --- a/src/compiler/scala/tools/nsc/io/MsilFile.scala +++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala @@ -1,18 +1,18 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Paul Phillips - */ - -package scala.tools.nsc -package io - -import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } - -/** This class wraps an MsilType. It exists only so - * ClassPath can treat all of JVM/MSIL/bin/src files - * uniformly, as AbstractFiles. - */ -class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { -} - -object NoMsilFile extends MsilFile(null) { } +// /* NSC -- new Scala compiler +// * Copyright 2005-2011 LAMP/EPFL +// * @author Paul Phillips +// */ +// +// package scala.tools.nsc +// package io +// +// import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } +// +// /** This class wraps an MsilType. It exists only so +// * ClassPath can treat all of JVM/MSIL/bin/src files +// * uniformly, as AbstractFiles. +// */ +// class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { +// } +// +// object NoMsilFile extends MsilFile(null) { } diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 942ec1fa86..2241bb224e 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -13,7 +13,7 @@ import classfile.ClassfileParser import reflect.internal.Flags._ import reflect.internal.MissingRequirementError import util.Statistics._ -import scala.tools.nsc.io.{ AbstractFile, MsilFile } +import scala.tools.nsc.io.{ AbstractFile } //, MsilFile } /** This class ... * @@ -236,16 +236,16 @@ abstract class SymbolLoaders { } override def sourcefile: Option[AbstractFile] = classfileParser.srcfile } - - class MsilFileLoader(msilFile: MsilFile) extends SymbolLoader { - private def typ = msilFile.msilType - private object typeParser extends clr.TypeParser { - val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global - } - - protected def description = "MsilFile "+ typ.FullName + ", assembly "+ typ.Assembly.FullName - protected def doComplete(root: Symbol) { typeParser.parse(typ, root) } - } + // + // class MsilFileLoader(msilFile: MsilFile) extends SymbolLoader { + // private def typ = msilFile.msilType + // private object typeParser extends clr.TypeParser { + // val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global + // } + // + // protected def description = "MsilFile "+ typ.FullName + ", assembly "+ typ.Assembly.FullName + // protected def doComplete(root: Symbol) { typeParser.parse(typ, root) } + // } class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader { protected def description = "source file "+ srcfile.toString @@ -258,11 +258,11 @@ abstract class SymbolLoaders { protected def description = "module class loader" protected def doComplete(root: Symbol) { root.sourceModule.initialize } } - - object clrTypes extends clr.CLRTypes { - val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global - if (global.forMSIL) init() - } + // + // object clrTypes extends clr.CLRTypes { + // val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global + // if (global.forMSIL) init() + // } /** used from classfile parser to avoid cyclies */ var parentsLevel = 0 diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala index 7be0fcb146..4346cb6f8d 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala @@ -1,137 +1,137 @@ -/* NSC -- new scala compiler - * Copyright 2004-2011 LAMP/EPFL - */ - - -package scala.tools.nsc -package symtab -package clr - -import java.io.File -import java.util.{Comparator, StringTokenizer} -import scala.util.Sorting -import ch.epfl.lamp.compiler.msil._ -import scala.collection.{ mutable, immutable } -import scala.tools.nsc.util.{Position, NoPosition} - -/** - * Collects all types from all reference assemblies. - */ -abstract class CLRTypes { - - val global: Global - import global.Symbol - import global.definitions - - //########################################################################## - - var BYTE: Type = _ - var UBYTE: Type = _ - var SHORT: Type = _ - var USHORT: Type = _ - var CHAR: Type = _ - var INT: Type = _ - var UINT: Type = _ - var LONG: Type = _ - var ULONG: Type = _ - var FLOAT: Type = _ - var DOUBLE: Type = _ - var BOOLEAN: Type = _ - var VOID: Type = _ - var ENUM: Type = _ - var DELEGATE: Type = _ - - var OBJECT: Type = _ - var STRING: Type = _ - var STRING_ARRAY: Type = _ - - var VALUE_TYPE: Type = _ - - var SCALA_SYMTAB_ATTR: Type = _ - var SYMTAB_CONSTR: ConstructorInfo = _ - var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _ - - var DELEGATE_COMBINE: MethodInfo = _ - var DELEGATE_REMOVE: MethodInfo = _ - - val types: mutable.Map[Symbol,Type] = new mutable.HashMap - val constructors: mutable.Map[Symbol,ConstructorInfo] = new mutable.HashMap - val methods: mutable.Map[Symbol,MethodInfo] = new mutable.HashMap - val fields: mutable.Map[Symbol, FieldInfo] = new mutable.HashMap - val sym2type: mutable.Map[Type,Symbol] = new mutable.HashMap - val addressOfViews = new mutable.HashSet[Symbol] - val mdgptrcls4clssym: mutable.Map[ /*cls*/ Symbol, /*cls*/ Symbol] = new mutable.HashMap - - def isAddressOf(msym : Symbol) = addressOfViews.contains(msym) - - def isNonEnumValuetype(cls: Symbol) = { - val msilTOpt = types.get(cls) - val res = msilTOpt.isDefined && { - val msilT = msilTOpt.get - msilT.IsValueType && !msilT.IsEnum - } - res - } - - def isValueType(cls: Symbol): Boolean = { - val opt = types.get(cls) - opt.isDefined && opt.get.IsValueType - } - - def init() = try { // initialize - // the MsilClasspath (nsc/util/Classpath.scala) initializes the msil-library by calling - // Assembly.LoadFrom("mscorlib.dll"), so this type should be found - Type.initMSCORLIB(getTypeSafe("System.String").Assembly) - - BYTE = getTypeSafe("System.SByte") - UBYTE = getTypeSafe("System.Byte") - CHAR = getTypeSafe("System.Char") - SHORT = getTypeSafe("System.Int16") - USHORT = getTypeSafe("System.UInt16") - INT = getTypeSafe("System.Int32") - UINT = getTypeSafe("System.UInt32") - LONG = getTypeSafe("System.Int64") - ULONG = getTypeSafe("System.UInt64") - FLOAT = getTypeSafe("System.Single") - DOUBLE = getTypeSafe("System.Double") - BOOLEAN = getTypeSafe("System.Boolean") - VOID = getTypeSafe("System.Void") - ENUM = getTypeSafe("System.Enum") - DELEGATE = getTypeSafe("System.MulticastDelegate") - - OBJECT = getTypeSafe("System.Object") - STRING = getTypeSafe("System.String") - STRING_ARRAY = getTypeSafe("System.String[]") - VALUE_TYPE = getTypeSafe("System.ValueType") - - SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute") - val bytearray: Array[Type] = Array(Type.GetType("System.Byte[]")) - SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray) - SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes) - - val delegate: Type = getTypeSafe("System.Delegate") - val dargs: Array[Type] = Array(delegate, delegate) - DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs) - DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs) - } - catch { - case e: RuntimeException => - Console.println(e.getMessage) - throw e - } - - //########################################################################## - // type mapping and lookup - - def getType(name: String): Type = Type.GetType(name) - - def getTypeSafe(name: String): Type = { - val t = Type.GetType(name) - assert(t != null, name) - t - } - - def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]") - - def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE } -} // CLRTypes +// /* NSC -- new scala compiler +// * Copyright 2004-2011 LAMP/EPFL +// */ +// +// +// package scala.tools.nsc +// package symtab +// package clr +// +// import java.io.File +// import java.util.{Comparator, StringTokenizer} +// import scala.util.Sorting +// import ch.epfl.lamp.compiler.msil._ +// import scala.collection.{ mutable, immutable } +// import scala.tools.nsc.util.{Position, NoPosition} +// +// /** +// * Collects all types from all reference assemblies. +// */ +// abstract class CLRTypes { +// +// val global: Global +// import global.Symbol +// import global.definitions +// +// //########################################################################## +// +// var BYTE: Type = _ +// var UBYTE: Type = _ +// var SHORT: Type = _ +// var USHORT: Type = _ +// var CHAR: Type = _ +// var INT: Type = _ +// var UINT: Type = _ +// var LONG: Type = _ +// var ULONG: Type = _ +// var FLOAT: Type = _ +// var DOUBLE: Type = _ +// var BOOLEAN: Type = _ +// var VOID: Type = _ +// var ENUM: Type = _ +// var DELEGATE: Type = _ +// +// var OBJECT: Type = _ +// var STRING: Type = _ +// var STRING_ARRAY: Type = _ +// +// var VALUE_TYPE: Type = _ +// +// var SCALA_SYMTAB_ATTR: Type = _ +// var SYMTAB_CONSTR: ConstructorInfo = _ +// var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _ +// +// var DELEGATE_COMBINE: MethodInfo = _ +// var DELEGATE_REMOVE: MethodInfo = _ +// +// val types: mutable.Map[Symbol,Type] = new mutable.HashMap +// val constructors: mutable.Map[Symbol,ConstructorInfo] = new mutable.HashMap +// val methods: mutable.Map[Symbol,MethodInfo] = new mutable.HashMap +// val fields: mutable.Map[Symbol, FieldInfo] = new mutable.HashMap +// val sym2type: mutable.Map[Type,Symbol] = new mutable.HashMap +// val addressOfViews = new mutable.HashSet[Symbol] +// val mdgptrcls4clssym: mutable.Map[ /*cls*/ Symbol, /*cls*/ Symbol] = new mutable.HashMap +// +// def isAddressOf(msym : Symbol) = addressOfViews.contains(msym) +// +// def isNonEnumValuetype(cls: Symbol) = { +// val msilTOpt = types.get(cls) +// val res = msilTOpt.isDefined && { +// val msilT = msilTOpt.get +// msilT.IsValueType && !msilT.IsEnum +// } +// res +// } +// +// def isValueType(cls: Symbol): Boolean = { +// val opt = types.get(cls) +// opt.isDefined && opt.get.IsValueType +// } +// +// def init() = try { // initialize +// // the MsilClasspath (nsc/util/Classpath.scala) initializes the msil-library by calling +// // Assembly.LoadFrom("mscorlib.dll"), so this type should be found +// Type.initMSCORLIB(getTypeSafe("System.String").Assembly) +// +// BYTE = getTypeSafe("System.SByte") +// UBYTE = getTypeSafe("System.Byte") +// CHAR = getTypeSafe("System.Char") +// SHORT = getTypeSafe("System.Int16") +// USHORT = getTypeSafe("System.UInt16") +// INT = getTypeSafe("System.Int32") +// UINT = getTypeSafe("System.UInt32") +// LONG = getTypeSafe("System.Int64") +// ULONG = getTypeSafe("System.UInt64") +// FLOAT = getTypeSafe("System.Single") +// DOUBLE = getTypeSafe("System.Double") +// BOOLEAN = getTypeSafe("System.Boolean") +// VOID = getTypeSafe("System.Void") +// ENUM = getTypeSafe("System.Enum") +// DELEGATE = getTypeSafe("System.MulticastDelegate") +// +// OBJECT = getTypeSafe("System.Object") +// STRING = getTypeSafe("System.String") +// STRING_ARRAY = getTypeSafe("System.String[]") +// VALUE_TYPE = getTypeSafe("System.ValueType") +// +// SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute") +// val bytearray: Array[Type] = Array(Type.GetType("System.Byte[]")) +// SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray) +// SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes) +// +// val delegate: Type = getTypeSafe("System.Delegate") +// val dargs: Array[Type] = Array(delegate, delegate) +// DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs) +// DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs) +// } +// catch { +// case e: RuntimeException => +// Console.println(e.getMessage) +// throw e +// } +// +// //########################################################################## +// // type mapping and lookup +// +// def getType(name: String): Type = Type.GetType(name) +// +// def getTypeSafe(name: String): Type = { +// val t = Type.GetType(name) +// assert(t != null, name) +// t +// } +// +// def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]") +// +// def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE } +// } // CLRTypes diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 736d1c78a3..82d1dd6bc3 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -1,851 +1,851 @@ -/* NSC -- new scala compiler - * Copyright 2004-2011 LAMP/EPFL - */ - -package scala.tools.nsc -package symtab -package clr - -import java.io.IOException -import io.MsilFile -import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _} -import scala.collection.{ mutable, immutable } -import scala.reflect.internal.pickling.UnPickler -import ch.epfl.lamp.compiler.msil.Type.TMVarUsage - -/** - * @author Nikolay Mihaylov - */ -abstract class TypeParser { - - val global: Global - - import global._ - import loaders.clrTypes - - //########################################################################## - - private var clazz: Symbol = _ - private var instanceDefs: Scope = _ // was members - private var staticModule: Symbol = _ // was staticsClass - private var staticDefs: Scope = _ // was statics - - protected def statics: Symbol = staticModule.moduleClass - - protected var busy: Boolean = false // lock to detect recursive reads - - private implicit def stringToTermName(s: String): TermName = newTermName(s) - - private object unpickler extends UnPickler { - val global: TypeParser.this.global.type = TypeParser.this.global - } - - def parse(typ: MSILType, root: Symbol) { - - def handleError(e: Throwable) = { - if (settings.debug.value) e.printStackTrace() //debug - throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")") - } - assert(!busy) - busy = true - - if (root.isModule) { - this.clazz = root.companionClass - this.staticModule = root - } else { - this.clazz = root - this.staticModule = root.companionModule - } - try { - parseClass(typ) - } catch { - case e: FatalError => handleError(e) - case e: RuntimeException => handleError(e) - } - busy = false - } - - class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { - override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } - } - - /* the names `classTParams` and `newTParams` stem from the forJVM version (ClassfileParser.sigToType()) - * but there are differences that should be kept in mind. - * forMSIL, a nested class knows nothing about any type-params in the nesting class, - * therefore newTParams is redundant (other than for recording lexical order), - * it always contains the same elements as classTParams.value */ - val classTParams = scala.collection.mutable.Map[Int,Symbol]() // TODO should this be a stack? (i.e., is it possible for >1 invocation to getCLRType on the same TypeParser instance be active ) - val newTParams = new scala.collection.mutable.ListBuffer[Symbol]() - val methodTParams = scala.collection.mutable.Map[Int,Symbol]() - - private def sig2typeBounds(tvarCILDef: GenericParamAndConstraints): Type = { - val ts = new scala.collection.mutable.ListBuffer[Type] - for (cnstrnt <- tvarCILDef.Constraints) { - ts += getCLRType(cnstrnt) // TODO we're definitely not at or after erasure, no need to call objToAny, right? - } - TypeBounds.upper(intersectionType(ts.toList, clazz)) - // TODO variance??? - } - - private def createViewFromTo(viewSuffix : String, fromTpe : Type, toTpe : Type, - addToboxMethodMap : Boolean, isAddressOf : Boolean) : Symbol = { - val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? - val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(List(fromTpe)), toTpe) - val vmsym = createMethod(nme.view_ + viewSuffix, flags, viewMethodType, null, true); - // !!! this used to mutate a mutable map in definitions, but that map became - // immutable and this kept "working" with a no-op. So now it's commented out - // since I retired the deprecated code which allowed for that bug. - // - // if (addToboxMethodMap) definitions.boxMethod(clazz) = vmsym - - if (isAddressOf) clrTypes.addressOfViews += vmsym - vmsym - } - - private def createDefaultConstructor(typ: MSILType) { - val attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName // TODO instance - val declType= typ - val method = new ConstructorInfo(declType, attrs, Array[MSILType]()) - val flags = Flags.JAVA - val owner = clazz - val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags) - val rettype = clazz.tpe - val mtype = methodType(Array[MSILType](), rettype); - val mInfo = mtype(methodSym) - methodSym.setInfo(mInfo) - instanceDefs.enter(methodSym); - clrTypes.constructors(methodSym) = method - } - - private def parseClass(typ: MSILType) { - - { - val t4c = clrTypes.types.get(clazz) - assert(t4c == None || t4c == Some(typ)) - } - clrTypes.types(clazz) = typ - - { - val c4t = clrTypes.sym2type.get(typ) - assert(c4t == None || c4t == Some(clazz)) - } - clrTypes.sym2type(typ) = clazz - - if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) { - val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false); - assert (attrs.length == 1, attrs.length); - val a = attrs(0).asInstanceOf[MSILAttribute]; - assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR); - val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]] - unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName); - val mClass = clrTypes.getType(typ.FullName + "$"); - if (mClass != null) { - clrTypes.types(statics) = mClass; - val moduleInstance = mClass.GetField("MODULE$"); - assert (moduleInstance != null, mClass); - clrTypes.fields(statics) = moduleInstance; - } - return - } - val flags = translateAttributes(typ) - - var clazzBoxed : Symbol = NoSymbol - var clazzMgdPtr : Symbol = NoSymbol - - val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum") - - if(canBeTakenAddressOf) { - clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed")) - clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr")) - clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr - /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed, - before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */ - val typMgdPtr = MSILType.mkByRef(typ) - clrTypes.types(clazzMgdPtr) = typMgdPtr - clrTypes.sym2type(typMgdPtr) = clazzMgdPtr - /* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance, - because there's no metadata-level representation for a "boxed valuetype" */ - val instanceDefsMgdPtr = newScope - val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr) - clazzMgdPtr.setFlag(flags) - clazzMgdPtr.setInfo(classInfoMgdPtr) - } - -/* START CLR generics (snippet 1) */ - // first pass - for (tvarCILDef <- typ.getSortedTVars() ) { - val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) - val tpsym = clazz.newTypeParameter(tpname) - classTParams.put(tvarCILDef.Number, tpsym) - newTParams += tpsym - // TODO wouldn't the following also be needed later, i.e. during getCLRType - tpsym.setInfo(definitions.AnyClass.tpe) - } - // second pass - for (tvarCILDef <- typ.getSortedTVars() ) { - val tpsym = classTParams(tvarCILDef.Number) - tpsym.setInfo(sig2typeBounds(tvarCILDef)) // we never skip bounds unlike in forJVM - } -/* END CLR generics (snippet 1) */ - val ownTypeParams = newTParams.toList -/* START CLR generics (snippet 2) */ - if (!ownTypeParams.isEmpty) { - clazz.setInfo(new TypeParamsType(ownTypeParams)) - if(typ.IsValueType && !typ.IsEnum) { - clazzBoxed.setInfo(new TypeParamsType(ownTypeParams)) - } - } -/* END CLR generics (snippet 2) */ - instanceDefs = newScope - staticDefs = newScope - - val classInfoAsInMetadata = { - val ifaces: Array[MSILType] = typ.getInterfaces() - val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType()) - else if (typ.IsInterface()) definitions.ObjectClass.tpe - else definitions.AnyClass.tpe; // this branch activates for System.Object only. - // parents (i.e., base type and interfaces) - val parents = new scala.collection.mutable.ListBuffer[Type]() - parents += superType - for (iface <- ifaces) { - parents += getCLRType(iface) // here the variance doesn't matter - } - // methods, properties, events, fields are entered in a moment - if (canBeTakenAddressOf) { - val instanceDefsBoxed = newScope - ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed) - } else - ClassInfoType(parents.toList, instanceDefs, clazz) - } - - val staticInfo = ClassInfoType(List(), staticDefs, statics) - - clazz.setFlag(flags) - - if (canBeTakenAddressOf) { - clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) - clazzBoxed.setFlag(flags) - val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) - clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType - else GenPolyType(ownTypeParams, rawValueInfoType) ) - } else { - clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) - } - - // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params - statics.setFlag(Flags.JAVA) - statics.setInfo(staticInfo) - staticModule.setFlag(Flags.JAVA) - staticModule.setInfo(statics.tpe) - - - if (canBeTakenAddressOf) { - // implicit conversions are owned by staticModule.moduleClass - createViewFromTo("2Boxed", clazz.tpe, clazzBoxed.tpe, addToboxMethodMap = true, isAddressOf = false) - // createViewFromTo("2Object", clazz.tpe, definitions.ObjectClass.tpe, addToboxMethodMap = true, isAddressOf = false) - createViewFromTo("2MgdPtr", clazz.tpe, clazzMgdPtr.tpe, addToboxMethodMap = false, isAddressOf = true) - // a return can't have type managed-pointer, thus a dereference-conversion is not needed - // similarly, a method can't declare as return type "boxed valuetype" - if (!typ.IsEnum) { - // a synthetic default constructor for raw-type allows `new X' syntax - createDefaultConstructor(typ) - } - } - - // import nested types - for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem) - || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) - { - val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) - val nclazz = statics.newClass(ntype.Name.toTypeName) - val nmodule = statics.newModule(ntype.Name) - nclazz.setInfo(loader) - nmodule.setInfo(loader) - staticDefs.enter(nclazz) - staticDefs.enter(nmodule) - - assert(nclazz.companionModule == nmodule, nmodule) - assert(nmodule.companionClass == nclazz, nclazz) - } - - val fields = typ.getFields() - for (field <- fields - if !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly) - if (getCLRType(field.FieldType) != null) - ) { - assert (!field.FieldType.IsPointer && !field.FieldType.IsByRef, "CLR requirement") - val flags = translateAttributes(field); - val name = newTermName(field.Name); - val fieldType = - if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType))) - ConstantType(getConstant(getCLRType(field.FieldType), field.getValue)) - else - getCLRType(field.FieldType) - val owner = if (field.IsStatic()) statics else clazz; - val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType); - // TODO: set private within!!! -> look at typechecker/Namers.scala - (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym); - clrTypes.fields(sym) = field; - } - - for (constr <- typ.getConstructors() if !constr.IsStatic() && !constr.IsPrivate() && - !constr.IsAssembly() && !constr.IsFamilyAndAssembly() && !constr.HasPtrParamOrRetType()) - createMethod(constr); - - // initially also contains getters and setters of properties. - val methodsSet = new mutable.HashSet[MethodInfo](); - methodsSet ++= typ.getMethods(); - - for (prop <- typ.getProperties) { - val propType: Type = getCLSType(prop.PropertyType); - if (propType != null) { - val getter: MethodInfo = prop.GetGetMethod(true); - val setter: MethodInfo = prop.GetSetMethod(true); - var gparamsLength: Int = -1; - if (!(getter == null || getter.IsPrivate || getter.IsAssembly - || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType)) - { - assert(prop.PropertyType == getter.ReturnType); - val gparams: Array[ParameterInfo] = getter.GetParameters(); - gparamsLength = gparams.length; - val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; - val flags = translateAttributes(getter); - val owner: Symbol = if (getter.IsStatic) statics else clazz; - val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) - val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic - else methodType(getter, getter.ReturnType)(methodSym) - methodSym.setInfo(mtype); - methodSym.setFlag(Flags.ACCESSOR); - (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) - clrTypes.methods(methodSym) = getter; - methodsSet -= getter; - } - if (!(setter == null || setter.IsPrivate || setter.IsAssembly - || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType)) - { - val sparams: Array[ParameterInfo] = setter.GetParameters() - if(getter != null) - assert(getter.IsStatic == setter.IsStatic); - assert(setter.ReturnType == clrTypes.VOID); - if(getter != null) - assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter); - - val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) - else nme.update; - val flags = translateAttributes(setter); - val mtype = methodType(setter, definitions.UnitClass.tpe); - val owner: Symbol = if (setter.IsStatic) statics else clazz; - val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) - methodSym.setInfo(mtype(methodSym)) - methodSym.setFlag(Flags.ACCESSOR); - (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); - clrTypes.methods(methodSym) = setter; - methodsSet -= setter; - } - } - } - -/* for (event <- typ.GetEvents) { - // adding += and -= methods to add delegates to an event. - // raising the event ist not possible from outside the class (this is so - // generally in .net world) - val adder: MethodInfo = event.GetAddMethod(); - val remover: MethodInfo = event.GetRemoveMethod(); - if (!(adder == null || adder.IsPrivate || adder.IsAssembly - || adder.IsFamilyAndAssembly)) - { - assert(adder.ReturnType == clrTypes.VOID); - assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); - val name = encode("+="); - val flags = translateAttributes(adder); - val mtype: Type = methodType(adder, adder.ReturnType); - createMethod(name, flags, mtype, adder, adder.IsStatic) - methodsSet -= adder; - } - if (!(remover == null || remover.IsPrivate || remover.IsAssembly - || remover.IsFamilyAndAssembly)) - { - assert(remover.ReturnType == clrTypes.VOID); - assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); - val name = encode("-="); - val flags = translateAttributes(remover); - val mtype: Type = methodType(remover, remover.ReturnType); - createMethod(name, flags, mtype, remover, remover.IsStatic) - methodsSet -= remover; - } - } */ - -/* Adds view amounting to syntax sugar for a CLR implicit overload. - The long-form syntax can also be supported if "methodsSet -= method" (last statement) is removed. - - /* remember, there's typ.getMethods and type.GetMethods */ - for (method <- typ.getMethods) - if(!method.HasPtrParamOrRetType && - method.IsPublic && method.IsStatic && method.IsSpecialName && - method.Name == "op_Implicit") { - // create a view: typ => method's return type - val viewRetType: Type = getCLRType(method.ReturnType) - val viewParamTypes: List[Type] = method.GetParameters().map(_.ParameterType).map(getCLSType).toList; - /* The spec says "The operator method shall be defined as a static method on either the operand or return type." - * We don't consider the declaring type for the purposes of definitions.functionType, - * instead we regard op_Implicit's argument type and return type as defining the view's signature. - */ - if (viewRetType != null && !viewParamTypes.contains(null)) { - /* The check above applies e.g. to System.Decimal that has a conversion from UInt16, a non-CLS type, whose CLS-mapping returns null */ - val funType: Type = definitions.functionType(viewParamTypes, viewRetType); - val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? - val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(viewParamTypes), funType) - val vmsym = createMethod(nme.view_, flags, viewMethodType, method, true); - methodsSet -= method; - } - } -*/ - - for (method <- methodsSet.iterator) - if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly() - && !method.HasPtrParamOrRetType) - createMethod(method); - - // Create methods and views for delegate support - if (clrTypes.isDelegateType(typ)) { - createDelegateView(typ) - createDelegateChainers(typ) - } - - // for enumerations introduce comparison and bitwise logical operations; - // the backend will recognize them and replace them with comparison or - // bitwise logical operations on the primitive underlying type - - if (typ.IsEnum) { - val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE); - val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR); - - val flags = Flags.JAVA | Flags.FINAL - for (cmpName <- ENUM_CMP_NAMES) { - val enumCmp = clazz.newMethod(NoPosition, cmpName) - val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe) - enumCmp.setFlag(flags).setInfo(enumCmpType) - instanceDefs.enter(enumCmp) - } - - for (bitLogName <- ENUM_BIT_LOG_NAMES) { - val enumBitLog = clazz.newMethod(NoPosition, bitLogName) - val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */) - enumBitLog.setFlag(flags).setInfo(enumBitLogType) - instanceDefs.enter(enumBitLog) - } - } - - } // parseClass - - private def populateMethodTParams(method: MethodBase, methodSym: MethodSymbol) : List[Symbol] = { - if(!method.IsGeneric) Nil - else { - methodTParams.clear - val newMethodTParams = new scala.collection.mutable.ListBuffer[Symbol]() - - // first pass - for (mvarCILDef <- method.getSortedMVars() ) { - val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO) - val mtpsym = methodSym.newTypeParameter(mtpname) - methodTParams.put(mvarCILDef.Number, mtpsym) - newMethodTParams += mtpsym - // TODO wouldn't the following also be needed later, i.e. during getCLRType - mtpsym.setInfo(definitions.AnyClass.tpe) - } - // second pass - for (mvarCILDef <- method.getSortedMVars() ) { - val mtpsym = methodTParams(mvarCILDef.Number) - mtpsym.setInfo(sig2typeBounds(mvarCILDef)) // we never skip bounds unlike in forJVM - } - - newMethodTParams.toList - } - } - - private def createMethod(method: MethodBase) { - - val flags = translateAttributes(method); - val owner = if (method.IsStatic()) statics else clazz; - val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags) - /* START CLR generics (snippet 3) */ - val newMethodTParams = populateMethodTParams(method, methodSym) - /* END CLR generics (snippet 3) */ - - val rettype = if (method.IsConstructor()) clazz.tpe - else getCLSType(method.asInstanceOf[MethodInfo].ReturnType); - if (rettype == null) return; - val mtype = methodType(method, rettype); - if (mtype == null) return; -/* START CLR generics (snippet 4) */ - val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) - else mtype(methodSym) -/* END CLR generics (snippet 4) */ -/* START CLR non-generics (snippet 4) - val mInfo = mtype(methodSym) - END CLR non-generics (snippet 4) */ - methodSym.setInfo(mInfo) - (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym); - if (method.IsConstructor()) - clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo] - else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo]; - } - - private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = { - val mtype = methodType(args, getCLSType(retType)) - assert(mtype != null) - createMethod(name, flags, mtype, method, statik) - } - - private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = { - val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name) - methodSym.setFlag(flags).setInfo(mtype(methodSym)) - (if (statik) staticDefs else instanceDefs).enter(methodSym) - if (method != null) - clrTypes.methods(methodSym) = method - methodSym - } - - private def createDelegateView(typ: MSILType) = { - val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo]; - val invokeRetType: Type = getCLRType(invoke.ReturnType); - val invokeParamTypes: List[Type] =invoke.GetParameters().map(_.ParameterType).map(getCLSType).toList; - val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType); - - val typClrType: Type = getCLRType(typ); - val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed - - // create the forward view: delegate => function - val delegateParamTypes: List[Type] = List(typClrType); - // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods) - val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType) - val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true); - - // create the backward view: function => delegate - val functionParamTypes: List[Type] = List(funType); - val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType) - val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true); - } - - private def createDelegateChainers(typ: MSILType) = { - val flags: Long = Flags.JAVA | Flags.FINAL - val args: Array[MSILType] = Array(typ) - - var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false); - s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false); - - s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false); - s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false); - } - - private def getName(method: MethodBase): Name = { - - def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match { - case 1 => name match { - // PartitionI.10.3.1 - case "op_Decrement" => Some(encode("--")) - case "op_Increment" => Some(encode("++")) - case "op_UnaryNegation" => Some(nme.UNARY_-) - case "op_UnaryPlus" => Some(nme.UNARY_+) - case "op_LogicalNot" => Some(nme.UNARY_!) - case "op_OnesComplement" => Some(nme.UNARY_~) - /* op_True and op_False have no operator symbol assigned, - Other methods that will have to be written in full are: - op_AddressOf & (unary) - op_PointerDereference * (unary) */ - case _ => None - } - case 2 => name match { - // PartitionI.10.3.2 - case "op_Addition" => Some(nme.ADD) - case "op_Subtraction" => Some(nme.SUB) - case "op_Multiply" => Some(nme.MUL) - case "op_Division" => Some(nme.DIV) - case "op_Modulus" => Some(nme.MOD) - case "op_ExclusiveOr" => Some(nme.XOR) - case "op_BitwiseAnd" => Some(nme.AND) - case "op_BitwiseOr" => Some(nme.OR) - case "op_LogicalAnd" => Some(nme.ZAND) - case "op_LogicalOr" => Some(nme.ZOR) - case "op_LeftShift" => Some(nme.LSL) - case "op_RightShift" => Some(nme.ASR) - case "op_Equality" => Some(nme.EQ) - case "op_GreaterThan" => Some(nme.GT) - case "op_LessThan" => Some(nme.LT) - case "op_Inequality" => Some(nme.NE) - case "op_GreaterThanOrEqual" => Some(nme.GE) - case "op_LessThanOrEqual" => Some(nme.LE) - - /* op_MemberSelection is reserved in Scala */ - - /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift , - * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */ - - /* - The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full. - - op_RightShiftAssignment >>= - op_MultiplicationAssignment *= - op_PointerToMemberSelection ->* - op_SubtractionAssignment -= - op_ExclusiveOrAssignment ^= - op_LeftShiftAssignment <<= - op_ModulusAssignment %= - op_AdditionAssignment += - op_BitwiseAndAssignment &= - op_BitwiseOrAssignment |= - op_Comma , - op_DivisionAssignment /= - */ - case _ => None - } - case _ => None - } - - if (method.IsConstructor()) return nme.CONSTRUCTOR; - val name = method.Name; - if (method.IsStatic()) { - if(method.IsSpecialName) { - val paramsArity = method.GetParameters().size - // handle operator overload, otherwise handle as any static method - val operName = operatorOverload(name, paramsArity) - if (operName.isDefined) { return operName.get; } - } - return newTermName(name); - } - val params = method.GetParameters(); - name match { - case "GetHashCode" if (params.length == 0) => nme.hashCode_; - case "ToString" if (params.length == 0) => nme.toString_; - case "Finalize" if (params.length == 0) => nme.finalize_; - case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) => - nme.equals_; - case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply; - case _ => newTermName(name); - } - } - - //########################################################################## - - private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = { - val rtype = getCLSType(rettype); - if (rtype == null) null else methodType(method, rtype); - } - - /** Return a method type for the given method. */ - private def methodType(method: MethodBase, rettype: Type): Symbol => Type = - methodType(method.GetParameters().map(_.ParameterType), rettype); - - /** Return a method type for the provided argument types and return type. */ - private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = { - def paramType(typ: MSILType): Type = - if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe // TODO a hack to compile scalalib, should be definitions.AnyRefClass.tpe - else getCLSType(typ); - val ptypes = argtypes.map(paramType).toList; - if (ptypes.contains(null)) null - else method => JavaMethodType(method.newSyntheticValueParams(ptypes), rettype); - } - - //########################################################################## - - private def getClassType(typ: MSILType): Type = { - assert(typ != null); - val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe; - //if (res.isError()) - // global.reporter.error("unknown class reference " + type.FullName); - res - } - - private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not - if (typ.IsTMVarUsage()) - /* START CLR generics (snippet 5) */ - getCLRType(typ) - /* END CLR generics (snippet 5) */ - /* START CLR non-generics (snippet 5) - null - END CLR non-generics (snippet 5) */ - else if ( /* TODO hack if UBYE, uncommented, "ambiguous reference to overloaded definition" ensues, for example for System.Math.Max(x, y) */ - typ == clrTypes.USHORT || typ == clrTypes.UINT || typ == clrTypes.ULONG - /* || typ == clrTypes.UBYTE */ - || typ.IsNotPublic() || typ.IsNestedPrivate() - || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem() - || typ.IsPointer() - || (typ.IsArray() && getCLRType(typ.GetElementType()) == null) /* TODO hack: getCLR instead of getCLS */ - || (typ.IsByRef() && !typ.GetElementType().CanBeTakenAddressOf())) - null - else - getCLRType(typ) - } - - private def getCLRTypeIfPrimitiveNullOtherwise(typ: MSILType): Type = - if (typ == clrTypes.OBJECT) - definitions.ObjectClass.tpe; - else if (typ == clrTypes.VALUE_TYPE) - definitions.AnyValClass.tpe - else if (typ == clrTypes.STRING) - definitions.StringClass.tpe; - else if (typ == clrTypes.VOID) - definitions.UnitClass.tpe - else if (typ == clrTypes.BOOLEAN) - definitions.BooleanClass.tpe - else if (typ == clrTypes.CHAR) - definitions.CharClass.tpe - else if ((typ == clrTypes.BYTE) || (typ == clrTypes.UBYTE)) // TODO U... is a hack to compile scalalib - definitions.ByteClass.tpe - else if ((typ == clrTypes.SHORT) || (typ == clrTypes.SHORT)) // TODO U... is a hack to compile scalalib - definitions.ShortClass.tpe - else if ((typ == clrTypes.INT) || (typ == clrTypes.UINT)) // TODO U... is a hack to compile scalalib - definitions.IntClass.tpe - else if ((typ == clrTypes.LONG) || (typ == clrTypes.LONG)) // TODO U... is a hack to compile scalalib - definitions.LongClass.tpe - else if (typ == clrTypes.FLOAT) - definitions.FloatClass.tpe - else if (typ == clrTypes.DOUBLE) - definitions.DoubleClass.tpe - else null - - - private def getCLRType(tMSIL: MSILType): Type = { - var res = getCLRTypeIfPrimitiveNullOtherwise(tMSIL) - if (res != null) res - else if (tMSIL.isInstanceOf[ConstructedType]) { - val ct = tMSIL.asInstanceOf[ConstructedType] - /* START CLR generics (snippet 6) */ - val cttpArgs = ct.typeArgs.map(tmsil => getCLRType(tmsil)).toList - appliedType(getCLRType(ct.instantiatedType), cttpArgs) - /* END CLR generics (snippet 6) */ - /* START CLR non-generics (snippet 6) - getCLRType(ct.instantiatedType) - END CLR non-generics (snippet 6) */ - } else if (tMSIL.isInstanceOf[TMVarUsage]) { - /* START CLR generics (snippet 7) */ - val tVarUsage = tMSIL.asInstanceOf[TMVarUsage] - val tVarNumber = tVarUsage.Number - if (tVarUsage.isTVar) classTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst - else methodTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst - /* END CLR generics (snippet 7) */ - /* START CLR non-generics (snippet 7) - null // definitions.ObjectClass.tpe - END CLR non-generics (snippet 7) */ - } else if (tMSIL.IsArray()) { - var elemtp = getCLRType(tMSIL.GetElementType()) - // cut&pasted from ClassfileParser - // make unbounded Array[T] where T is a type variable into Array[T with Object] - // (this is necessary because such arrays have a representation which is incompatible - // with arrays of primitive types). - // TODO does that incompatibility also apply to .NET? - if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) - elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe)) - appliedType(definitions.ArrayClass.tpe, List(elemtp)) - } else { - res = clrTypes.sym2type.get(tMSIL) match { - case Some(sym) => sym.tpe - case None => if (tMSIL.IsByRef && tMSIL.GetElementType.IsValueType) { - val addressed = getCLRType(tMSIL.GetElementType) - val clasym = addressed.typeSymbolDirect // TODO should be .typeSymbol? - clasym.info.load(clasym) - val secondAttempt = clrTypes.sym2type.get(tMSIL) - secondAttempt match { case Some(sym) => sym.tpe - case None => null - } - } else getClassType(tMSIL) - } - if (res == null) - null // TODO new RuntimeException() - else res - } - } - - // the values are Java-Box-Classes (e.g. Integer, Boolean, Character) - // java.lang.Number to get the value (if a number, not for boolean, character) - // see ch.epfl.lamp.compiler.msil.util.PEStream.java - def getConstant(constType: Type, value: Object): Constant = { - val typeClass = constType.typeSymbol - if (typeClass == definitions.BooleanClass) - Constant(value.asInstanceOf[java.lang.Boolean].booleanValue) - else if (typeClass == definitions.ByteClass) - Constant(value.asInstanceOf[java.lang.Number].byteValue) - else if (typeClass == definitions.ShortClass) - Constant(value.asInstanceOf[java.lang.Number].shortValue) - else if (typeClass == definitions.CharClass) - Constant(value.asInstanceOf[java.lang.Character].charValue) - else if (typeClass == definitions.IntClass) - Constant(value.asInstanceOf[java.lang.Number].intValue) - else if (typeClass == definitions.LongClass) - Constant(value.asInstanceOf[java.lang.Number].longValue) - else if (typeClass == definitions.FloatClass) - Constant(value.asInstanceOf[java.lang.Number].floatValue) - else if (typeClass == definitions.DoubleClass) - Constant(value.asInstanceOf[java.lang.Number].doubleValue) - else if (typeClass == definitions.StringClass) - Constant(value.asInstanceOf[java.lang.String]) - else - abort("illegal value: " + value + ", class-symbol: " + typeClass) - } - - def isDefinedAtgetConstant(constType: Type): Boolean = { - val typeClass = constType.typeSymbol - if ( (typeClass == definitions.BooleanClass) - || (typeClass == definitions.ByteClass) - || (typeClass == definitions.ShortClass) - || (typeClass == definitions.CharClass) - || (typeClass == definitions.IntClass) - || (typeClass == definitions.LongClass) - || (typeClass == definitions.FloatClass) - || (typeClass == definitions.DoubleClass) - || (typeClass == definitions.StringClass) - ) - true - else - false - } - - private def translateAttributes(typ: MSILType): Long = { - var flags: Long = Flags.JAVA; - if (typ.IsNotPublic() || typ.IsNestedPrivate() - || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()) - flags = flags | Flags.PRIVATE; - else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem()) - flags = flags | Flags.PROTECTED; - if (typ.IsAbstract()) - flags = flags | Flags.ABSTRACT; - if (typ.IsSealed()) - flags = flags | Flags.FINAL; - if (typ.IsInterface()) - flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT; - - flags - } - - private def translateAttributes(field: FieldInfo): Long = { - var flags: Long = Flags.JAVA; - if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly()) - flags = flags | Flags.PRIVATE; - else if (field.IsFamily() || field.IsFamilyOrAssembly()) - flags = flags | Flags.PROTECTED; - if (field.IsInitOnly() || field.IsLiteral()) - flags = flags | Flags.FINAL; - else - flags = flags | Flags.MUTABLE; - if (field.IsStatic) - flags = flags | Flags.STATIC - - flags - } - - private def translateAttributes(method: MethodBase): Long = { - var flags: Long = Flags.JAVA; - if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly()) - flags = flags | Flags.PRIVATE; - else if (method.IsFamily() || method.IsFamilyOrAssembly()) - flags = flags | Flags.PROTECTED; - if (method.IsAbstract()) - flags = flags | Flags.DEFERRED; - if (method.IsStatic) - flags = flags | Flags.STATIC - - flags - } -} +// /* NSC -- new scala compiler +// * Copyright 2004-2011 LAMP/EPFL +// */ +// +// package scala.tools.nsc +// package symtab +// package clr +// +// import java.io.IOException +// import io.MsilFile +// import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _} +// import scala.collection.{ mutable, immutable } +// import scala.reflect.internal.pickling.UnPickler +// import ch.epfl.lamp.compiler.msil.Type.TMVarUsage +// +// /** +// * @author Nikolay Mihaylov +// */ +// abstract class TypeParser { +// +// val global: Global +// +// import global._ +// import loaders.clrTypes +// +// //########################################################################## +// +// private var clazz: Symbol = _ +// private var instanceDefs: Scope = _ // was members +// private var staticModule: Symbol = _ // was staticsClass +// private var staticDefs: Scope = _ // was statics +// +// protected def statics: Symbol = staticModule.moduleClass +// +// protected var busy: Boolean = false // lock to detect recursive reads +// +// private implicit def stringToTermName(s: String): TermName = newTermName(s) +// +// private object unpickler extends UnPickler { +// val global: TypeParser.this.global.type = TypeParser.this.global +// } +// +// def parse(typ: MSILType, root: Symbol) { +// +// def handleError(e: Throwable) = { +// if (settings.debug.value) e.printStackTrace() //debug +// throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")") +// } +// assert(!busy) +// busy = true +// +// if (root.isModule) { +// this.clazz = root.companionClass +// this.staticModule = root +// } else { +// this.clazz = root +// this.staticModule = root.companionModule +// } +// try { +// parseClass(typ) +// } catch { +// case e: FatalError => handleError(e) +// case e: RuntimeException => handleError(e) +// } +// busy = false +// } +// +// class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { +// override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } +// } +// +// /* the names `classTParams` and `newTParams` stem from the forJVM version (ClassfileParser.sigToType()) +// * but there are differences that should be kept in mind. +// * forMSIL, a nested class knows nothing about any type-params in the nesting class, +// * therefore newTParams is redundant (other than for recording lexical order), +// * it always contains the same elements as classTParams.value */ +// val classTParams = scala.collection.mutable.Map[Int,Symbol]() // TODO should this be a stack? (i.e., is it possible for >1 invocation to getCLRType on the same TypeParser instance be active ) +// val newTParams = new scala.collection.mutable.ListBuffer[Symbol]() +// val methodTParams = scala.collection.mutable.Map[Int,Symbol]() +// +// private def sig2typeBounds(tvarCILDef: GenericParamAndConstraints): Type = { +// val ts = new scala.collection.mutable.ListBuffer[Type] +// for (cnstrnt <- tvarCILDef.Constraints) { +// ts += getCLRType(cnstrnt) // TODO we're definitely not at or after erasure, no need to call objToAny, right? +// } +// TypeBounds.upper(intersectionType(ts.toList, clazz)) +// // TODO variance??? +// } +// +// private def createViewFromTo(viewSuffix : String, fromTpe : Type, toTpe : Type, +// addToboxMethodMap : Boolean, isAddressOf : Boolean) : Symbol = { +// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? +// val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(List(fromTpe)), toTpe) +// val vmsym = createMethod(nme.view_ + viewSuffix, flags, viewMethodType, null, true); +// // !!! this used to mutate a mutable map in definitions, but that map became +// // immutable and this kept "working" with a no-op. So now it's commented out +// // since I retired the deprecated code which allowed for that bug. +// // +// // if (addToboxMethodMap) definitions.boxMethod(clazz) = vmsym +// +// if (isAddressOf) clrTypes.addressOfViews += vmsym +// vmsym +// } +// +// private def createDefaultConstructor(typ: MSILType) { +// val attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName // TODO instance +// val declType= typ +// val method = new ConstructorInfo(declType, attrs, Array[MSILType]()) +// val flags = Flags.JAVA +// val owner = clazz +// val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags) +// val rettype = clazz.tpe +// val mtype = methodType(Array[MSILType](), rettype); +// val mInfo = mtype(methodSym) +// methodSym.setInfo(mInfo) +// instanceDefs.enter(methodSym); +// clrTypes.constructors(methodSym) = method +// } +// +// private def parseClass(typ: MSILType) { +// +// { +// val t4c = clrTypes.types.get(clazz) +// assert(t4c == None || t4c == Some(typ)) +// } +// clrTypes.types(clazz) = typ +// +// { +// val c4t = clrTypes.sym2type.get(typ) +// assert(c4t == None || c4t == Some(clazz)) +// } +// clrTypes.sym2type(typ) = clazz +// +// if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) { +// val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false); +// assert (attrs.length == 1, attrs.length); +// val a = attrs(0).asInstanceOf[MSILAttribute]; +// assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR); +// val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]] +// unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName); +// val mClass = clrTypes.getType(typ.FullName + "$"); +// if (mClass != null) { +// clrTypes.types(statics) = mClass; +// val moduleInstance = mClass.GetField("MODULE$"); +// assert (moduleInstance != null, mClass); +// clrTypes.fields(statics) = moduleInstance; +// } +// return +// } +// val flags = translateAttributes(typ) +// +// var clazzBoxed : Symbol = NoSymbol +// var clazzMgdPtr : Symbol = NoSymbol +// +// val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum") +// +// if(canBeTakenAddressOf) { +// clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed")) +// clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr")) +// clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr +// /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed, +// before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */ +// val typMgdPtr = MSILType.mkByRef(typ) +// clrTypes.types(clazzMgdPtr) = typMgdPtr +// clrTypes.sym2type(typMgdPtr) = clazzMgdPtr +// /* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance, +// because there's no metadata-level representation for a "boxed valuetype" */ +// val instanceDefsMgdPtr = newScope +// val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr) +// clazzMgdPtr.setFlag(flags) +// clazzMgdPtr.setInfo(classInfoMgdPtr) +// } +// +// /* START CLR generics (snippet 1) */ +// // first pass +// for (tvarCILDef <- typ.getSortedTVars() ) { +// val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) +// val tpsym = clazz.newTypeParameter(tpname) +// classTParams.put(tvarCILDef.Number, tpsym) +// newTParams += tpsym +// // TODO wouldn't the following also be needed later, i.e. during getCLRType +// tpsym.setInfo(definitions.AnyClass.tpe) +// } +// // second pass +// for (tvarCILDef <- typ.getSortedTVars() ) { +// val tpsym = classTParams(tvarCILDef.Number) +// tpsym.setInfo(sig2typeBounds(tvarCILDef)) // we never skip bounds unlike in forJVM +// } +// /* END CLR generics (snippet 1) */ +// val ownTypeParams = newTParams.toList +// /* START CLR generics (snippet 2) */ +// if (!ownTypeParams.isEmpty) { +// clazz.setInfo(new TypeParamsType(ownTypeParams)) +// if(typ.IsValueType && !typ.IsEnum) { +// clazzBoxed.setInfo(new TypeParamsType(ownTypeParams)) +// } +// } +// /* END CLR generics (snippet 2) */ +// instanceDefs = newScope +// staticDefs = newScope +// +// val classInfoAsInMetadata = { +// val ifaces: Array[MSILType] = typ.getInterfaces() +// val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType()) +// else if (typ.IsInterface()) definitions.ObjectClass.tpe +// else definitions.AnyClass.tpe; // this branch activates for System.Object only. +// // parents (i.e., base type and interfaces) +// val parents = new scala.collection.mutable.ListBuffer[Type]() +// parents += superType +// for (iface <- ifaces) { +// parents += getCLRType(iface) // here the variance doesn't matter +// } +// // methods, properties, events, fields are entered in a moment +// if (canBeTakenAddressOf) { +// val instanceDefsBoxed = newScope +// ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed) +// } else +// ClassInfoType(parents.toList, instanceDefs, clazz) +// } +// +// val staticInfo = ClassInfoType(List(), staticDefs, statics) +// +// clazz.setFlag(flags) +// +// if (canBeTakenAddressOf) { +// clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata +// else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) +// clazzBoxed.setFlag(flags) +// val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) +// clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType +// else GenPolyType(ownTypeParams, rawValueInfoType) ) +// } else { +// clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata +// else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) +// } +// +// // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params +// statics.setFlag(Flags.JAVA) +// statics.setInfo(staticInfo) +// staticModule.setFlag(Flags.JAVA) +// staticModule.setInfo(statics.tpe) +// +// +// if (canBeTakenAddressOf) { +// // implicit conversions are owned by staticModule.moduleClass +// createViewFromTo("2Boxed", clazz.tpe, clazzBoxed.tpe, addToboxMethodMap = true, isAddressOf = false) +// // createViewFromTo("2Object", clazz.tpe, definitions.ObjectClass.tpe, addToboxMethodMap = true, isAddressOf = false) +// createViewFromTo("2MgdPtr", clazz.tpe, clazzMgdPtr.tpe, addToboxMethodMap = false, isAddressOf = true) +// // a return can't have type managed-pointer, thus a dereference-conversion is not needed +// // similarly, a method can't declare as return type "boxed valuetype" +// if (!typ.IsEnum) { +// // a synthetic default constructor for raw-type allows `new X' syntax +// createDefaultConstructor(typ) +// } +// } +// +// // import nested types +// for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem) +// || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) +// { +// val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) +// val nclazz = statics.newClass(ntype.Name.toTypeName) +// val nmodule = statics.newModule(ntype.Name) +// nclazz.setInfo(loader) +// nmodule.setInfo(loader) +// staticDefs.enter(nclazz) +// staticDefs.enter(nmodule) +// +// assert(nclazz.companionModule == nmodule, nmodule) +// assert(nmodule.companionClass == nclazz, nclazz) +// } +// +// val fields = typ.getFields() +// for (field <- fields +// if !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly) +// if (getCLRType(field.FieldType) != null) +// ) { +// assert (!field.FieldType.IsPointer && !field.FieldType.IsByRef, "CLR requirement") +// val flags = translateAttributes(field); +// val name = newTermName(field.Name); +// val fieldType = +// if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType))) +// ConstantType(getConstant(getCLRType(field.FieldType), field.getValue)) +// else +// getCLRType(field.FieldType) +// val owner = if (field.IsStatic()) statics else clazz; +// val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType); +// // TODO: set private within!!! -> look at typechecker/Namers.scala +// (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym); +// clrTypes.fields(sym) = field; +// } +// +// for (constr <- typ.getConstructors() if !constr.IsStatic() && !constr.IsPrivate() && +// !constr.IsAssembly() && !constr.IsFamilyAndAssembly() && !constr.HasPtrParamOrRetType()) +// createMethod(constr); +// +// // initially also contains getters and setters of properties. +// val methodsSet = new mutable.HashSet[MethodInfo](); +// methodsSet ++= typ.getMethods(); +// +// for (prop <- typ.getProperties) { +// val propType: Type = getCLSType(prop.PropertyType); +// if (propType != null) { +// val getter: MethodInfo = prop.GetGetMethod(true); +// val setter: MethodInfo = prop.GetSetMethod(true); +// var gparamsLength: Int = -1; +// if (!(getter == null || getter.IsPrivate || getter.IsAssembly +// || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType)) +// { +// assert(prop.PropertyType == getter.ReturnType); +// val gparams: Array[ParameterInfo] = getter.GetParameters(); +// gparamsLength = gparams.length; +// val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; +// val flags = translateAttributes(getter); +// val owner: Symbol = if (getter.IsStatic) statics else clazz; +// val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) +// val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic +// else methodType(getter, getter.ReturnType)(methodSym) +// methodSym.setInfo(mtype); +// methodSym.setFlag(Flags.ACCESSOR); +// (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) +// clrTypes.methods(methodSym) = getter; +// methodsSet -= getter; +// } +// if (!(setter == null || setter.IsPrivate || setter.IsAssembly +// || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType)) +// { +// val sparams: Array[ParameterInfo] = setter.GetParameters() +// if(getter != null) +// assert(getter.IsStatic == setter.IsStatic); +// assert(setter.ReturnType == clrTypes.VOID); +// if(getter != null) +// assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter); +// +// val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) +// else nme.update; +// val flags = translateAttributes(setter); +// val mtype = methodType(setter, definitions.UnitClass.tpe); +// val owner: Symbol = if (setter.IsStatic) statics else clazz; +// val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) +// methodSym.setInfo(mtype(methodSym)) +// methodSym.setFlag(Flags.ACCESSOR); +// (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); +// clrTypes.methods(methodSym) = setter; +// methodsSet -= setter; +// } +// } +// } +// +// /* for (event <- typ.GetEvents) { +// // adding += and -= methods to add delegates to an event. +// // raising the event ist not possible from outside the class (this is so +// // generally in .net world) +// val adder: MethodInfo = event.GetAddMethod(); +// val remover: MethodInfo = event.GetRemoveMethod(); +// if (!(adder == null || adder.IsPrivate || adder.IsAssembly +// || adder.IsFamilyAndAssembly)) +// { +// assert(adder.ReturnType == clrTypes.VOID); +// assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); +// val name = encode("+="); +// val flags = translateAttributes(adder); +// val mtype: Type = methodType(adder, adder.ReturnType); +// createMethod(name, flags, mtype, adder, adder.IsStatic) +// methodsSet -= adder; +// } +// if (!(remover == null || remover.IsPrivate || remover.IsAssembly +// || remover.IsFamilyAndAssembly)) +// { +// assert(remover.ReturnType == clrTypes.VOID); +// assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); +// val name = encode("-="); +// val flags = translateAttributes(remover); +// val mtype: Type = methodType(remover, remover.ReturnType); +// createMethod(name, flags, mtype, remover, remover.IsStatic) +// methodsSet -= remover; +// } +// } */ +// +// /* Adds view amounting to syntax sugar for a CLR implicit overload. +// The long-form syntax can also be supported if "methodsSet -= method" (last statement) is removed. +// +// /* remember, there's typ.getMethods and type.GetMethods */ +// for (method <- typ.getMethods) +// if(!method.HasPtrParamOrRetType && +// method.IsPublic && method.IsStatic && method.IsSpecialName && +// method.Name == "op_Implicit") { +// // create a view: typ => method's return type +// val viewRetType: Type = getCLRType(method.ReturnType) +// val viewParamTypes: List[Type] = method.GetParameters().map(_.ParameterType).map(getCLSType).toList; +// /* The spec says "The operator method shall be defined as a static method on either the operand or return type." +// * We don't consider the declaring type for the purposes of definitions.functionType, +// * instead we regard op_Implicit's argument type and return type as defining the view's signature. +// */ +// if (viewRetType != null && !viewParamTypes.contains(null)) { +// /* The check above applies e.g. to System.Decimal that has a conversion from UInt16, a non-CLS type, whose CLS-mapping returns null */ +// val funType: Type = definitions.functionType(viewParamTypes, viewRetType); +// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? +// val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(viewParamTypes), funType) +// val vmsym = createMethod(nme.view_, flags, viewMethodType, method, true); +// methodsSet -= method; +// } +// } +// */ +// +// for (method <- methodsSet.iterator) +// if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly() +// && !method.HasPtrParamOrRetType) +// createMethod(method); +// +// // Create methods and views for delegate support +// if (clrTypes.isDelegateType(typ)) { +// createDelegateView(typ) +// createDelegateChainers(typ) +// } +// +// // for enumerations introduce comparison and bitwise logical operations; +// // the backend will recognize them and replace them with comparison or +// // bitwise logical operations on the primitive underlying type +// +// if (typ.IsEnum) { +// val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE); +// val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR); +// +// val flags = Flags.JAVA | Flags.FINAL +// for (cmpName <- ENUM_CMP_NAMES) { +// val enumCmp = clazz.newMethod(NoPosition, cmpName) +// val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe) +// enumCmp.setFlag(flags).setInfo(enumCmpType) +// instanceDefs.enter(enumCmp) +// } +// +// for (bitLogName <- ENUM_BIT_LOG_NAMES) { +// val enumBitLog = clazz.newMethod(NoPosition, bitLogName) +// val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */) +// enumBitLog.setFlag(flags).setInfo(enumBitLogType) +// instanceDefs.enter(enumBitLog) +// } +// } +// +// } // parseClass +// +// private def populateMethodTParams(method: MethodBase, methodSym: MethodSymbol) : List[Symbol] = { +// if(!method.IsGeneric) Nil +// else { +// methodTParams.clear +// val newMethodTParams = new scala.collection.mutable.ListBuffer[Symbol]() +// +// // first pass +// for (mvarCILDef <- method.getSortedMVars() ) { +// val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO) +// val mtpsym = methodSym.newTypeParameter(mtpname) +// methodTParams.put(mvarCILDef.Number, mtpsym) +// newMethodTParams += mtpsym +// // TODO wouldn't the following also be needed later, i.e. during getCLRType +// mtpsym.setInfo(definitions.AnyClass.tpe) +// } +// // second pass +// for (mvarCILDef <- method.getSortedMVars() ) { +// val mtpsym = methodTParams(mvarCILDef.Number) +// mtpsym.setInfo(sig2typeBounds(mvarCILDef)) // we never skip bounds unlike in forJVM +// } +// +// newMethodTParams.toList +// } +// } +// +// private def createMethod(method: MethodBase) { +// +// val flags = translateAttributes(method); +// val owner = if (method.IsStatic()) statics else clazz; +// val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags) +// /* START CLR generics (snippet 3) */ +// val newMethodTParams = populateMethodTParams(method, methodSym) +// /* END CLR generics (snippet 3) */ +// +// val rettype = if (method.IsConstructor()) clazz.tpe +// else getCLSType(method.asInstanceOf[MethodInfo].ReturnType); +// if (rettype == null) return; +// val mtype = methodType(method, rettype); +// if (mtype == null) return; +// /* START CLR generics (snippet 4) */ +// val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) +// else mtype(methodSym) +// /* END CLR generics (snippet 4) */ +// /* START CLR non-generics (snippet 4) +// val mInfo = mtype(methodSym) +// END CLR non-generics (snippet 4) */ +// methodSym.setInfo(mInfo) +// (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym); +// if (method.IsConstructor()) +// clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo] +// else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo]; +// } +// +// private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = { +// val mtype = methodType(args, getCLSType(retType)) +// assert(mtype != null) +// createMethod(name, flags, mtype, method, statik) +// } +// +// private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = { +// val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name) +// methodSym.setFlag(flags).setInfo(mtype(methodSym)) +// (if (statik) staticDefs else instanceDefs).enter(methodSym) +// if (method != null) +// clrTypes.methods(methodSym) = method +// methodSym +// } +// +// private def createDelegateView(typ: MSILType) = { +// val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo]; +// val invokeRetType: Type = getCLRType(invoke.ReturnType); +// val invokeParamTypes: List[Type] =invoke.GetParameters().map(_.ParameterType).map(getCLSType).toList; +// val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType); +// +// val typClrType: Type = getCLRType(typ); +// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed +// +// // create the forward view: delegate => function +// val delegateParamTypes: List[Type] = List(typClrType); +// // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods) +// val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType) +// val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true); +// +// // create the backward view: function => delegate +// val functionParamTypes: List[Type] = List(funType); +// val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType) +// val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true); +// } +// +// private def createDelegateChainers(typ: MSILType) = { +// val flags: Long = Flags.JAVA | Flags.FINAL +// val args: Array[MSILType] = Array(typ) +// +// var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false); +// s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false); +// +// s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false); +// s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false); +// } +// +// private def getName(method: MethodBase): Name = { +// +// def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match { +// case 1 => name match { +// // PartitionI.10.3.1 +// case "op_Decrement" => Some(encode("--")) +// case "op_Increment" => Some(encode("++")) +// case "op_UnaryNegation" => Some(nme.UNARY_-) +// case "op_UnaryPlus" => Some(nme.UNARY_+) +// case "op_LogicalNot" => Some(nme.UNARY_!) +// case "op_OnesComplement" => Some(nme.UNARY_~) +// /* op_True and op_False have no operator symbol assigned, +// Other methods that will have to be written in full are: +// op_AddressOf & (unary) +// op_PointerDereference * (unary) */ +// case _ => None +// } +// case 2 => name match { +// // PartitionI.10.3.2 +// case "op_Addition" => Some(nme.ADD) +// case "op_Subtraction" => Some(nme.SUB) +// case "op_Multiply" => Some(nme.MUL) +// case "op_Division" => Some(nme.DIV) +// case "op_Modulus" => Some(nme.MOD) +// case "op_ExclusiveOr" => Some(nme.XOR) +// case "op_BitwiseAnd" => Some(nme.AND) +// case "op_BitwiseOr" => Some(nme.OR) +// case "op_LogicalAnd" => Some(nme.ZAND) +// case "op_LogicalOr" => Some(nme.ZOR) +// case "op_LeftShift" => Some(nme.LSL) +// case "op_RightShift" => Some(nme.ASR) +// case "op_Equality" => Some(nme.EQ) +// case "op_GreaterThan" => Some(nme.GT) +// case "op_LessThan" => Some(nme.LT) +// case "op_Inequality" => Some(nme.NE) +// case "op_GreaterThanOrEqual" => Some(nme.GE) +// case "op_LessThanOrEqual" => Some(nme.LE) +// +// /* op_MemberSelection is reserved in Scala */ +// +// /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift , +// * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */ +// +// /* +// The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full. +// +// op_RightShiftAssignment >>= +// op_MultiplicationAssignment *= +// op_PointerToMemberSelection ->* +// op_SubtractionAssignment -= +// op_ExclusiveOrAssignment ^= +// op_LeftShiftAssignment <<= +// op_ModulusAssignment %= +// op_AdditionAssignment += +// op_BitwiseAndAssignment &= +// op_BitwiseOrAssignment |= +// op_Comma , +// op_DivisionAssignment /= +// */ +// case _ => None +// } +// case _ => None +// } +// +// if (method.IsConstructor()) return nme.CONSTRUCTOR; +// val name = method.Name; +// if (method.IsStatic()) { +// if(method.IsSpecialName) { +// val paramsArity = method.GetParameters().size +// // handle operator overload, otherwise handle as any static method +// val operName = operatorOverload(name, paramsArity) +// if (operName.isDefined) { return operName.get; } +// } +// return newTermName(name); +// } +// val params = method.GetParameters(); +// name match { +// case "GetHashCode" if (params.length == 0) => nme.hashCode_; +// case "ToString" if (params.length == 0) => nme.toString_; +// case "Finalize" if (params.length == 0) => nme.finalize_; +// case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) => +// nme.equals_; +// case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply; +// case _ => newTermName(name); +// } +// } +// +// //########################################################################## +// +// private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = { +// val rtype = getCLSType(rettype); +// if (rtype == null) null else methodType(method, rtype); +// } +// +// /** Return a method type for the given method. */ +// private def methodType(method: MethodBase, rettype: Type): Symbol => Type = +// methodType(method.GetParameters().map(_.ParameterType), rettype); +// +// /** Return a method type for the provided argument types and return type. */ +// private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = { +// def paramType(typ: MSILType): Type = +// if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe // TODO a hack to compile scalalib, should be definitions.AnyRefClass.tpe +// else getCLSType(typ); +// val ptypes = argtypes.map(paramType).toList; +// if (ptypes.contains(null)) null +// else method => JavaMethodType(method.newSyntheticValueParams(ptypes), rettype); +// } +// +// //########################################################################## +// +// private def getClassType(typ: MSILType): Type = { +// assert(typ != null); +// val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe; +// //if (res.isError()) +// // global.reporter.error("unknown class reference " + type.FullName); +// res +// } +// +// private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not +// if (typ.IsTMVarUsage()) +// /* START CLR generics (snippet 5) */ +// getCLRType(typ) +// /* END CLR generics (snippet 5) */ +// /* START CLR non-generics (snippet 5) +// null +// END CLR non-generics (snippet 5) */ +// else if ( /* TODO hack if UBYE, uncommented, "ambiguous reference to overloaded definition" ensues, for example for System.Math.Max(x, y) */ +// typ == clrTypes.USHORT || typ == clrTypes.UINT || typ == clrTypes.ULONG +// /* || typ == clrTypes.UBYTE */ +// || typ.IsNotPublic() || typ.IsNestedPrivate() +// || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem() +// || typ.IsPointer() +// || (typ.IsArray() && getCLRType(typ.GetElementType()) == null) /* TODO hack: getCLR instead of getCLS */ +// || (typ.IsByRef() && !typ.GetElementType().CanBeTakenAddressOf())) +// null +// else +// getCLRType(typ) +// } +// +// private def getCLRTypeIfPrimitiveNullOtherwise(typ: MSILType): Type = +// if (typ == clrTypes.OBJECT) +// definitions.ObjectClass.tpe; +// else if (typ == clrTypes.VALUE_TYPE) +// definitions.AnyValClass.tpe +// else if (typ == clrTypes.STRING) +// definitions.StringClass.tpe; +// else if (typ == clrTypes.VOID) +// definitions.UnitClass.tpe +// else if (typ == clrTypes.BOOLEAN) +// definitions.BooleanClass.tpe +// else if (typ == clrTypes.CHAR) +// definitions.CharClass.tpe +// else if ((typ == clrTypes.BYTE) || (typ == clrTypes.UBYTE)) // TODO U... is a hack to compile scalalib +// definitions.ByteClass.tpe +// else if ((typ == clrTypes.SHORT) || (typ == clrTypes.SHORT)) // TODO U... is a hack to compile scalalib +// definitions.ShortClass.tpe +// else if ((typ == clrTypes.INT) || (typ == clrTypes.UINT)) // TODO U... is a hack to compile scalalib +// definitions.IntClass.tpe +// else if ((typ == clrTypes.LONG) || (typ == clrTypes.LONG)) // TODO U... is a hack to compile scalalib +// definitions.LongClass.tpe +// else if (typ == clrTypes.FLOAT) +// definitions.FloatClass.tpe +// else if (typ == clrTypes.DOUBLE) +// definitions.DoubleClass.tpe +// else null +// +// +// private def getCLRType(tMSIL: MSILType): Type = { +// var res = getCLRTypeIfPrimitiveNullOtherwise(tMSIL) +// if (res != null) res +// else if (tMSIL.isInstanceOf[ConstructedType]) { +// val ct = tMSIL.asInstanceOf[ConstructedType] +// /* START CLR generics (snippet 6) */ +// val cttpArgs = ct.typeArgs.map(tmsil => getCLRType(tmsil)).toList +// appliedType(getCLRType(ct.instantiatedType), cttpArgs) +// /* END CLR generics (snippet 6) */ +// /* START CLR non-generics (snippet 6) +// getCLRType(ct.instantiatedType) +// END CLR non-generics (snippet 6) */ +// } else if (tMSIL.isInstanceOf[TMVarUsage]) { +// /* START CLR generics (snippet 7) */ +// val tVarUsage = tMSIL.asInstanceOf[TMVarUsage] +// val tVarNumber = tVarUsage.Number +// if (tVarUsage.isTVar) classTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst +// else methodTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst +// /* END CLR generics (snippet 7) */ +// /* START CLR non-generics (snippet 7) +// null // definitions.ObjectClass.tpe +// END CLR non-generics (snippet 7) */ +// } else if (tMSIL.IsArray()) { +// var elemtp = getCLRType(tMSIL.GetElementType()) +// // cut&pasted from ClassfileParser +// // make unbounded Array[T] where T is a type variable into Array[T with Object] +// // (this is necessary because such arrays have a representation which is incompatible +// // with arrays of primitive types). +// // TODO does that incompatibility also apply to .NET? +// if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) +// elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe)) +// appliedType(definitions.ArrayClass.tpe, List(elemtp)) +// } else { +// res = clrTypes.sym2type.get(tMSIL) match { +// case Some(sym) => sym.tpe +// case None => if (tMSIL.IsByRef && tMSIL.GetElementType.IsValueType) { +// val addressed = getCLRType(tMSIL.GetElementType) +// val clasym = addressed.typeSymbolDirect // TODO should be .typeSymbol? +// clasym.info.load(clasym) +// val secondAttempt = clrTypes.sym2type.get(tMSIL) +// secondAttempt match { case Some(sym) => sym.tpe +// case None => null +// } +// } else getClassType(tMSIL) +// } +// if (res == null) +// null // TODO new RuntimeException() +// else res +// } +// } +// +// // the values are Java-Box-Classes (e.g. Integer, Boolean, Character) +// // java.lang.Number to get the value (if a number, not for boolean, character) +// // see ch.epfl.lamp.compiler.msil.util.PEStream.java +// def getConstant(constType: Type, value: Object): Constant = { +// val typeClass = constType.typeSymbol +// if (typeClass == definitions.BooleanClass) +// Constant(value.asInstanceOf[java.lang.Boolean].booleanValue) +// else if (typeClass == definitions.ByteClass) +// Constant(value.asInstanceOf[java.lang.Number].byteValue) +// else if (typeClass == definitions.ShortClass) +// Constant(value.asInstanceOf[java.lang.Number].shortValue) +// else if (typeClass == definitions.CharClass) +// Constant(value.asInstanceOf[java.lang.Character].charValue) +// else if (typeClass == definitions.IntClass) +// Constant(value.asInstanceOf[java.lang.Number].intValue) +// else if (typeClass == definitions.LongClass) +// Constant(value.asInstanceOf[java.lang.Number].longValue) +// else if (typeClass == definitions.FloatClass) +// Constant(value.asInstanceOf[java.lang.Number].floatValue) +// else if (typeClass == definitions.DoubleClass) +// Constant(value.asInstanceOf[java.lang.Number].doubleValue) +// else if (typeClass == definitions.StringClass) +// Constant(value.asInstanceOf[java.lang.String]) +// else +// abort("illegal value: " + value + ", class-symbol: " + typeClass) +// } +// +// def isDefinedAtgetConstant(constType: Type): Boolean = { +// val typeClass = constType.typeSymbol +// if ( (typeClass == definitions.BooleanClass) +// || (typeClass == definitions.ByteClass) +// || (typeClass == definitions.ShortClass) +// || (typeClass == definitions.CharClass) +// || (typeClass == definitions.IntClass) +// || (typeClass == definitions.LongClass) +// || (typeClass == definitions.FloatClass) +// || (typeClass == definitions.DoubleClass) +// || (typeClass == definitions.StringClass) +// ) +// true +// else +// false +// } +// +// private def translateAttributes(typ: MSILType): Long = { +// var flags: Long = Flags.JAVA; +// if (typ.IsNotPublic() || typ.IsNestedPrivate() +// || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()) +// flags = flags | Flags.PRIVATE; +// else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem()) +// flags = flags | Flags.PROTECTED; +// if (typ.IsAbstract()) +// flags = flags | Flags.ABSTRACT; +// if (typ.IsSealed()) +// flags = flags | Flags.FINAL; +// if (typ.IsInterface()) +// flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT; +// +// flags +// } +// +// private def translateAttributes(field: FieldInfo): Long = { +// var flags: Long = Flags.JAVA; +// if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly()) +// flags = flags | Flags.PRIVATE; +// else if (field.IsFamily() || field.IsFamilyOrAssembly()) +// flags = flags | Flags.PROTECTED; +// if (field.IsInitOnly() || field.IsLiteral()) +// flags = flags | Flags.FINAL; +// else +// flags = flags | Flags.MUTABLE; +// if (field.IsStatic) +// flags = flags | Flags.STATIC +// +// flags +// } +// +// private def translateAttributes(method: MethodBase): Long = { +// var flags: Long = Flags.JAVA; +// if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly()) +// flags = flags | Flags.PRIVATE; +// else if (method.IsFamily() || method.IsFamilyOrAssembly()) +// flags = flags | Flags.PROTECTED; +// if (method.IsAbstract()) +// flags = flags | Flags.DEFERRED; +// if (method.IsStatic) +// flags = flags | Flags.STATIC +// +// flags +// } +// } diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala index 6215506141..260c350ede 100644 --- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -1,169 +1,169 @@ -/* NSC -- new Scala compiler - * Copyright 2006-2011 LAMP/EPFL - * @author Martin Odersky - */ - -// $Id$ - -package scala.tools.nsc -package util - -import java.io.File -import java.net.URL -import java.util.StringTokenizer -import scala.util.Sorting -import scala.collection.mutable -import scala.tools.nsc.io.{ AbstractFile, MsilFile } -import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly } -import ClassPath.{ ClassPathContext, isTraitImplementation } - -/** Keeping the MSIL classpath code in its own file is important to make sure - * we don't accidentally introduce a dependency on msil.jar in the jvm. - */ - -object MsilClassPath { - def collectTypes(assemFile: AbstractFile) = { - var res: Array[MSILType] = MSILType.EmptyTypes - val assem = Assembly.LoadFrom(assemFile.path) - if (assem != null) { - // DeclaringType == null: true for non-inner classes - res = assem.GetTypes() filter (_.DeclaringType == null) - Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0) - } - res - } - - /** On the java side this logic is in PathResolver, but as I'm not really - * up to folding MSIL into that, I am encapsulating it here. - */ - def fromSettings(settings: Settings): MsilClassPath = { - val context = - if (settings.inline.value) new MsilContext - else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) } - - import settings._ - new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context) - } - - class MsilContext extends ClassPathContext[MsilFile] { - def toBinaryName(rep: MsilFile) = rep.msilType.Name - def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this) - } - - private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MsilFile]] = { - import ClassPath._ - val etr = new mutable.ListBuffer[ClassPath[MsilFile]] - val names = new mutable.HashSet[String] - - // 1. Assemblies from -Xassem-extdirs - for (dirName <- expandPath(ext, expandStar = false)) { - val dir = AbstractFile.getDirectory(dirName) - if (dir ne null) { - for (file <- dir) { - val name = file.name.toLowerCase - if (name.endsWith(".dll") || name.endsWith(".exe")) { - names += name - etr += context.newClassPath(file) - } - } - } - } - - // 2. Assemblies from -Xassem-path - for (fileName <- expandPath(user, expandStar = false)) { - val file = AbstractFile.getFile(fileName) - if (file ne null) { - val name = file.name.toLowerCase - if (name.endsWith(".dll") || name.endsWith(".exe")) { - names += name - etr += context.newClassPath(file) - } - } - } - - def check(n: String) { - if (!names.contains(n)) - throw new AssertionError("Cannot find assembly "+ n + - ". Use -Xassem-extdirs or -Xassem-path to specify its location") - } - check("mscorlib.dll") - check("scalaruntime.dll") - - // 3. Source path - for (dirName <- expandPath(source, expandStar = false)) { - val file = AbstractFile.getDirectory(dirName) - if (file ne null) etr += new SourcePath[MsilFile](file, context) - } - - etr.toList - } -} -import MsilClassPath._ - -/** - * A assembly file (dll / exe) containing classes and namespaces - */ -class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MsilFile] { - def name = { - val i = namespace.lastIndexOf('.') - if (i < 0) namespace - else namespace drop (i + 1) - } - def asURLs = List(new java.net.URL(name)) - def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here? - - private lazy val first: Int = { - var m = 0 - var n = types.length - 1 - while (m < n) { - val l = (m + n) / 2 - val res = types(l).FullName.compareTo(namespace) - if (res < 0) m = l + 1 - else n = l - } - if (types(m).FullName.startsWith(namespace)) m else types.length - } - - lazy val classes = { - val cls = new mutable.ListBuffer[ClassRep] - var i = first - while (i < types.length && types(i).Namespace.startsWith(namespace)) { - // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..) - if (types(i).Namespace == namespace) - cls += ClassRep(Some(new MsilFile(types(i))), None) - i += 1 - } - cls.toIndexedSeq - } - - lazy val packages = { - val nsSet = new mutable.HashSet[String] - var i = first - while (i < types.length && types(i).Namespace.startsWith(namespace)) { - val subns = types(i).Namespace - if (subns.length > namespace.length) { - // example: namespace = "System", subns = "System.Reflection.Emit" - // => find second "." and "System.Reflection" to nsSet. - val end = subns.indexOf('.', namespace.length + 1) - nsSet += (if (end < 0) subns - else subns.substring(0, end)) - } - i += 1 - } - val xs = for (ns <- nsSet.toList) - yield new AssemblyClassPath(types, ns, context) - - xs.toIndexedSeq - } - - val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq() - - override def toString() = "assembly classpath "+ namespace -} - -/** - * The classpath when compiling with target:msil. Binary files are represented as - * MSILType values. - */ -class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) -extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } \ No newline at end of file +// /* NSC -- new Scala compiler +// * Copyright 2006-2011 LAMP/EPFL +// * @author Martin Odersky +// */ +// +// // $Id$ +// +// package scala.tools.nsc +// package util +// +// import java.io.File +// import java.net.URL +// import java.util.StringTokenizer +// import scala.util.Sorting +// import scala.collection.mutable +// import scala.tools.nsc.io.{ AbstractFile, MsilFile } +// import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly } +// import ClassPath.{ ClassPathContext, isTraitImplementation } +// +// /** Keeping the MSIL classpath code in its own file is important to make sure +// * we don't accidentally introduce a dependency on msil.jar in the jvm. +// */ +// +// object MsilClassPath { +// def collectTypes(assemFile: AbstractFile) = { +// var res: Array[MSILType] = MSILType.EmptyTypes +// val assem = Assembly.LoadFrom(assemFile.path) +// if (assem != null) { +// // DeclaringType == null: true for non-inner classes +// res = assem.GetTypes() filter (_.DeclaringType == null) +// Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0) +// } +// res +// } +// +// /** On the java side this logic is in PathResolver, but as I'm not really +// * up to folding MSIL into that, I am encapsulating it here. +// */ +// def fromSettings(settings: Settings): MsilClassPath = { +// val context = +// if (settings.inline.value) new MsilContext +// else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) } +// +// import settings._ +// new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context) +// } +// +// class MsilContext extends ClassPathContext[MsilFile] { +// def toBinaryName(rep: MsilFile) = rep.msilType.Name +// def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this) +// } +// +// private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MsilFile]] = { +// import ClassPath._ +// val etr = new mutable.ListBuffer[ClassPath[MsilFile]] +// val names = new mutable.HashSet[String] +// +// // 1. Assemblies from -Xassem-extdirs +// for (dirName <- expandPath(ext, expandStar = false)) { +// val dir = AbstractFile.getDirectory(dirName) +// if (dir ne null) { +// for (file <- dir) { +// val name = file.name.toLowerCase +// if (name.endsWith(".dll") || name.endsWith(".exe")) { +// names += name +// etr += context.newClassPath(file) +// } +// } +// } +// } +// +// // 2. Assemblies from -Xassem-path +// for (fileName <- expandPath(user, expandStar = false)) { +// val file = AbstractFile.getFile(fileName) +// if (file ne null) { +// val name = file.name.toLowerCase +// if (name.endsWith(".dll") || name.endsWith(".exe")) { +// names += name +// etr += context.newClassPath(file) +// } +// } +// } +// +// def check(n: String) { +// if (!names.contains(n)) +// throw new AssertionError("Cannot find assembly "+ n + +// ". Use -Xassem-extdirs or -Xassem-path to specify its location") +// } +// check("mscorlib.dll") +// check("scalaruntime.dll") +// +// // 3. Source path +// for (dirName <- expandPath(source, expandStar = false)) { +// val file = AbstractFile.getDirectory(dirName) +// if (file ne null) etr += new SourcePath[MsilFile](file, context) +// } +// +// etr.toList +// } +// } +// import MsilClassPath._ +// +// /** +// * A assembly file (dll / exe) containing classes and namespaces +// */ +// class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MsilFile] { +// def name = { +// val i = namespace.lastIndexOf('.') +// if (i < 0) namespace +// else namespace drop (i + 1) +// } +// def asURLs = List(new java.net.URL(name)) +// def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here? +// +// private lazy val first: Int = { +// var m = 0 +// var n = types.length - 1 +// while (m < n) { +// val l = (m + n) / 2 +// val res = types(l).FullName.compareTo(namespace) +// if (res < 0) m = l + 1 +// else n = l +// } +// if (types(m).FullName.startsWith(namespace)) m else types.length +// } +// +// lazy val classes = { +// val cls = new mutable.ListBuffer[ClassRep] +// var i = first +// while (i < types.length && types(i).Namespace.startsWith(namespace)) { +// // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..) +// if (types(i).Namespace == namespace) +// cls += ClassRep(Some(new MsilFile(types(i))), None) +// i += 1 +// } +// cls.toIndexedSeq +// } +// +// lazy val packages = { +// val nsSet = new mutable.HashSet[String] +// var i = first +// while (i < types.length && types(i).Namespace.startsWith(namespace)) { +// val subns = types(i).Namespace +// if (subns.length > namespace.length) { +// // example: namespace = "System", subns = "System.Reflection.Emit" +// // => find second "." and "System.Reflection" to nsSet. +// val end = subns.indexOf('.', namespace.length + 1) +// nsSet += (if (end < 0) subns +// else subns.substring(0, end)) +// } +// i += 1 +// } +// val xs = for (ns <- nsSet.toList) +// yield new AssemblyClassPath(types, ns, context) +// +// xs.toIndexedSeq +// } +// +// val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq() +// +// override def toString() = "assembly classpath "+ namespace +// } +// +// /** +// * The classpath when compiling with target:msil. Binary files are represented as +// * MSILType values. +// */ +// class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) +// extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } \ No newline at end of file -- cgit v1.2.3 From 57f19c440a69714abf248ef7bbc5e94b96d89f2f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 09:36:56 -0800 Subject: ant and diff friendlier msil-disabling. --- .../scala/tools/nsc/backend/MSILPlatform.scala | 123 +- .../scala/tools/nsc/backend/msil/GenMSIL.scala | 4699 ++++++++++---------- src/compiler/scala/tools/nsc/io/MsilFile.scala | 35 +- .../scala/tools/nsc/symtab/clr/CLRTypes.scala | 263 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 1691 +++---- .../scala/tools/nsc/util/MsilClassPath.scala | 323 +- 6 files changed, 3570 insertions(+), 3564 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala index a86528d492..d5a02f9242 100644 --- a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala @@ -1,65 +1,66 @@ -// /* NSC -- new Scala compiler -// * Copyright 2005-2011 LAMP/EPFL -// * @author Paul Phillips -// */ -// -// package scala.tools.nsc -// package backend -// +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package backend + // import ch.epfl.lamp.compiler.{ msil => msillib } // import util.{ ClassPath, MsilClassPath } // import msil.GenMSIL // import io.{ AbstractFile, MsilFile } -// -// trait MSILPlatform extends Platform { -// import global._ -// import definitions.{ ComparatorClass, BoxedNumberClass, getMember } -// -// type BinaryRepr = MsilFile -// -// if (settings.verbose.value) -// inform("[AssemRefs = " + settings.assemrefs.value + "]") -// -// // phaseName = "msil" -// object genMSIL extends { -// val global: MSILPlatform.this.global.type = MSILPlatform.this.global -// val runsAfter = List[String]("dce") -// val runsRightAfter = None -// } with GenMSIL -// -// lazy val classPath = MsilClassPath.fromSettings(settings) -// def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]]) -// // See discussion in JavaPlatForm for why we need a cast here. -// -// def platformPhases = List( -// genMSIL // generate .msil files -// ) -// -// lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_) -// def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass -// -// def newClassLoader(bin: MsilFile): loaders.SymbolLoader = new loaders.MsilFileLoader(bin) -// -// /** -// * Tells whether a class should be loaded and entered into the package -// * scope. On .NET, this method returns `false` for all synthetic classes -// * (anonymous classes, implementation classes, module classes), their -// * symtab is encoded in the pickle of another class. -// */ -// def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = { -// if (cls.binary.isDefined) { -// val typ = cls.binary.get.msilType -// if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) { -// val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false) -// assert(attrs.length == 1, attrs.length) -// val a = attrs(0).asInstanceOf[msillib.Attribute] -// // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle. -// // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic. -// a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR -// } else true // always load non-scala types -// } else true // always load source -// } -// -// def needCompile(bin: MsilFile, src: AbstractFile) = -// false // always use compiled file on .net -// } + +trait MSILPlatform /*extends Platform { + import global._ + import definitions.{ ComparatorClass, BoxedNumberClass, getMember } + + type BinaryRepr = MsilFile + + if (settings.verbose.value) + inform("[AssemRefs = " + settings.assemrefs.value + "]") + + // phaseName = "msil" + object genMSIL extends { + val global: MSILPlatform.this.global.type = MSILPlatform.this.global + val runsAfter = List[String]("dce") + val runsRightAfter = None + } with GenMSIL + + lazy val classPath = MsilClassPath.fromSettings(settings) + def rootLoader = new loaders.PackageLoader(classPath.asInstanceOf[ClassPath[platform.BinaryRepr]]) + // See discussion in JavaPlatForm for why we need a cast here. + + def platformPhases = List( + genMSIL // generate .msil files + ) + + lazy val externalEquals = getMember(ComparatorClass.companionModule, nme.equals_) + def isMaybeBoxed(sym: Symbol) = sym isNonBottomSubClass BoxedNumberClass + + def newClassLoader(bin: MsilFile): loaders.SymbolLoader = new loaders.MsilFileLoader(bin) + + /** + * Tells whether a class should be loaded and entered into the package + * scope. On .NET, this method returns `false` for all synthetic classes + * (anonymous classes, implementation classes, module classes), their + * symtab is encoded in the pickle of another class. + */ + def doLoad(cls: ClassPath[BinaryRepr]#ClassRep): Boolean = { + if (cls.binary.isDefined) { + val typ = cls.binary.get.msilType + if (typ.IsDefined(loaders.clrTypes.SCALA_SYMTAB_ATTR, false)) { + val attrs = typ.GetCustomAttributes(loaders.clrTypes.SCALA_SYMTAB_ATTR, false) + assert(attrs.length == 1, attrs.length) + val a = attrs(0).asInstanceOf[msillib.Attribute] + // symtab_constr takes a byte array argument (the pickle), i.e. typ has a pickle. + // otherwise, symtab_default_constr was used, which marks typ as scala-synthetic. + a.getConstructor() == loaders.clrTypes.SYMTAB_CONSTR + } else true // always load non-scala types + } else true // always load source + } + + def needCompile(bin: MsilFile, src: AbstractFile) = + false // always use compiled file on .net +} +*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index ab07f2e4fc..aba537f3bd 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -1,12 +1,12 @@ -// /* NSC -- new scala compiler -// * Copyright 2005-2011 LAMP/EPFL -// * @author Nikolay Mihaylov -// */ -// -// -// package scala.tools.nsc -// package backend.msil -// +/* NSC -- new scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Nikolay Mihaylov + */ + + +package scala.tools.nsc +package backend.msil + // import java.io.{File, IOException} // import java.nio.{ByteBuffer, ByteOrder} // import scala.collection.{ mutable, immutable } @@ -15,2343 +15,2344 @@ // import ch.epfl.lamp.compiler.msil.{Type => MsilType, _} // import ch.epfl.lamp.compiler.msil.emit._ // import ch.epfl.lamp.compiler.msil.util.PECustomMod -// -// abstract class GenMSIL extends SubComponent { -// import global._ -// import loaders.clrTypes -// import clrTypes.{types, constructors, methods, fields} -// import icodes._ -// import icodes.opcodes._ -// -// val x = loaders -// -// /** Create a new phase */ -// override def newPhase(p: Phase) = new MsilPhase(p) -// -// val phaseName = "msil" -// /** MSIL code generation phase -// */ -// class MsilPhase(prev: Phase) extends GlobalPhase(prev) { -// def name = phaseName -// override def newFlags = phaseNewFlags -// -// override def erasedTypes = true -// -// override def run() { -// if (settings.debug.value) inform("[running phase " + name + " on icode]") -// -// val codeGenerator = new BytecodeGenerator -// -// //classes is ICodes.classes, a HashMap[Symbol, IClass] -// classes.values foreach codeGenerator.findEntryPoint -// if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead -// val entryclass = opt.showClass.get.toString -// warning("Couldn't find entry class " + entryclass) -// } -// -// codeGenerator.initAssembly -// -// val classesSorted = classes.values.toList.sortBy(c => c.symbol.id) // simplifies comparing cross-compiler vs. .exe output -// classesSorted foreach codeGenerator.createTypeBuilder -// classesSorted foreach codeGenerator.createClassMembers -// -// try { -// classesSorted foreach codeGenerator.genClass -// } finally { -// codeGenerator.writeAssembly -// } -// } -// -// override def apply(unit: CompilationUnit) { -// abort("MSIL works on icode classes, not on compilation units!") -// } -// } -// -// /** -// * MSIL bytecode generator. -// * -// */ -// class BytecodeGenerator { -// -// val MODULE_INSTANCE_NAME = "MODULE$" -// -// import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, BYTE => MBYTE, SHORT => MSHORT, -// CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT, -// DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING, -// STRING_ARRAY => MSTRING_ARRAY, -// SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR, -// SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR} -// -// val EXCEPTION = clrTypes.getType("System.Exception") -// val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE) -// -// val ICLONEABLE = clrTypes.getType("System.ICloneable") -// val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes) -// -// val MMONITOR = clrTypes.getType("System.Threading.Monitor") -// val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT)) -// val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT)) -// -// val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder") -// val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes) -// val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString", -// MsilType.EmptyTypes) -// -// val TYPE_FROM_HANDLE = -// clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle"))) -// -// val INT_PTR = clrTypes.getType("System.IntPtr") -// -// val JOBJECT = definitions.ObjectClass -// val JSTRING = definitions.StringClass -// -// val SystemConvert = clrTypes.getType("System.Convert") -// -// val objParam = Array(MOBJECT) -// -// val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam) // see comment in emitUnbox -// val toSByte: MethodInfo = SystemConvert.GetMethod("ToSByte", objParam) -// val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam) -// val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam) -// val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam) -// val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam) -// val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam) -// val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam) -// -// //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT") -// val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT) -// -// // Scala attributes -// // symtab.Definitions -> object (singleton..) -// val SerializableAttr = definitions.SerializableAttr.tpe -// val CloneableAttr = definitions.CloneableAttr.tpe -// val TransientAtt = definitions.TransientAttr.tpe -// // remoting: the architectures are too different, no mapping (no portable code -// // possible) -// -// // java instance methods that are mapped to static methods in .net -// // these will need to be called with OpCodes.Call (not Callvirt) -// val dynToStatMapped = mutable.HashSet[Symbol]() -// -// initMappings() -// -// /** Create the mappings between java and .net classes and methods */ -// private def initMappings() { -// mapType(definitions.AnyClass, MOBJECT) -// mapType(definitions.AnyRefClass, MOBJECT) -// //mapType(definitions.NullClass, clrTypes.getType("scala.AllRef$")) -// //mapType(definitions.NothingClass, clrTypes.getType("scala.All$")) -// // FIXME: for some reason the upper two lines map to null -// mapType(definitions.NullClass, EXCEPTION) -// mapType(definitions.NothingClass, EXCEPTION) -// -// mapType(definitions.BooleanClass, MBOOL) -// mapType(definitions.ByteClass, MBYTE) -// mapType(definitions.ShortClass, MSHORT) -// mapType(definitions.CharClass, MCHAR) -// mapType(definitions.IntClass, MINT) -// mapType(definitions.LongClass, MLONG) -// mapType(definitions.FloatClass, MFLOAT) -// mapType(definitions.DoubleClass, MDOUBLE) -// } -// -// var clasz: IClass = _ -// var method: IMethod = _ -// -// var massembly: AssemblyBuilder = _ -// var mmodule: ModuleBuilder = _ -// var mcode: ILGenerator = _ -// -// var assemName: String = _ -// var firstSourceName = "" -// var outDir: File = _ -// var srcPath: File = _ -// var moduleName: String = _ -// -// def initAssembly() { -// -// assemName = settings.assemname.value -// -// if (assemName == "") { -// if (entryPoint != null) { -// assemName = msilName(entryPoint.enclClass) -// // remove the $ at the end (from module-name) -// assemName = assemName.substring(0, assemName.length() - 1) -// } else { -// // assuming filename of first source file -// assert(firstSourceName.endsWith(".scala"), firstSourceName) -// assemName = firstSourceName.substring(0, firstSourceName.length() - 6) -// } -// } else { -// if (assemName.endsWith(".msil")) -// assemName = assemName.substring(0, assemName.length()-5) -// if (assemName.endsWith(".il")) -// assemName = assemName.substring(0, assemName.length()-3) -// val f: File = new File(assemName) -// assemName = f.getName() -// } -// -// outDir = new File(settings.outdir.value) -// -// srcPath = new File(settings.sourcedir.value) -// -// val assemblyName = new AssemblyName() -// assemblyName.Name = assemName -// massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName) -// -// moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe") -// // filename here: .dll or .exe (in both parameters), second: give absolute-path -// mmodule = massembly.DefineDynamicModule(moduleName, -// new File(outDir, moduleName).getAbsolutePath()) -// assert (mmodule != null) -// } -// -// -// /** -// * Form of the custom Attribute parameter (Ecma-335.pdf) -// * - p. 163 for CustomAttrib Form, -// * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!) -// * !! least significant byte first if values longer than one byte !! -// * -// * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00 -// * 2: FixedArgs (directly the data, get number and types from related constructor) -// * 2.1: length of the array (unsigned int32, 4 bytes, least significant first) -// * 2.2: the byte array data -// * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000) -// */ -// def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) { -// def addMarker() { -// val markerSymtab = new Array[Byte](4) -// markerSymtab(0) = 1.toByte -// tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR, markerSymtab) -// } -// -// // both conditions are needed (why exactly..?) -// if (tBuilder.Name.endsWith("$") || sym.isModuleClass) { -// addMarker() -// } else { -// currentRun.symData.get(sym) match { -// case Some(pickle) => -// var size = pickle.writeIndex -// val symtab = new Array[Byte](size + 8) -// symtab(0) = 1.toByte -// for (i <- 2 until 6) { -// symtab(i) = (size & 0xff).toByte -// size = size >> 8 -// } -// java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) -// -// tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) -// -// currentRun.symData -= sym -// currentRun.symData -= sym.companionSymbol -// -// case _ => -// addMarker() -// } -// } -// } -// -// /** -// * Mutates `member` adding CLR attributes (if any) based on sym.annotations. -// * Please notice that CLR custom modifiers are a different beast (see customModifiers below) -// * and thus shouldn't be added by this method. -// */ -// def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) { -// val attributes = annotations.map(_.atp.typeSymbol).collect { -// case definitions.TransientAttr => null // TODO this is just an example -// } -// return // TODO: implement at some point -// } -// -// /** -// * What's a CLR custom modifier? Intro available as source comments in compiler.msil.CustomModifier. -// * It's basically a marker associated with a location (think of FieldInfo, ParameterInfo, and PropertyInfo) -// * and thus that marker (be it optional or required) becomes part of the signature of that location. -// * Some annotations will become CLR attributes (see addAttributes above), others custom modifiers (this method). -// */ -// def customModifiers(annotations: List[AnnotationInfo]): Array[CustomModifier] = { -// annotations.map(_.atp.typeSymbol).collect { -// case definitions.VolatileAttr => new CustomModifier(true, CustomModifier.VolatileMarker) -// } toArray -// } -// -// -// -// /* -// debuglog("creating annotations: " + annotations + " for member : " + member) -// for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ; -// if annot.isConstant) -// //!typ.typeSymbol.isJavaDefined -// { -// // assert(consts.length <= 1, -// // "too many constant arguments for annotations; "+consts.toString()) -// -// // Problem / TODO having the symbol of the annotations type would be nicer -// // (i hope that type.typeSymbol is the same as the one in types2create) -// // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder) -// // when this is solved, types2create will be the same as icodes.classes, thus superfluous -// val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder] -// // val annType: MsilType = getType(typ.typeSymbol) -// -// // Problem / TODO: i have no idea which constructor is used. This -// // information should be available in AnnotationInfo. -// annType.CreateType() // else, GetConstructors can't be used -// val constr: ConstructorInfo = annType.GetConstructors()(0) -// // prevent a second call of CreateType, only needed because there's no -// // other way than GetConstructors()(0) to get the constructor, if there's -// // no constructor symbol available. -// -// val args: Array[Byte] = -// getAttributeArgs( -// annArgs map (_.constant.get), -// (for((n,v) <- nvPairs) yield (n, v.constant.get))) -// member.SetCustomAttribute(constr, args) -// } -// } */ -// -// /* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { -// val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough! -// buf.order(ByteOrder.LITTLE_ENDIAN) -// buf.putShort(1.toShort) // signature -// -// def emitSerString(str: String) = { -// // this is wrong, it has to be the length of the UTF-8 byte array, which -// // may be longer (see clr-book on page 302) -// // val length: Int = str.length -// val strBytes: Array[Byte] = try { -// str.getBytes("UTF-8") -// } catch { -// case _: Error => abort("could not get byte-array for string: " + str) -// } -// val length: Int = strBytes.length //this length is stored big-endian -// if (length < 128) -// buf.put(length.toByte) -// else if (length < (1<<14)) { -// buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0' -// buf.put((length | 0xff).toByte) -// } else if (length < (1 << 29)) { -// buf.put(((length >> 24) | 0xc0).toByte) -// buf.put(((length >> 16) & 0xff).toByte) -// buf.put(((length >> 8) & 0xff).toByte) -// buf.put(((length ) & 0xff).toByte) -// } else -// abort("string too long for attribute parameter: " + length) -// buf.put(strBytes) -// } -// -// def emitConst(const: Constant): Unit = const.tag match { -// case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte) -// case ByteTag => buf.put(const.byteValue) -// case ShortTag => buf.putShort(const.shortValue) -// case CharTag => buf.putChar(const.charValue) -// case IntTag => buf.putInt(const.intValue) -// case LongTag => buf.putLong(const.longValue) -// case FloatTag => buf.putFloat(const.floatValue) -// case DoubleTag => buf.putDouble(const.doubleValue) -// case StringTag => -// val str: String = const.stringValue -// if (str == null) { -// buf.put(0xff.toByte) -// } else { -// emitSerString(str) -// } -// case ArrayTag => -// val arr: Array[Constant] = const.arrayValue -// if (arr == null) { -// buf.putInt(0xffffffff) -// } else { -// buf.putInt(arr.length) -// arr.foreach(emitConst) -// } -// -// // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ??? -// -// case _ => abort("could not handle attribute argument: " + const) -// } -// -// consts foreach emitConst -// buf.putShort(nvPairs.length.toShort) -// def emitNamedArg(nvPair: (Name, Constant)) { -// // the named argument is a property of the attribute (it can't be a field, since -// // all fields in scala are private) -// buf.put(0x54.toByte) -// -// def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151 -// case BooleanTag => buf.put(0x02.toByte) -// case ByteTag => buf.put(0x05.toByte) -// case ShortTag => buf.put(0x06.toByte) -// case CharTag => buf.put(0x07.toByte) -// case IntTag => buf.put(0x08.toByte) -// case LongTag => buf.put(0x0a.toByte) -// case FloatTag => buf.put(0x0c.toByte) -// case DoubleTag => buf.put(0x0d.toByte) -// case StringTag => buf.put(0x0e.toByte) -// -// // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ??? -// -// // ArrayTag falls in here -// case _ => abort("could not handle attribute argument: " + c) -// } -// -// val cnst: Constant = nvPair._2 -// if (cnst.tag == ArrayTag) { -// buf.put(0x1d.toByte) -// emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0 -// } else if (cnst.tag == EnumTag) { -// buf.put(0x55.toByte) -// // TODO: put a SerString (don't know what exactly, names of the enums somehow..) -// } else { -// buf.put(0x51.toByte) -// emitType(cnst) -// } -// -// emitSerString(nvPair._1.toString) -// emitConst(nvPair._2) -// } -// -// val length = buf.position() -// buf.array().slice(0, length) -// } */ -// -// def writeAssembly() { -// if (entryPoint != null) { -// assert(entryPoint.enclClass.isModuleClass, entryPoint.enclClass) -// val mainMethod = methods(entryPoint) -// val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY) -// val globalMain = mmodule.DefineGlobalMethod( -// "Main", MethodAttributes.Public | MethodAttributes.Static, -// MVOID, stringArrayTypes) -// globalMain.DefineParameter(0, ParameterAttributes.None, "args") -// massembly.SetEntryPoint(globalMain) -// val code = globalMain.GetILGenerator() -// val moduleField = getModuleInstanceField(entryPoint.enclClass) -// code.Emit(OpCodes.Ldsfld, moduleField) -// code.Emit(OpCodes.Ldarg_0) -// code.Emit(OpCodes.Callvirt, mainMethod) -// code.Emit(OpCodes.Ret) -// } -// createTypes() -// var outDirName: String = null -// try { -// if (settings.Ygenjavap.isDefault) { // we reuse the JVM-sounding setting because it's conceptually similar -// outDirName = outDir.getPath() -// massembly.Save(outDirName + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */ -// } else { -// outDirName = srcPath.getPath() -// massembly.Save(settings.Ygenjavap.value, outDirName) /* use MultipleFilesILPrinterVisitor */ -// } -// } catch { -// case e:IOException => abort("Could not write to " + outDirName + ": " + e.getMessage()) -// } -// } -// -// private def createTypes() { -// for (sym <- classes.keys) { -// val iclass = classes(sym) -// val tBuilder = types(sym).asInstanceOf[TypeBuilder] -// -// debuglog("Calling CreatType for " + sym + ", " + tBuilder.toString) -// -// tBuilder.CreateType() -// tBuilder.setSourceFilepath(iclass.cunit.source.file.path) -// } -// } -// -// private[GenMSIL] def ilasmFileName(iclass: IClass) : String = { -// // method.sourceFile contains just the filename -// iclass.cunit.source.file.toString.replace("\\", "\\\\") -// } -// -// private[GenMSIL] def genClass(iclass: IClass) { -// val sym = iclass.symbol -// debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags)) -// clasz = iclass -// -// val tBuilder = getType(sym).asInstanceOf[TypeBuilder] -// if (isCloneable(sym)) { -// // FIXME: why there's no nme.clone_ ? -// // "Clone": if the code is non-portable, "Clone" is defined, not "clone" -// // TODO: improve condition (should override AnyRef.clone) -// if (iclass.methods.forall(m => { -// !((m.symbol.name.toString != "clone" || m.symbol.name.toString != "Clone") && -// m.symbol.tpe.paramTypes.length != 0) -// })) { -// debuglog("auto-generating cloneable method for " + sym) -// val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual | -// MethodAttributes.HideBySig).toShort -// val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT, -// MsilType.EmptyTypes) -// val clCode = cloneMethod.GetILGenerator() -// clCode.Emit(OpCodes.Ldarg_0) -// clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE) -// clCode.Emit(OpCodes.Ret) -// } -// } -// -// val line = sym.pos.line -// tBuilder.setPosition(line, ilasmFileName(iclass)) -// -// if (isTopLevelModule(sym)) { -// if (sym.companionClass == NoSymbol) -// generateMirrorClass(sym) -// else -// log("No mirror class for module with linked class: " + -// sym.fullName) -// } -// -// addSymtabAttribute(sym, tBuilder) -// addAttributes(tBuilder, sym.annotations) -// -// if (iclass.symbol != definitions.ArrayClass) -// iclass.methods foreach genMethod -// -// } //genClass -// -// -// private def genMethod(m: IMethod) { -// debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + -// " owner: " + m.symbol.owner) -// method = m -// localBuilders.clear -// computeLocalVarsIndex(m) -// -// if (m.symbol.isClassConstructor) { -// mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator() -// } else { -// val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder] -// if (!mBuilder.IsAbstract()) -// try { -// mcode = mBuilder.GetILGenerator() -// } catch { -// case e: Exception => -// java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) -// java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner) -// java.lang.System.out.println("mBuilder = " + mBuilder) -// java.lang.System.out.println("mBuilder.DeclaringType = " + -// TypeAttributes.toString(mBuilder.DeclaringType.Attributes) + -// "::" + mBuilder.DeclaringType) -// throw e -// } -// else -// mcode = null -// } -// -// if (mcode != null) { -// for (local <- m.locals ; if !(m.params contains local)) { -// debuglog("add local var: " + local + ", of kind " + local.kind) -// val t: MsilType = msilType(local.kind) -// val localBuilder = mcode.DeclareLocal(t) -// localBuilder.SetLocalSymInfo(msilName(local.sym)) -// localBuilders(local) = localBuilder -// } -// genCode(m) -// } -// -// } -// -// /** Special linearizer for methods with at least one exception handler. This -// * linearizer brings all basic blocks in the right order so that nested -// * try-catch and try-finally blocks can be emitted. -// */ -// val msilLinearizer = new MSILLinearizer() -// -// val labels = mutable.HashMap[BasicBlock, Label]() -// -// /* when emitting .line, it's enough to include the full filename just once per method, thus reducing filesize. -// * this scheme relies on the fact that the entry block is emitted first. */ -// var dbFilenameSeen = false -// -// def genCode(m: IMethod) { -// -// def makeLabels(blocks: List[BasicBlock]) = { -// debuglog("Making labels for: " + method) -// for (bb <- blocks) labels(bb) = mcode.DefineLabel() -// } -// -// labels.clear -// -// var linearization = if(!m.exh.isEmpty) msilLinearizer.linearize(m) -// else linearizer.linearize(m) -// -// if (!m.exh.isEmpty) -// linearization = computeExceptionMaps(linearization, m) -// -// makeLabels(linearization) -// -// // debug val blocksInM = m.code.blocks.toList.sortBy(bb => bb.label) -// // debug val blocksInL = linearization.sortBy(bb => bb.label) -// // debug val MButNotL = (blocksInM.toSet) diff (blocksInL.toSet) // if non-empty, a jump to B fails to find a label for B (case CJUMP, case CZJUMP) -// // debug if(!MButNotL.isEmpty) { } -// -// dbFilenameSeen = false -// genBlocks(linearization) -// -// // RETURN inside exception blocks are replaced by Leave. The target of the -// // leave is a `Ret` outside any exception block (generated here). -// if (handlerReturnMethod == m) { -// mcode.MarkLabel(handlerReturnLabel) -// if (handlerReturnKind != UNIT) -// mcode.Emit(OpCodes.Ldloc, handlerReturnLocal) -// mcode.Emit(OpCodes.Ret) -// } -// -// beginExBlock.clear() -// beginCatchBlock.clear() -// endExBlock.clear() -// endFinallyLabels.clear() -// } -// -// def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) { -// blocks match { -// case Nil => () -// case x :: Nil => genBlock(x, prev = previous, next = null) -// case x :: y :: ys => genBlock(x, prev = previous, next = y); genBlocks(y :: ys, previous = x) -// } -// } -// -// // the try blocks starting at a certain BasicBlock -// val beginExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() -// -// // the catch blocks starting / endling at a certain BasicBlock -// val beginCatchBlock = mutable.HashMap[BasicBlock, ExceptionHandler]() -// val endExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() -// -// /** When emitting the code (genBlock), the number of currently active try / catch -// * blocks. When seeing a `RETURN` inside a try / catch, we need to -// * - store the result in a local (if it's not UNIT) -// * - emit `Leave handlerReturnLabel` instead of the Return -// * - emit code at the end: load the local and return its value -// */ -// var currentHandlers = new mutable.Stack[ExceptionHandler] -// // The IMethod the Local/Label/Kind below belong to -// var handlerReturnMethod: IMethod = _ -// // Stores the result when returning inside an exception block -// var handlerReturnLocal: LocalBuilder = _ -// // Label for a return instruction outside any exception block -// var handlerReturnLabel: Label = _ -// // The result kind. -// var handlerReturnKind: TypeKind = _ -// def returnFromHandler(kind: TypeKind): (LocalBuilder, Label) = { -// if (handlerReturnMethod != method) { -// handlerReturnMethod = method -// if (kind != UNIT) { -// handlerReturnLocal = mcode.DeclareLocal(msilType(kind)) -// handlerReturnLocal.SetLocalSymInfo("$handlerReturn") -// } -// handlerReturnLabel = mcode.DefineLabel() -// handlerReturnKind = kind -// } -// (handlerReturnLocal, handlerReturnLabel) -// } -// -// /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the -// * Leave target has to be inside the finally (and it has to be the `endfinally` instruction). -// * So for every finalizer, we have a label which marks the place of the `endfinally`, -// * nested try/catch blocks will leave there. -// */ -// val endFinallyLabels = mutable.HashMap[ExceptionHandler, Label]() -// -// /** Computes which blocks are the beginning / end of a try or catch block */ -// private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = { -// val visitedBlocks = new mutable.HashSet[BasicBlock]() -// -// // handlers which have not been introduced so far -// var openHandlers = m.exh -// -// -// /** Example -// * try { -// * try { -// * // *1* -// * } catch { -// * case h1 => -// * } -// * } catch { -// * case h2 => -// * case h3 => -// * try { -// * -// * } catch { -// * case h4 => // *2* -// * case h5 => -// * } -// * } -// */ -// -// // Stack of nested try blocks. Each bloc has a List of ExceptionHandler (multiple -// // catch statements). Example *1*: Stack(List(h2, h3), List(h1)) -// val currentTryHandlers = new mutable.Stack[List[ExceptionHandler]]() -// -// // Stack of nested catch blocks. The head of the list is the current catch block. The -// // tail is all following catch blocks. Example *2*: Stack(List(h3), List(h4, h5)) -// val currentCatchHandlers = new mutable.Stack[List[ExceptionHandler]]() -// -// for (b <- blocks) { -// -// // are we past the current catch blocks? -// def endHandlers(): List[ExceptionHandler] = { -// var res: List[ExceptionHandler] = Nil -// if (!currentCatchHandlers.isEmpty) { -// val handler = currentCatchHandlers.top.head -// if (!handler.blocks.contains(b)) { -// // all blocks of the handler are either visited, or not part of the linearization (i.e. dead) -// assert(handler.blocks.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), -// "Bad linearization of basic blocks inside catch. Found block not part of the handler\n"+ -// b.fullString +"\nwhile in catch-part of\n"+ handler) -// -// val rest = currentCatchHandlers.pop.tail -// if (rest.isEmpty) { -// // all catch blocks of that exception handler are covered -// res = handler :: endHandlers() -// } else { -// // there are more catch blocks for that try (handlers covering the same) -// currentCatchHandlers.push(rest) -// beginCatchBlock(b) = rest.head -// } -// } -// } -// res -// } -// val end = endHandlers() -// if (!end.isEmpty) endExBlock(b) = end -// -// // are we past the current try block? -// if (!currentTryHandlers.isEmpty) { -// val handler = currentTryHandlers.top.head -// if (!handler.covers(b)) { -// // all of the covered blocks are visited, or not part of the linearization -// assert(handler.covered.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), -// "Bad linearization of basic blocks inside try. Found non-covered block\n"+ -// b.fullString +"\nwhile in try-part of\n"+ handler) -// -// assert(handler.startBlock == b, -// "Bad linearization of basic blocks. The entry block of a catch does not directly follow the try\n"+ -// b.fullString +"\n"+ handler) -// -// val handlers = currentTryHandlers.pop -// currentCatchHandlers.push(handlers) -// beginCatchBlock(b) = handler -// } -// } -// -// // are there try blocks starting at b? -// val (newHandlers, stillOpen) = openHandlers.partition(_.covers(b)) -// openHandlers = stillOpen -// -// val newHandlersBySize = newHandlers.groupBy(_.covered.size) -// // big handlers first, smaller ones are nested inside the try of the big one -// // (checked by the assertions below) -// val sizes = newHandlersBySize.keys.toList.sortWith(_ > _) -// -// val beginHandlers = new mutable.ListBuffer[ExceptionHandler] -// for (s <- sizes) { -// val sHandlers = newHandlersBySize(s) -// for (h <- sHandlers) { -// assert(h.covered == sHandlers.head.covered, -// "bad nesting of exception handlers. same size, but not covering same blocks\n"+ -// h +"\n"+ sHandlers.head) -// assert(h.resultKind == sHandlers.head.resultKind, -// "bad nesting of exception handlers. same size, but the same resultKind\n"+ -// h +"\n"+ sHandlers.head) -// } -// for (bigger <- beginHandlers; h <- sHandlers) { -// assert(h.covered.subsetOf(bigger.covered), -// "bad nesting of exception handlers. try blocks of smaller handler are not nested in bigger one.\n"+ -// h +"\n"+ bigger) -// assert(h.blocks.toSet.subsetOf(bigger.covered), -// "bad nesting of exception handlers. catch blocks of smaller handler are not nested in bigger one.\n"+ -// h +"\n"+ bigger) -// } -// beginHandlers += sHandlers.head -// currentTryHandlers.push(sHandlers) -// } -// beginExBlock(b) = beginHandlers.toList -// visitedBlocks += b -// } -// -// // if there handlers left (i.e. handlers covering nothing, or a -// // non-existent (dead) block), remove their catch-blocks. -// val liveBlocks = if (openHandlers.isEmpty) blocks else { -// blocks.filter(b => openHandlers.forall(h => !h.blocks.contains(b))) -// } -// -// /** There might be open handlers, but no more blocks. happens when try/catch end -// * with `throw` or `return` -// * def foo() { try { .. throw } catch { _ => .. throw } } -// * -// * In this case we need some code after the catch block for the auto-generated -// * `leave` instruction. So we're adding a (dead) `throw new Exception`. -// */ -// val rest = currentCatchHandlers.map(handlers => { -// assert(handlers.length == 1, handlers) -// handlers.head -// }).toList -// -// if (rest.isEmpty) { -// liveBlocks -// } else { -// val b = m.code.newBlock -// b.emit(Seq( -// NEW(REFERENCE(definitions.ThrowableClass)), -// DUP(REFERENCE(definitions.ObjectClass)), -// CALL_METHOD(definitions.ThrowableClass.primaryConstructor, Static(true)), -// THROW(definitions.ThrowableClass) -// )) -// b.close -// endExBlock(b) = rest -// liveBlocks ::: List(b) -// } -// } -// -// /** -// * @param block the BasicBlock to emit code for -// * @param next the following BasicBlock, `null` if `block` is the last one -// */ -// def genBlock(block: BasicBlock, prev: BasicBlock, next: BasicBlock) { -// -// def loadLocalOrAddress(local: Local, msg : String , loadAddr : Boolean) { -// debuglog(msg + " for " + local) -// val isArg = local.arg -// val i = local.index -// if (isArg) -// loadArg(mcode, loadAddr)(i) -// else -// loadLocal(i, local, mcode, loadAddr) -// } -// -// def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) { -// debuglog(msg + " with owner: " + field.owner + -// " flags: " + Flags.flagsToString(field.owner.flags)) -// var fieldInfo = fields.get(field) match { -// case Some(fInfo) => fInfo -// case None => -// val fInfo = getType(field.owner).GetField(msilName(field)) -// fields(field) = fInfo -// fInfo -// } -// if (fieldInfo.IsVolatile) { -// mcode.Emit(OpCodes.Volatile) -// } -// if (!fieldInfo.IsLiteral) { -// if (loadAddr) { -// mcode.Emit(if (isStatic) OpCodes.Ldsflda else OpCodes.Ldflda, fieldInfo) -// } else { -// mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) -// } -// } else { -// assert(!loadAddr, "can't take AddressOf a literal field (not even with readonly. prefix) because no memory was allocated to such field ...") -// // TODO the above can be overcome by loading the value, boxing, and finally unboxing. An address to a copy of the raw value will be on the stack. -// /* We perform `field inlining' as required by CLR. -// * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available -// * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type -// * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case, -// * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */ -// val value = fieldInfo.getValue() -// if (value == null) { -// mcode.Emit(OpCodes.Ldnull) -// } else { -// val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType -// else fieldInfo.FieldType -// if (typ == clrTypes.STRING) { -// mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String]) -// } else if (typ == clrTypes.BOOLEAN) { -// mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1 -// else OpCodes.Ldc_I4_0) -// } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) { -// loadI4(value.asInstanceOf[Byte], mcode) -// } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) { -// loadI4(value.asInstanceOf[Int], mcode) -// } else if (typ == clrTypes.CHAR) { -// loadI4(value.asInstanceOf[Char], mcode) -// } else if (typ == clrTypes.INT || typ == clrTypes.UINT) { -// loadI4(value.asInstanceOf[Int], mcode) -// } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) { -// mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long]) -// } else if (typ == clrTypes.FLOAT) { -// mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float]) -// } else if (typ == clrTypes.DOUBLE) { -// mcode.Emit(OpCodes.Ldc_R8, value.asInstanceOf[Double]) -// } else { -// /* TODO one more case is described in Partition II, 16.2: bytearray(...) */ -// abort("Unknown type for static literal field: " + fieldInfo) -// } -// } -// } -// } -// -// /** Creating objects works differently on .NET. On the JVM -// * - NEW(type) => reference on Stack -// * - DUP, load arguments, CALL_METHOD(constructor) -// * -// * On .NET, the NEW and DUP are ignored, but we emit a special method call -// * - load arguments -// * - NewObj(constructor) => reference on stack -// * -// * This variable tells whether the previous instruction was a NEW, -// * we expect a DUP which is not emitted. */ -// var previousWasNEW = false -// -// var lastLineNr: Int = 0 -// var lastPos: Position = NoPosition -// -// -// // EndExceptionBlock must happen before MarkLabel because it adds the -// // Leave instruction. Otherwise, labels(block) points to the Leave -// // (inside the catch) instead of the instruction afterwards. -// for (handlers <- endExBlock.get(block); exh <- handlers) { -// currentHandlers.pop() -// for (l <- endFinallyLabels.get(exh)) -// mcode.MarkLabel(l) -// mcode.EndExceptionBlock() -// } -// -// mcode.MarkLabel(labels(block)) -// debuglog("Generating code for block: " + block) -// -// for (handler <- beginCatchBlock.get(block)) { -// if (!currentHandlers.isEmpty && currentHandlers.top.covered == handler.covered) { -// currentHandlers.pop() -// currentHandlers.push(handler) -// } -// if (handler.cls == NoSymbol) { -// // `finally` blocks are represented the same as `catch`, but with no catch-type -// mcode.BeginFinallyBlock() -// } else { -// val t = getType(handler.cls) -// mcode.BeginCatchBlock(t) -// } -// } -// for (handlers <- beginExBlock.get(block); exh <- handlers) { -// currentHandlers.push(exh) -// mcode.BeginExceptionBlock() -// } -// -// for (instr <- block) { -// try { -// val currentLineNr = instr.pos.line -// val skip = if(instr.pos.isRange) instr.pos.sameRange(lastPos) else (currentLineNr == lastLineNr); -// if(!skip || !dbFilenameSeen) { -// val fileName = if(dbFilenameSeen) "" else {dbFilenameSeen = true; ilasmFileName(clasz)}; -// if(instr.pos.isRange) { -// val startLine = instr.pos.focusStart.line -// val endLine = instr.pos.focusEnd.line -// val startCol = instr.pos.focusStart.column -// val endCol = instr.pos.focusEnd.column -// mcode.setPosition(startLine, endLine, startCol, endCol, fileName) -// } else { -// mcode.setPosition(instr.pos.line, fileName) -// } -// lastLineNr = currentLineNr -// lastPos = instr.pos -// } -// } catch { case _: UnsupportedOperationException => () } -// -// if (previousWasNEW) -// assert(instr.isInstanceOf[DUP], block) -// -// instr match { -// case THIS(clasz) => -// mcode.Emit(OpCodes.Ldarg_0) -// -// case CONSTANT(const) => -// const.tag match { -// case UnitTag => () -// case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1 -// else OpCodes.Ldc_I4_0) -// case ByteTag => loadI4(const.byteValue, mcode) -// case ShortTag => loadI4(const.shortValue, mcode) -// case CharTag => loadI4(const.charValue, mcode) -// case IntTag => loadI4(const.intValue, mcode) -// case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue) -// case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue) -// case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue) -// case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue) -// case NullTag => mcode.Emit(OpCodes.Ldnull) -// case ClassTag => -// mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue)) -// mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE) -// case _ => abort("Unknown constant value: " + const) -// } -// -// case LOAD_ARRAY_ITEM(kind) => -// (kind: @unchecked) match { -// case BOOL => mcode.Emit(OpCodes.Ldelem_I1) -// case BYTE => mcode.Emit(OpCodes.Ldelem_I1) // I1 for System.SByte, i.e. a scala.Byte -// case SHORT => mcode.Emit(OpCodes.Ldelem_I2) -// case CHAR => mcode.Emit(OpCodes.Ldelem_U2) -// case INT => mcode.Emit(OpCodes.Ldelem_I4) -// case LONG => mcode.Emit(OpCodes.Ldelem_I8) -// case FLOAT => mcode.Emit(OpCodes.Ldelem_R4) -// case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8) -// case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref) -// case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref) -// -// // case UNIT is not possible: an Array[Unit] will be an -// // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) -// } -// -// case LOAD_LOCAL(local) => loadLocalOrAddress(local, "load_local", false) -// -// case CIL_LOAD_LOCAL_ADDRESS(local) => loadLocalOrAddress(local, "cil_load_local_address", true) -// -// case LOAD_FIELD(field, isStatic) => loadFieldOrAddress(field, isStatic, "load_field", false) -// -// case CIL_LOAD_FIELD_ADDRESS(field, isStatic) => loadFieldOrAddress(field, isStatic, "cil_load_field_address", true) -// -// case CIL_LOAD_ARRAY_ITEM_ADDRESS(kind) => mcode.Emit(OpCodes.Ldelema, msilType(kind)) -// -// case CIL_NEWOBJ(msym) => -// assert(msym.isClassConstructor) -// val constructorInfo: ConstructorInfo = getConstructor(msym) -// mcode.Emit(OpCodes.Newobj, constructorInfo) -// -// case LOAD_MODULE(module) => -// debuglog("Generating LOAD_MODULE for: " + showsym(module)) -// mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module)) -// -// case STORE_ARRAY_ITEM(kind) => -// (kind: @unchecked) match { -// case BOOL => mcode.Emit(OpCodes.Stelem_I1) -// case BYTE => mcode.Emit(OpCodes.Stelem_I1) -// case SHORT => mcode.Emit(OpCodes.Stelem_I2) -// case CHAR => mcode.Emit(OpCodes.Stelem_I2) -// case INT => mcode.Emit(OpCodes.Stelem_I4) -// case LONG => mcode.Emit(OpCodes.Stelem_I8) -// case FLOAT => mcode.Emit(OpCodes.Stelem_R4) -// case DOUBLE => mcode.Emit(OpCodes.Stelem_R8) -// case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref) -// case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method) -// -// // case UNIT not possible (see comment at LOAD_ARRAY_ITEM) -// } -// -// case STORE_LOCAL(local) => -// val isArg = local.arg -// val i = local.index -// debuglog("store_local for " + local + ", index " + i) -// -// // there are some locals defined by the compiler that -// // are isArg and are need to be stored. -// if (isArg) { -// if (i >= -128 && i <= 127) -// mcode.Emit(OpCodes.Starg_S, i) -// else -// mcode.Emit(OpCodes.Starg, i) -// } else { -// i match { -// case 0 => mcode.Emit(OpCodes.Stloc_0) -// case 1 => mcode.Emit(OpCodes.Stloc_1) -// case 2 => mcode.Emit(OpCodes.Stloc_2) -// case 3 => mcode.Emit(OpCodes.Stloc_3) -// case _ => -// if (i >= -128 && i <= 127) -// mcode.Emit(OpCodes.Stloc_S, localBuilders(local)) -// else -// mcode.Emit(OpCodes.Stloc, localBuilders(local)) -// } -// } -// -// case STORE_THIS(_) => -// // this only works for impl classes because the self parameter comes first -// // in the method signature. If that changes, this code has to be revisited. -// mcode.Emit(OpCodes.Starg_S, 0) -// -// case STORE_FIELD(field, isStatic) => -// val fieldInfo = fields.get(field) match { -// case Some(fInfo) => fInfo -// case None => -// val fInfo = getType(field.owner).GetField(msilName(field)) -// fields(field) = fInfo -// fInfo -// } -// mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo) -// -// case CALL_PRIMITIVE(primitive) => -// genPrimitive(primitive, instr.pos) -// -// case CALL_METHOD(msym, style) => -// if (msym.isClassConstructor) { -// val constructorInfo: ConstructorInfo = getConstructor(msym) -// (style: @unchecked) match { -// // normal constructor calls are Static.. -// case Static(_) => -// if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner) -// // we're generating a constructor (method: IMethod is a constructor), and we're -// // calling another constructor of the same class. -// -// // @LUC TODO: this can probably break, namely when having: class A { def this() { new A() } } -// // instead, we should instruct the CALL_METHOD with additional information, know whether it's -// // an instance creation constructor call or not. -// mcode.Emit(OpCodes.Call, constructorInfo) -// else -// mcode.Emit(OpCodes.Newobj, constructorInfo) -// case SuperCall(_) => -// mcode.Emit(OpCodes.Call, constructorInfo) -// if (isStaticModule(clasz.symbol) && -// notInitializedModules.contains(clasz.symbol) && -// method.symbol.isClassConstructor) -// { -// notInitializedModules -= clasz.symbol -// mcode.Emit(OpCodes.Ldarg_0) -// mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) -// } -// } -// -// } else { -// -// var doEmit = true -// getTypeOpt(msym.owner) match { -// case Some(typ) if (typ.IsEnum) => { -// def negBool() = { -// mcode.Emit(OpCodes.Ldc_I4_0) -// mcode.Emit(OpCodes.Ceq) -// } -// doEmit = false -// val name = msym.name -// if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) } -// else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool } -// else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) } -// else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool } -// else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) } -// else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool } -// else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) } -// else if (name eq nme.AND) { mcode.Emit(OpCodes.And) } -// else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) } -// else -// doEmit = true -// } -// case _ => () -// } -// -// // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType -// val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase) { -// msym.tpe match { -// case MethodType(params, resultType) -// if (params.length == 1 && msym.name == nme.view_) => -// val paramType = params(0).tpe -// val isDel = definitions.isCorrespondingDelegate(resultType, paramType) -// (isDel, paramType, resultType) -// case _ => (false, null, null) -// } -// } -// if (doEmit && isDelegateView) { -// doEmit = false -// createDelegateCaller(paramType, resType) -// } -// -// if (doEmit && -// (msym.name == nme.PLUS || msym.name == nme.MINUS) -// && clrTypes.isDelegateType(msilType(msym.owner.tpe))) -// { -// doEmit = false -// val methodInfo: MethodInfo = getMethod(msym) -// // call it as a static method, even if the compiler (symbol) thinks it's virtual -// mcode.Emit(OpCodes.Call, methodInfo) -// mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe)) -// } -// -// if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) { -// doEmit = false -// val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym) -// val delegateType: Type = msym.tpe match { -// case MethodType(_, retType) => retType -// case _ => abort("not a method type: " + msym.tpe) -// } -// val methodInfo: MethodInfo = getMethod(methodSym) -// val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) -// if (methodSym.isStatic) { -// mcode.Emit(OpCodes.Ldftn, methodInfo) -// } else { -// mcode.Emit(OpCodes.Dup) -// mcode.Emit(OpCodes.Ldvirtftn, methodInfo) -// } -// mcode.Emit(OpCodes.Newobj, delegCtor) -// } -// -// if (doEmit) { -// val methodInfo: MethodInfo = getMethod(msym) -// (style: @unchecked) match { -// case SuperCall(_) => -// mcode.Emit(OpCodes.Call, methodInfo) -// case Dynamic => -// // methodInfo.DeclaringType is null for global methods -// val isValuetypeMethod = (methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType) -// val isValuetypeVirtualMethod = isValuetypeMethod && (methodInfo.IsVirtual) -// if (dynToStatMapped(msym)) { -// mcode.Emit(OpCodes.Call, methodInfo) -// } else if (isValuetypeVirtualMethod) { -// mcode.Emit(OpCodes.Constrained, methodInfo.DeclaringType) -// mcode.Emit(OpCodes.Callvirt, methodInfo) -// } else if (isValuetypeMethod) { -// // otherwise error "Callvirt on a value type method" ensues -// mcode.Emit(OpCodes.Call, methodInfo) -// } else { -// mcode.Emit(OpCodes.Callvirt, methodInfo) -// } -// case Static(_) => -// if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) { -// mcode.Emit(OpCodes.Callvirt, methodInfo) -// } else mcode.Emit(OpCodes.Call, methodInfo) -// } -// } -// } -// -// case BOX(boxType) => -// emitBox(mcode, boxType) -// -// case UNBOX(boxType) => -// emitUnbox(mcode, boxType) -// -// case CIL_UNBOX(boxType) => -// mcode.Emit(OpCodes.Unbox, msilType(boxType)) -// -// case CIL_INITOBJ(valueType) => -// mcode.Emit(OpCodes.Initobj, msilType(valueType)) -// -// case NEW(REFERENCE(cls)) => -// // the next instruction must be a DUP, see comment on `var previousWasNEW` -// previousWasNEW = true -// -// // works also for arrays and reference-types -// case CREATE_ARRAY(elem, dims) => -// // TODO: handle multi dimensional arrays -// assert(dims == 1, "Can't handle multi dimensional arrays") -// mcode.Emit(OpCodes.Newarr, msilType(elem)) -// -// // works for arrays and reference-types -// case IS_INSTANCE(tpe) => -// mcode.Emit(OpCodes.Isinst, msilType(tpe)) -// mcode.Emit(OpCodes.Ldnull) -// mcode.Emit(OpCodes.Ceq) -// mcode.Emit(OpCodes.Ldc_I4_0) -// mcode.Emit(OpCodes.Ceq) -// -// // works for arrays and reference-types -// // part from the scala reference: "S <: T does not imply -// // Array[S] <: Array[T] in Scala. However, it is possible -// // to cast an array of S to an array of T if such a cast -// // is permitted in the host environment." -// case CHECK_CAST(tpknd) => -// val tMSIL = msilType(tpknd) -// mcode.Emit(OpCodes.Castclass, tMSIL) -// -// // no SWITCH is generated when there's -// // - a default case ("case _ => ...") in the matching expr -// // - OR is used ("case 1 | 2 => ...") -// case SWITCH(tags, branches) => -// // tags is List[List[Int]]; a list of integers for every label. -// // if the int on stack is 4, and 4 is in the second list => jump -// // to second label -// // branches is List[BasicBlock] -// // the labels to jump to (the last one is the default one) -// -// val switchLocal = mcode.DeclareLocal(MINT) -// // several switch variables will appear with the same name in the -// // assembly code, but this makes no truble -// switchLocal.SetLocalSymInfo("$switch_var") -// -// mcode.Emit(OpCodes.Stloc, switchLocal) -// var i = 0 -// for (l <- tags) { -// var targetLabel = labels(branches(i)) -// for (i <- l) { -// mcode.Emit(OpCodes.Ldloc, switchLocal) -// loadI4(i, mcode) -// mcode.Emit(OpCodes.Beq, targetLabel) -// } -// i += 1 -// } -// val defaultTarget = labels(branches(i)) -// if (next != branches(i)) -// mcode.Emit(OpCodes.Br, defaultTarget) -// -// case JUMP(whereto) => -// val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto) -// if (leaveHandler) { -// if (leaveFinally) { -// if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get) -// else mcode.Emit(OpCodes.Endfinally) -// } else -// mcode.Emit(OpCodes.Leave, labels(whereto)) -// } else if (next != whereto) -// mcode.Emit(OpCodes.Br, labels(whereto)) -// -// case CJUMP(success, failure, cond, kind) => -// // cond is TestOp (see Primitives.scala), and can take -// // values EQ, NE, LT, GE LE, GT -// // kind is TypeKind -// val isFloat = kind == FLOAT || kind == DOUBLE -// val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat) -// emitCondBr(block, cond, success, failure, next, emit) -// -// case CZJUMP(success, failure, cond, kind) => -// emitCondBr(block, cond, success, failure, next, emitBrBool(_, _)) -// -// case RETURN(kind) => -// if (currentHandlers.isEmpty) -// mcode.Emit(OpCodes.Ret) -// else { -// val (local, label) = returnFromHandler(kind) -// if (kind != UNIT) -// mcode.Emit(OpCodes.Stloc, local) -// mcode.Emit(OpCodes.Leave, label) -// } -// -// case THROW(_) => -// mcode.Emit(OpCodes.Throw) -// -// case DROP(kind) => -// mcode.Emit(OpCodes.Pop) -// -// case DUP(kind) => -// // see comment on `var previousWasNEW` -// if (!previousWasNEW) -// mcode.Emit(OpCodes.Dup) -// else -// previousWasNEW = false -// -// case MONITOR_ENTER() => -// mcode.Emit(OpCodes.Call, MMONITOR_ENTER) -// -// case MONITOR_EXIT() => -// mcode.Emit(OpCodes.Call, MMONITOR_EXIT) -// -// case SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION(_) => -// () -// } -// -// } // end for (instr <- b) { .. } -// } // end genBlock -// -// def genPrimitive(primitive: Primitive, pos: Position) { -// primitive match { -// case Negation(kind) => -// kind match { -// // CHECK: is ist possible to get this for BOOL? in this case, verify. -// case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE => -// mcode.Emit(OpCodes.Neg) -// -// case _ => abort("Impossible to negate a " + kind) -// } -// -// case Arithmetic(op, kind) => -// op match { -// case ADD => mcode.Emit(OpCodes.Add) -// case SUB => mcode.Emit(OpCodes.Sub) -// case MUL => mcode.Emit(OpCodes.Mul) -// case DIV => mcode.Emit(OpCodes.Div) -// case REM => mcode.Emit(OpCodes.Rem) -// case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement) -// case _ => abort("Unknown arithmetic primitive " + primitive ) -// } -// -// case Logical(op, kind) => op match { -// case AND => mcode.Emit(OpCodes.And) -// case OR => mcode.Emit(OpCodes.Or) -// case XOR => mcode.Emit(OpCodes.Xor) -// } -// -// case Shift(op, kind) => op match { -// case LSL => mcode.Emit(OpCodes.Shl) -// case ASR => mcode.Emit(OpCodes.Shr) -// case LSR => mcode.Emit(OpCodes.Shr_Un) -// } -// -// case Conversion(src, dst) => -// debuglog("Converting from: " + src + " to: " + dst) -// -// dst match { -// case BYTE => mcode.Emit(OpCodes.Conv_I1) // I1 for System.SByte, i.e. a scala.Byte -// case SHORT => mcode.Emit(OpCodes.Conv_I2) -// case CHAR => mcode.Emit(OpCodes.Conv_U2) -// case INT => mcode.Emit(OpCodes.Conv_I4) -// case LONG => mcode.Emit(OpCodes.Conv_I8) -// case FLOAT => mcode.Emit(OpCodes.Conv_R4) -// case DOUBLE => mcode.Emit(OpCodes.Conv_R8) -// case _ => -// Console.println("Illegal conversion at: " + clasz + -// " at: " + pos.source + ":" + pos.line) -// } -// -// case ArrayLength(_) => -// mcode.Emit(OpCodes.Ldlen) -// -// case StartConcat => -// mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR) -// -// -// case StringConcat(el) => -// val elemType : MsilType = el match { -// case REFERENCE(_) | ARRAY(_) => MOBJECT -// case _ => msilType(el) -// } -// -// val argTypes:Array[MsilType] = Array(elemType) -// val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes ) -// mcode.Emit(OpCodes.Callvirt, stringBuilderAppend) -// -// case EndConcat => -// mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING) -// -// case _ => -// abort("Unimplemented primitive " + primitive) -// } -// } // end genPrimitive -// -// -// ////////////////////// loading /////////////////////// -// -// def loadI4(value: Int, code: ILGenerator): Unit = value match { -// case -1 => code.Emit(OpCodes.Ldc_I4_M1) -// case 0 => code.Emit(OpCodes.Ldc_I4_0) -// case 1 => code.Emit(OpCodes.Ldc_I4_1) -// case 2 => code.Emit(OpCodes.Ldc_I4_2) -// case 3 => code.Emit(OpCodes.Ldc_I4_3) -// case 4 => code.Emit(OpCodes.Ldc_I4_4) -// case 5 => code.Emit(OpCodes.Ldc_I4_5) -// case 6 => code.Emit(OpCodes.Ldc_I4_6) -// case 7 => code.Emit(OpCodes.Ldc_I4_7) -// case 8 => code.Emit(OpCodes.Ldc_I4_8) -// case _ => -// if (value >= -128 && value <= 127) -// code.Emit(OpCodes.Ldc_I4_S, value) -// else -// code.Emit(OpCodes.Ldc_I4, value) -// } -// -// def loadArg(code: ILGenerator, loadAddr: Boolean)(i: Int) = -// if (loadAddr) { -// if (i >= -128 && i <= 127) -// code.Emit(OpCodes.Ldarga_S, i) -// else -// code.Emit(OpCodes.Ldarga, i) -// } else { -// i match { -// case 0 => code.Emit(OpCodes.Ldarg_0) -// case 1 => code.Emit(OpCodes.Ldarg_1) -// case 2 => code.Emit(OpCodes.Ldarg_2) -// case 3 => code.Emit(OpCodes.Ldarg_3) -// case _ => -// if (i >= -128 && i <= 127) -// code.Emit(OpCodes.Ldarg_S, i) -// else -// code.Emit(OpCodes.Ldarg, i) -// } -// } -// -// def loadLocal(i: Int, local: Local, code: ILGenerator, loadAddr: Boolean) = -// if (loadAddr) { -// if (i >= -128 && i <= 127) -// code.Emit(OpCodes.Ldloca_S, localBuilders(local)) -// else -// code.Emit(OpCodes.Ldloca, localBuilders(local)) -// } else { -// i match { -// case 0 => code.Emit(OpCodes.Ldloc_0) -// case 1 => code.Emit(OpCodes.Ldloc_1) -// case 2 => code.Emit(OpCodes.Ldloc_2) -// case 3 => code.Emit(OpCodes.Ldloc_3) -// case _ => -// if (i >= -128 && i <= 127) -// code.Emit(OpCodes.Ldloc_S, localBuilders(local)) -// else -// code.Emit(OpCodes.Ldloc, localBuilders(local)) -// } -// } -// -// ////////////////////// branches /////////////////////// -// -// /** Returns a Triple (Boolean, Boolean, Option[Label]) -// * - whether the jump leaves some exception block (try / catch / finally) -// * - whether it leaves a finally handler (finally block, but not it's try / catch) -// * - a label where to jump for leaving the finally handler -// * . None to leave directly using `endfinally` -// * . Some(label) to emit `leave label` (for try / catch inside a finally handler) -// */ -// def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) = -// if (currentHandlers.isEmpty) (false, false, None) -// else { -// val h = currentHandlers.head -// val leaveHead = { h.covers(from) != h.covers(to) || -// h.blocks.contains(from) != h.blocks.contains(to) } -// if (leaveHead) { -// // we leave the innermost exception block. -// // find out if we also leave som e `finally` handler -// currentHandlers.find(e => { -// e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to) -// }) match { -// case Some(finallyHandler) => -// if (h == finallyHandler) { -// // the finally handler is the innermost, so we can emit `endfinally` directly -// (true, true, None) -// } else { -// // we need to `Leave` to the `endfinally` of the next outer finally handler -// val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel()) -// (true, true, Some(l)) -// } -// case None => -// (true, false, None) -// } -// } else (false, false, None) -// } -// -// def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock, -// next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) { -// val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success) -// val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure) -// -// if (sLeaveHandler || fLeaveHandler) { -// val sLabelOpt = if (sLeaveHandler) { -// val leaveSLabel = mcode.DefineLabel() -// emitBrFun(cond, leaveSLabel) -// Some(leaveSLabel) -// } else { -// emitBrFun(cond, labels(success)) -// None -// } -// -// if (fLeaveHandler) { -// if (fLeaveFinally) { -// if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get) -// else mcode.Emit(OpCodes.Endfinally) -// } else -// mcode.Emit(OpCodes.Leave, labels(failure)) -// } else -// mcode.Emit(OpCodes.Br, labels(failure)) -// -// sLabelOpt.map(l => { -// mcode.MarkLabel(l) -// if (sLeaveFinally) { -// if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get) -// else mcode.Emit(OpCodes.Endfinally) -// } else -// mcode.Emit(OpCodes.Leave, labels(success)) -// }) -// } else { -// if (next == success) { -// emitBrFun(cond.negate, labels(failure)) -// } else { -// emitBrFun(cond, labels(success)) -// if (next != failure) { -// mcode.Emit(OpCodes.Br, labels(failure)) -// } -// } -// } -// } -// -// def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) { -// condition match { -// case EQ => mcode.Emit(OpCodes.Beq, dest) -// case NE => mcode.Emit(OpCodes.Bne_Un, dest) -// case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest) -// case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest) -// case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest) -// case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest) -// } -// } -// -// def emitBrBool(cond: TestOp, dest: Label) { -// cond match { -// // EQ -> Brfalse, NE -> Brtrue; this is because we come from -// // a CZJUMP. If the value on the stack is 0 (e.g. a boolean -// // method returned false), and we are in the case EQ, then -// // we need to emit Brfalse (EQ Zero means false). vice versa -// case EQ => mcode.Emit(OpCodes.Brfalse, dest) -// case NE => mcode.Emit(OpCodes.Brtrue, dest) -// } -// } -// -// ////////////////////// local vars /////////////////////// -// -// /** -// * Compute the indexes of each local variable of the given -// * method. -// */ -// def computeLocalVarsIndex(m: IMethod) { -// var idx = if (m.symbol.isStaticMember) 0 else 1 -// -// val params = m.params -// for (l <- params) { -// debuglog("Index value for parameter " + l + ": " + idx) -// l.index = idx -// idx += 1 // sizeOf(l.kind) -// } -// -// val locvars = m.locals filterNot (params contains) -// idx = 0 -// -// for (l <- locvars) { -// debuglog("Index value for local variable " + l + ": " + idx) -// l.index = idx -// idx += 1 // sizeOf(l.kind) -// } -// -// } -// -// ////////////////////// Utilities //////////////////////// -// -// /** Return the a name of this symbol that can be used on the .NET -// * platform. It removes spaces from names. -// * -// * Special handling: scala.All and scala.AllRef are 'erased' to -// * scala.All$ and scala.AllRef$. This is needed because they are -// * not real classes, and they mean 'abrupt termination upon evaluation -// * of that expression' or 'null' respectively. This handling is -// * done already in GenICode, but here we need to remove references -// * from method signatures to these types, because such classes can -// * not exist in the classpath: the type checker will be very confused. -// */ -// def msilName(sym: Symbol): String = { -// val suffix = sym.moduleSuffix -// // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class) -// -// if (sym == definitions.NothingClass) -// return "scala.runtime.Nothing$" -// else if (sym == definitions.NullClass) -// return "scala.runtime.Null$" -// -// (if (sym.isClass || (sym.isModule && !sym.isMethod)) { -// if (sym.isNestedClass) sym.simpleName -// else sym.fullName -// } else -// sym.simpleName.toString.trim()) + suffix -// } -// -// -// ////////////////////// flags /////////////////////// -// -// def msilTypeFlags(sym: Symbol): Int = { -// var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass -// -// if(sym.isNestedClass) { -// mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NestedPrivate else TypeAttributes.NestedPublic) -// } else { -// mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public) -// } -// mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0) -// mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class) -// mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) -// -// sym.annotations foreach { a => a match { -// case AnnotationInfo(SerializableAttr, _, _) => -// // TODO: add the Serializable TypeAttribute also if the annotation -// // System.SerializableAttribute is present (.net annotation, not scala) -// // Best way to do it: compare with -// // definitions.getClass("System.SerializableAttribute").tpe -// // when frontend available -// mf = mf | TypeAttributes.Serializable -// case _ => () -// }} -// -// mf -// // static: not possible (or?) -// } -// -// def msilMethodFlags(sym: Symbol): Short = { -// var mf: Int = MethodAttributes.HideBySig | -// (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private -// else MethodAttributes.Public) -// -// if (!sym.isClassConstructor) { -// if (sym.isStaticMember) -// mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ... -// else { -// mf = mf | MethodAttributes.Virtual -// if (sym.isFinal && !getType(sym.owner).IsInterface) -// mf = mf | MethodAttributes.Final -// if (sym.isDeferred || getType(sym.owner).IsInterface) -// mf = mf | MethodAttributes.Abstract -// } -// } -// -// if (sym.isStaticMember) { -// mf = mf | MethodAttributes.Static -// } -// -// // constructors of module classes should be private -// if (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) { -// mf |= MethodAttributes.Private -// mf &= ~(MethodAttributes.Public) -// } -// -// mf.toShort -// } -// -// def msilFieldFlags(sym: Symbol): Short = { -// var mf: Int = -// if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private -// else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem -// else FieldAttributes.Public -// -// if (sym hasFlag Flags.FINAL) -// mf = mf | FieldAttributes.InitOnly -// -// if (sym.isStaticMember) -// mf = mf | FieldAttributes.Static -// -// // TRANSIENT: "not serialized", VOLATILE: doesn't exist on .net -// // TODO: add this annotation also if the class has the custom attribute -// // System.NotSerializedAttribute -// sym.annotations.foreach( a => a match { -// case AnnotationInfo(TransientAtt, _, _) => -// mf = mf | FieldAttributes.NotSerialized -// case _ => () -// }) -// -// mf.toShort -// } -// -// ////////////////////// builders, types /////////////////////// -// -// var entryPoint: Symbol = _ -// -// val notInitializedModules = mutable.HashSet[Symbol]() -// -// // TODO: create fields also in def createType, and not in genClass, -// // add a getField method (it only works as it is because fields never -// // accessed from outside a class) -// -// val localBuilders = mutable.HashMap[Local, LocalBuilder]() -// -// private[GenMSIL] def findEntryPoint(cls: IClass) { -// -// def isEntryPoint(sym: Symbol):Boolean = { -// if (isStaticModule(sym.owner) && msilName(sym) == "main") -// if (sym.tpe.paramTypes.length == 1) { -// toTypeKind(sym.tpe.paramTypes(0)) match { -// case ARRAY(elem) => -// if (elem.toType.typeSymbol == definitions.StringClass) { -// return true -// } -// case _ => () -// } -// } -// false -// } -// -// if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead -// val entryclass = opt.showClass.get.toString -// val cfn = cls.symbol.fullName -// if(cfn == entryclass) { -// for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol } -// if(entryPoint == null) { warning("Couldn't find main method in class " + cfn) } -// } -// } -// -// if (firstSourceName == "") -// if (cls.symbol.sourceFile != null) // is null for nested classes -// firstSourceName = cls.symbol.sourceFile.name -// } -// -// // ##################################################################### -// // get and create types -// -// private def msilType(t: TypeKind): MsilType = (t: @unchecked) match { -// case UNIT => MVOID -// case BOOL => MBOOL -// case BYTE => MBYTE -// case SHORT => MSHORT -// case CHAR => MCHAR -// case INT => MINT -// case LONG => MLONG -// case FLOAT => MFLOAT -// case DOUBLE => MDOUBLE -// case REFERENCE(cls) => getType(cls) -// case ARRAY(elem) => -// msilType(elem) match { -// // For type builders, cannot call "clrTypes.mkArrayType" because this looks up -// // the type "tp" in the assembly (not in the HashMap "types" of the backend). -// // This can fail for nested types because the builders are not complete yet. -// case tb: TypeBuilder => tb.MakeArrayType() -// case tp: MsilType => clrTypes.mkArrayType(tp) -// } -// } -// -// private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe)) -// -// private def msilParamTypes(sym: Symbol): Array[MsilType] = { -// sym.tpe.paramTypes.map(msilType).toArray -// } -// -// def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym))) -// -// /** -// * Get an MSIL type from a symbol. First look in the clrTypes.types map, then -// * lookup the name using clrTypes.getType -// */ -// def getTypeOpt(sym: Symbol): Option[MsilType] = { -// val tmp = types.get(sym) -// tmp match { -// case typ @ Some(_) => typ -// case None => -// def typeString(sym: Symbol): String = { -// val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName -// else sym.fullName -// if (sym.isModuleClass && !sym.isTrait) s + "$" else s -// } -// val name = typeString(sym) -// val typ = clrTypes.getType(name) -// if (typ == null) -// None -// else { -// types(sym) = typ -// Some(typ) -// } -// } -// } -// -// def mapType(sym: Symbol, mType: MsilType) { -// assert(mType != null, showsym(sym)) -// types(sym) = mType -// } -// -// def createTypeBuilder(iclass: IClass) { -// /** -// * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise -// * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)). -// */ -// def msilTypeFromSym(sym: Symbol): MsilType = { -// types.get(sym).getOrElse { -// classes.get(sym) match { -// case Some(iclass) => -// msilTypeBuilderFromSym(sym) -// case None => -// getType(sym) -// } -// } -// } -// -// def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = { -// if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){ -// val iclass = classes(sym) -// assert(iclass != null) -// createTypeBuilder(iclass) -// } -// types(sym).asInstanceOf[TypeBuilder] -// } -// -// val sym = iclass.symbol -// if (types.contains(sym) && types(sym).isInstanceOf[TypeBuilder]) -// return -// -// def isInterface(s: Symbol) = s.isTrait && !s.isImplClass -// val parents: List[Type] = -// if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe) -// else sym.info.parents.distinct -// -// val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol) -// debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType) -// -// val interfaces: Array[MsilType] = -// parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray -// if (parents.length > 1) { -// if (settings.debug.value) { -// log("interfaces:") -// for (i <- 0.until(interfaces.length)) { -// log(" type: " + parents(i + 1).typeSymbol + ", msil type: " + interfaces(i)) -// } -// } -// } -// -// val tBuilder = if (sym.isNestedClass) { -// val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder] -// ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces) -// } else { -// mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces) -// } -// mapType(sym, tBuilder) -// } // createTypeBuilder -// -// def createClassMembers(iclass: IClass) { -// try { -// createClassMembers0(iclass) -// } -// catch { -// case e: Throwable => -// java.lang.System.err.println(showsym(iclass.symbol)) -// java.lang.System.err.println("with methods = " + iclass.methods) -// throw e -// } -// } -// -// def createClassMembers0(iclass: IClass) { -// -// val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder] -// -// for (ifield <- iclass.fields) { -// val sym = ifield.symbol -// debuglog("Adding field: " + sym.fullName) -// -// var attributes = msilFieldFlags(sym) -// val fieldTypeWithCustomMods = -// new PECustomMod(msilType(sym.tpe), -// customModifiers(sym.annotations)) -// val fBuilder = mtype.DefineField(msilName(sym), -// fieldTypeWithCustomMods, -// attributes) -// fields(sym) = fBuilder -// addAttributes(fBuilder, sym.annotations) -// } // all iclass.fields iterated over -// -// if (isStaticModule(iclass.symbol)) { -// val sc = iclass.lookupStaticCtor -// if (sc.isDefined) { -// val m = sc.get -// val oldLastBlock = m.lastBlock -// val lastBlock = m.newBlock() -// oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock)) -// // call object's private ctor from static ctor -// lastBlock.emit(CIL_NEWOBJ(iclass.symbol.primaryConstructor)) -// lastBlock.emit(DROP(toTypeKind(iclass.symbol.tpe))) -// lastBlock emit RETURN(UNIT) -// lastBlock.close -// } -// } -// -// if (iclass.symbol != definitions.ArrayClass) { -// for (m: IMethod <- iclass.methods) { -// val sym = m.symbol -// debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " + -// sym.owner.fullName + "::" + sym.name) -// -// val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder] -// assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType) -// var paramTypes = msilParamTypes(sym) -// val attr = msilMethodFlags(sym) -// -// if (m.symbol.isClassConstructor) { -// val constr = -// ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes) -// for (i <- 0.until(paramTypes.length)) { -// constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) -// } -// mapConstructor(sym, constr) -// addAttributes(constr, sym.annotations) -// } else { -// var resType = msilType(m.returnType) -// val method = -// ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes) -// for (i <- 0.until(paramTypes.length)) { -// method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) -// } -// if (!methods.contains(sym)) -// mapMethod(sym, method) -// addAttributes(method, sym.annotations) -// debuglog("\t created MethodBuilder " + method) -// } -// } -// } // method builders created for non-array iclass -// -// if (isStaticModule(iclass.symbol)) { -// addModuleInstanceField(iclass.symbol) -// notInitializedModules += iclass.symbol -// if (iclass.lookupStaticCtor.isEmpty) { -// addStaticInit(iclass.symbol) -// } -// } -// -// } // createClassMembers0 -// -// private def isTopLevelModule(sym: Symbol): Boolean = -// atPhase (currentRun.refchecksPhase) { -// sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass -// } -// -// // if the module is lifted it does not need to be initialized in -// // its static constructor, and the MODULE$ field is not required. -// // the outer class will care about it. -// private def isStaticModule(sym: Symbol): Boolean = { -// // .net inner classes: removed '!sym.hasFlag(Flags.LIFTED)', added -// // 'sym.isStatic'. -> no longer compatible without skipping flatten! -// sym.isModuleClass && sym.isStatic && !sym.isImplClass -// } -// -// private def isCloneable(sym: Symbol): Boolean = { -// !sym.annotations.forall( a => a match { -// case AnnotationInfo(CloneableAttr, _, _) => false -// case _ => true -// }) -// } -// -// private def addModuleInstanceField(sym: Symbol) { -// debuglog("Adding Module-Instance Field for " + showsym(sym)) -// val tBuilder = getType(sym).asInstanceOf[TypeBuilder] -// val fb = tBuilder.DefineField(MODULE_INSTANCE_NAME, -// tBuilder, -// (FieldAttributes.Public | -// //FieldAttributes.InitOnly | -// FieldAttributes.Static).toShort) -// fields(sym) = fb -// } -// -// -// // the symbol may be a object-symbol (module-symbol), or a module-class-symbol -// private def getModuleInstanceField(sym: Symbol): FieldInfo = { -// assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym)) -// -// // when called by LOAD_MODULE, the corresponding type maybe doesn't -// // exist yet -> make a getType -// val moduleClassSym = if (sym.isModule) sym.moduleClass else sym -// -// // TODO: get module field for modules not defined in the -// // source currently compiling (e.g. Console) -// -// fields get moduleClassSym match { -// case Some(sym) => sym -// case None => -// //val mclass = types(moduleClassSym) -// val nameInMetadata = nestingAwareFullClassname(moduleClassSym) -// val mClass = clrTypes.getType(nameInMetadata) -// val mfield = mClass.GetField("MODULE$") -// assert(mfield ne null, "module not found " + showsym(moduleClassSym)) -// fields(moduleClassSym) = mfield -// mfield -// } -// -// //fields(moduleClassSym) -// } -// -// def nestingAwareFullClassname(csym: Symbol) : String = { -// val suffix = csym.moduleSuffix -// val res = if (csym.isNestedClass) -// nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName -// else -// csym.fullName -// res + suffix -// } -// -// /** Adds a static initializer which creates an instance of the module -// * class (calls the primary constructor). A special primary constructor -// * will be generated (notInitializedModules) which stores the new instance -// * in the MODULE$ field right after the super call. -// */ -// private def addStaticInit(sym: Symbol) { -// val tBuilder = getType(sym).asInstanceOf[TypeBuilder] -// -// val staticInit = tBuilder.DefineConstructor( -// (MethodAttributes.Static | MethodAttributes.Public).toShort, -// CallingConventions.Standard, -// MsilType.EmptyTypes) -// -// val sicode = staticInit.GetILGenerator() -// -// val instanceConstructor = constructors(sym.primaryConstructor) -// -// // there are no constructor parameters. assuming the constructor takes no parameter -// // is fine: we call (in the static constructor) the constructor of the module class, -// // which takes no arguments - an object definition cannot take constructor arguments. -// sicode.Emit(OpCodes.Newobj, instanceConstructor) -// // the stsfld is done in the instance constructor, just after the super call. -// sicode.Emit(OpCodes.Pop) -// -// sicode.Emit(OpCodes.Ret) -// } -// -// private def generateMirrorClass(sym: Symbol) { -// val tBuilder = getType(sym) -// assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym) -// debuglog("Dumping mirror class for object: " + sym) -// val moduleName = msilName(sym) -// val mirrorName = moduleName.substring(0, moduleName.length() - 1) -// val mirrorTypeBuilder = mmodule.DefineType(mirrorName, -// TypeAttributes.Class | -// TypeAttributes.Public | -// TypeAttributes.Sealed, -// MOBJECT, -// MsilType.EmptyTypes) -// -// val iclass = classes(sym) -// -// for (m <- sym.tpe.nonPrivateMembers -// if m.owner != definitions.ObjectClass && !m.isProtected && -// m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase && -// !m.isDeferred) -// { -// debuglog(" Mirroring method: " + m) -// val paramTypes = msilParamTypes(m) -// val paramNames: Array[String] = new Array[String](paramTypes.length) -// for (i <- 0 until paramTypes.length) -// paramNames(i) = "x_" + i -// -// // CHECK: verify if getMethodName is better than msilName -// val mirrorMethod = mirrorTypeBuilder.DefineMethod(msilName(m), -// (MethodAttributes.Public | -// MethodAttributes.Static).toShort, -// msilType(m.tpe.resultType), -// paramTypes) -// -// var i = 0 -// while (i < paramTypes.length) { -// mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i)) -// i += 1 -// } -// -// val mirrorCode = mirrorMethod.GetILGenerator() -// mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym)) -// val mInfo = getMethod(m) -// for (paramidx <- 0.until(paramTypes.length)) { -// val mInfoParams = mInfo.GetParameters -// val loadAddr = mInfoParams(paramidx).ParameterType.IsByRef -// loadArg(mirrorCode, loadAddr)(paramidx) -// } -// -// mirrorCode.Emit(OpCodes.Callvirt, getMethod(m)) -// mirrorCode.Emit(OpCodes.Ret) -// } -// -// addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder) -// -// mirrorTypeBuilder.CreateType() -// mirrorTypeBuilder.setSourceFilepath(iclass.cunit.source.file.path) -// } -// -// -// // ##################################################################### -// // delegate callers -// -// var delegateCallers: TypeBuilder = _ -// var nbDelegateCallers: Int = 0 -// -// private def initDelegateCallers() = { -// delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public | -// TypeAttributes.Sealed) -// } -// -// private def createDelegateCaller(functionType: Type, delegateType: Type) = { -// if (delegateCallers == null) -// initDelegateCallers() -// // create a field an store the function-object -// val mFunctionType: MsilType = msilType(functionType) -// val anonfunField: FieldBuilder = delegateCallers.DefineField( -// "$anonfunField$$" + nbDelegateCallers, mFunctionType, -// (FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static).toShort) -// mcode.Emit(OpCodes.Stsfld, anonfunField) -// -// -// // create the static caller method and the delegate object -// val (params, returnType) = delegateType.member(nme.apply).tpe match { -// case MethodType(delParams, delReturn) => (delParams, delReturn) -// case _ => abort("not a delegate type: " + delegateType) -// } -// val caller: MethodBuilder = delegateCallers.DefineMethod( -// "$delegateCaller$$" + nbDelegateCallers, -// (MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static).toShort, -// msilType(returnType), (params map (_.tpe)).map(msilType).toArray) -// for (i <- 0 until params.length) -// caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol -// val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) -// mcode.Emit(OpCodes.Ldnull) -// mcode.Emit(OpCodes.Ldftn, caller) -// mcode.Emit(OpCodes.Newobj, delegCtor) -// -// -// // create the static caller method body -// val functionApply: MethodInfo = getMethod(functionType.member(nme.apply)) -// val dcode: ILGenerator = caller.GetILGenerator() -// dcode.Emit(OpCodes.Ldsfld, anonfunField) -// for (i <- 0 until params.length) { -// loadArg(dcode, false /* TODO confirm whether passing actual as-is to formal is correct wrt the ByRef attribute of the param */)(i) -// emitBox(dcode, toTypeKind(params(i).tpe)) -// } -// dcode.Emit(OpCodes.Callvirt, functionApply) -// emitUnbox(dcode, toTypeKind(returnType)) -// dcode.Emit(OpCodes.Ret) -// -// nbDelegateCallers = nbDelegateCallers + 1 -// -// } //def createDelegateCaller -// -// def emitBox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { -// // doesn't make sense, unit as parameter.. -// case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit) -// case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE => -// code.Emit(OpCodes.Box, msilType(boxType)) -// case REFERENCE(cls) if clrTypes.isValueType(cls) => -// code.Emit(OpCodes.Box, (msilType(boxType))) -// case REFERENCE(_) | ARRAY(_) => -// warning("Tried to BOX a non-valuetype.") -// () -// } -// -// def emitUnbox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { -// case UNIT => code.Emit(OpCodes.Pop) -// /* (1) it's essential to keep the code emitted here (as of now plain calls to System.Convert.ToBlaBla methods) -// behaviorally.equiv.wrt. BoxesRunTime.unboxToBlaBla methods -// (case null: that's easy, case boxed: track changes to unboxBlaBla) -// (2) See also: asInstanceOf to cast from Any to number, -// tracked in http://lampsvn.epfl.ch/trac/scala/ticket/4437 */ -// case BOOL => code.Emit(OpCodes.Call, toBool) -// case BYTE => code.Emit(OpCodes.Call, toSByte) -// case SHORT => code.Emit(OpCodes.Call, toShort) -// case CHAR => code.Emit(OpCodes.Call, toChar) -// case INT => code.Emit(OpCodes.Call, toInt) -// case LONG => code.Emit(OpCodes.Call, toLong) -// case FLOAT => code.Emit(OpCodes.Call, toFloat) -// case DOUBLE => code.Emit(OpCodes.Call, toDouble) -// case REFERENCE(cls) if clrTypes.isValueType(cls) => -// code.Emit(OpCodes.Unbox, msilType(boxType)) -// code.Emit(OpCodes.Ldobj, msilType(boxType)) -// case REFERENCE(_) | ARRAY(_) => -// warning("Tried to UNBOX a non-valuetype.") -// () -// } -// -// // ##################################################################### -// // get and create methods / constructors -// -// def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match { -// case Some(constr) => constr -// case None => -// val mClass = getType(sym.owner) -// val constr = mClass.GetConstructor(msilParamTypes(sym)) -// if (constr eq null) { -// java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name) -// java.lang.System.out.println("scope = " + sym.owner.tpe.decls) -// abort(sym.fullName) -// } -// else { -// mapConstructor(sym, constr) -// constr -// } -// } -// -// def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = { -// constructors(sym) = cInfo -// } -// -// private def getMethod(sym: Symbol): MethodInfo = { -// -// methods.get(sym) match { -// case Some(method) => method -// case None => -// val mClass = getType(sym.owner) -// try { -// val method = mClass.GetMethod(msilName(sym), msilParamTypes(sym), -// msilType(sym.tpe.resultType)) -// if (method eq null) { -// java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym)) -// java.lang.System.out.println("scope = " + sym.owner.tpe.decls) -// abort(sym.fullName) -// } -// else { -// mapMethod(sym, method) -// method -// } -// } -// catch { -// case e: Exception => -// Console.println("While looking up " + mClass + "::" + sym.nameString) -// Console.println("\t" + showsym(sym)) -// throw e -// } -// } -// } -// -// /* -// * add a mapping between sym and mInfo -// */ -// private def mapMethod(sym: Symbol, mInfo: MethodInfo) { -// assert (mInfo != null, mInfo) -// methods(sym) = mInfo -// } -// -// /* -// * add mapping between sym and method with newName, paramTypes of newClass -// */ -// private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) { -// val methodInfo = newClass.GetMethod(newName, paramTypes) -// assert(methodInfo != null, "Can't find mapping for " + sym + " -> " + -// newName + "(" + paramTypes + ")") -// mapMethod(sym, methodInfo) -// if (methodInfo.IsStatic) -// dynToStatMapped += sym -// } -// -// /* -// * add mapping between method with name and paramTypes of clazz to -// * method with newName and newParamTypes of newClass (used for instance -// * for "wait") -// */ -// private def mapMethod( -// clazz: Symbol, name: Name, paramTypes: Array[Type], -// newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) { -// val methodSym = lookupMethod(clazz, name, paramTypes) -// assert(methodSym != null, "cannot find method " + name + "(" + -// paramTypes + ")" + " in class " + clazz) -// mapMethod(methodSym, newClass, newName, newParamTypes) -// } -// -// /* -// * add mapping for member with name and paramTypes to member -// * newName of newClass (same parameters) -// */ -// private def mapMethod( -// clazz: Symbol, name: Name, paramTypes: Array[Type], -// newClass: MsilType, newName: String) { -// mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) -// } -// -// /* -// * add mapping for all methods with name of clazz to the corresponding -// * method (same parameters) with newName of newClass -// */ -// private def mapMethod( -// clazz: Symbol, name: Name, -// newClass: MsilType, newName: String) { -// val memberSym: Symbol = clazz.tpe.member(name) -// memberSym.tpe match { -// // alternatives: List[Symbol] -// case OverloadedType(_, alternatives) => -// alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s))) -// -// // paramTypes: List[Type], resType: Type -// case MethodType(params, resType) => -// mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) -// -// case _ => -// abort("member not found: " + clazz + ", " + name) -// } -// } -// -// -// /* -// * find the method in clazz with name and paramTypes -// */ -// private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = { -// val memberSym = clazz.tpe.member(name) -// memberSym.tpe match { -// case OverloadedType(_, alternatives) => -// alternatives.find(s => { -// var i: Int = 0 -// var typesOK: Boolean = true -// if (paramTypes.length == s.tpe.paramTypes.length) { -// while(i < paramTypes.length) { -// if (paramTypes(i) != s.tpe.paramTypes(i)) -// typesOK = false -// i += 1 -// } -// } else { -// typesOK = false -// } -// typesOK -// }) match { -// case Some(sym) => sym -// case None => abort("member of " + clazz + ", " + name + "(" + -// paramTypes + ") not found") -// } -// -// case MethodType(_, _) => memberSym -// -// case _ => abort("member not found: " + name + " of " + clazz) -// } -// } -// -// private def showsym(sym: Symbol): String = (sym.toString + -// "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym + -// "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner -// ) -// -// } // class BytecodeGenerator -// -// } // class GenMSIL + +abstract class GenMSIL /*extends SubComponent { + import global._ + import loaders.clrTypes + import clrTypes.{types, constructors, methods, fields} + import icodes._ + import icodes.opcodes._ + + val x = loaders + + /** Create a new phase */ + override def newPhase(p: Phase) = new MsilPhase(p) + + val phaseName = "msil" + /** MSIL code generation phase + */ + class MsilPhase(prev: Phase) extends GlobalPhase(prev) { + def name = phaseName + override def newFlags = phaseNewFlags + + override def erasedTypes = true + + override def run() { + if (settings.debug.value) inform("[running phase " + name + " on icode]") + + val codeGenerator = new BytecodeGenerator + + //classes is ICodes.classes, a HashMap[Symbol, IClass] + classes.values foreach codeGenerator.findEntryPoint + if( opt.showClass.isDefined && (codeGenerator.entryPoint == null) ) { // TODO introduce dedicated setting instead + val entryclass = opt.showClass.get.toString + warning("Couldn't find entry class " + entryclass) + } + + codeGenerator.initAssembly + + val classesSorted = classes.values.toList.sortBy(c => c.symbol.id) // simplifies comparing cross-compiler vs. .exe output + classesSorted foreach codeGenerator.createTypeBuilder + classesSorted foreach codeGenerator.createClassMembers + + try { + classesSorted foreach codeGenerator.genClass + } finally { + codeGenerator.writeAssembly + } + } + + override def apply(unit: CompilationUnit) { + abort("MSIL works on icode classes, not on compilation units!") + } + } + + /** + * MSIL bytecode generator. + * + */ + class BytecodeGenerator { + + val MODULE_INSTANCE_NAME = "MODULE$" + + import clrTypes.{VOID => MVOID, BOOLEAN => MBOOL, BYTE => MBYTE, SHORT => MSHORT, + CHAR => MCHAR, INT => MINT, LONG => MLONG, FLOAT => MFLOAT, + DOUBLE => MDOUBLE, OBJECT => MOBJECT, STRING => MSTRING, + STRING_ARRAY => MSTRING_ARRAY, + SYMTAB_CONSTR => SYMTAB_ATTRIBUTE_CONSTRUCTOR, + SYMTAB_DEFAULT_CONSTR => SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR} + + val EXCEPTION = clrTypes.getType("System.Exception") + val MBYTE_ARRAY = clrTypes.mkArrayType(MBYTE) + + val ICLONEABLE = clrTypes.getType("System.ICloneable") + val MEMBERWISE_CLONE = MOBJECT.GetMethod("MemberwiseClone", MsilType.EmptyTypes) + + val MMONITOR = clrTypes.getType("System.Threading.Monitor") + val MMONITOR_ENTER = MMONITOR.GetMethod("Enter", Array(MOBJECT)) + val MMONITOR_EXIT = MMONITOR.GetMethod("Exit", Array(MOBJECT)) + + val MSTRING_BUILDER = clrTypes.getType("System.Text.StringBuilder") + val MSTRING_BUILDER_CONSTR = MSTRING_BUILDER.GetConstructor(MsilType.EmptyTypes) + val MSTRING_BUILDER_TOSTRING = MSTRING_BUILDER.GetMethod("ToString", + MsilType.EmptyTypes) + + val TYPE_FROM_HANDLE = + clrTypes.getType("System.Type").GetMethod("GetTypeFromHandle", Array(clrTypes.getType("System.RuntimeTypeHandle"))) + + val INT_PTR = clrTypes.getType("System.IntPtr") + + val JOBJECT = definitions.ObjectClass + val JSTRING = definitions.StringClass + + val SystemConvert = clrTypes.getType("System.Convert") + + val objParam = Array(MOBJECT) + + val toBool: MethodInfo = SystemConvert.GetMethod("ToBoolean", objParam) // see comment in emitUnbox + val toSByte: MethodInfo = SystemConvert.GetMethod("ToSByte", objParam) + val toShort: MethodInfo = SystemConvert.GetMethod("ToInt16", objParam) + val toChar: MethodInfo = SystemConvert.GetMethod("ToChar", objParam) + val toInt: MethodInfo = SystemConvert.GetMethod("ToInt32", objParam) + val toLong: MethodInfo = SystemConvert.GetMethod("ToInt64", objParam) + val toFloat: MethodInfo = SystemConvert.GetMethod("ToSingle", objParam) + val toDouble: MethodInfo = SystemConvert.GetMethod("ToDouble", objParam) + + //val boxedUnit: FieldInfo = msilType(definitions.BoxedUnitModule.info).GetField("UNIT") + val boxedUnit: FieldInfo = fields(definitions.BoxedUnit_UNIT) + + // Scala attributes + // symtab.Definitions -> object (singleton..) + val SerializableAttr = definitions.SerializableAttr.tpe + val CloneableAttr = definitions.CloneableAttr.tpe + val TransientAtt = definitions.TransientAttr.tpe + // remoting: the architectures are too different, no mapping (no portable code + // possible) + + // java instance methods that are mapped to static methods in .net + // these will need to be called with OpCodes.Call (not Callvirt) + val dynToStatMapped = mutable.HashSet[Symbol]() + + initMappings() + + /** Create the mappings between java and .net classes and methods */ + private def initMappings() { + mapType(definitions.AnyClass, MOBJECT) + mapType(definitions.AnyRefClass, MOBJECT) + //mapType(definitions.NullClass, clrTypes.getType("scala.AllRef$")) + //mapType(definitions.NothingClass, clrTypes.getType("scala.All$")) + // FIXME: for some reason the upper two lines map to null + mapType(definitions.NullClass, EXCEPTION) + mapType(definitions.NothingClass, EXCEPTION) + + mapType(definitions.BooleanClass, MBOOL) + mapType(definitions.ByteClass, MBYTE) + mapType(definitions.ShortClass, MSHORT) + mapType(definitions.CharClass, MCHAR) + mapType(definitions.IntClass, MINT) + mapType(definitions.LongClass, MLONG) + mapType(definitions.FloatClass, MFLOAT) + mapType(definitions.DoubleClass, MDOUBLE) + } + + var clasz: IClass = _ + var method: IMethod = _ + + var massembly: AssemblyBuilder = _ + var mmodule: ModuleBuilder = _ + var mcode: ILGenerator = _ + + var assemName: String = _ + var firstSourceName = "" + var outDir: File = _ + var srcPath: File = _ + var moduleName: String = _ + + def initAssembly() { + + assemName = settings.assemname.value + + if (assemName == "") { + if (entryPoint != null) { + assemName = msilName(entryPoint.enclClass) + // remove the $ at the end (from module-name) + assemName = assemName.substring(0, assemName.length() - 1) + } else { + // assuming filename of first source file + assert(firstSourceName.endsWith(".scala"), firstSourceName) + assemName = firstSourceName.substring(0, firstSourceName.length() - 6) + } + } else { + if (assemName.endsWith(".msil")) + assemName = assemName.substring(0, assemName.length()-5) + if (assemName.endsWith(".il")) + assemName = assemName.substring(0, assemName.length()-3) + val f: File = new File(assemName) + assemName = f.getName() + } + + outDir = new File(settings.outdir.value) + + srcPath = new File(settings.sourcedir.value) + + val assemblyName = new AssemblyName() + assemblyName.Name = assemName + massembly = AssemblyBuilderFactory.DefineDynamicAssembly(assemblyName) + + moduleName = assemName // + (if (entryPoint == null) ".dll" else ".exe") + // filename here: .dll or .exe (in both parameters), second: give absolute-path + mmodule = massembly.DefineDynamicModule(moduleName, + new File(outDir, moduleName).getAbsolutePath()) + assert (mmodule != null) + } + + + /** + * Form of the custom Attribute parameter (Ecma-335.pdf) + * - p. 163 for CustomAttrib Form, + * - p. 164 for FixedArg Form (Array and Element) (if array or not is known!) + * !! least significant byte first if values longer than one byte !! + * + * 1: Prolog (unsigned int16, value 0x0001) -> symtab[0] = 0x01, symtab[1] = 0x00 + * 2: FixedArgs (directly the data, get number and types from related constructor) + * 2.1: length of the array (unsigned int32, 4 bytes, least significant first) + * 2.2: the byte array data + * 3: NumNamed (unsigned int16, number of named fields and properties, 0x0000) + */ + def addSymtabAttribute(sym: Symbol, tBuilder: TypeBuilder) { + def addMarker() { + val markerSymtab = new Array[Byte](4) + markerSymtab(0) = 1.toByte + tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_EMPTY_CONSTRUCTOR, markerSymtab) + } + + // both conditions are needed (why exactly..?) + if (tBuilder.Name.endsWith("$") || sym.isModuleClass) { + addMarker() + } else { + currentRun.symData.get(sym) match { + case Some(pickle) => + var size = pickle.writeIndex + val symtab = new Array[Byte](size + 8) + symtab(0) = 1.toByte + for (i <- 2 until 6) { + symtab(i) = (size & 0xff).toByte + size = size >> 8 + } + java.lang.System.arraycopy(pickle.bytes, 0, symtab, 6, pickle.writeIndex) + + tBuilder.SetCustomAttribute(SYMTAB_ATTRIBUTE_CONSTRUCTOR, symtab) + + currentRun.symData -= sym + currentRun.symData -= sym.companionSymbol + + case _ => + addMarker() + } + } + } + + /** + * Mutates `member` adding CLR attributes (if any) based on sym.annotations. + * Please notice that CLR custom modifiers are a different beast (see customModifiers below) + * and thus shouldn't be added by this method. + */ + def addAttributes(member: ICustomAttributeSetter, annotations: List[AnnotationInfo]) { + val attributes = annotations.map(_.atp.typeSymbol).collect { + case definitions.TransientAttr => null // TODO this is just an example + } + return // TODO: implement at some point + } + + /** + * What's a CLR custom modifier? Intro available as source comments in compiler.msil.CustomModifier. + * It's basically a marker associated with a location (think of FieldInfo, ParameterInfo, and PropertyInfo) + * and thus that marker (be it optional or required) becomes part of the signature of that location. + * Some annotations will become CLR attributes (see addAttributes above), others custom modifiers (this method). + */ + def customModifiers(annotations: List[AnnotationInfo]): Array[CustomModifier] = { + annotations.map(_.atp.typeSymbol).collect { + case definitions.VolatileAttr => new CustomModifier(true, CustomModifier.VolatileMarker) + } toArray + } + + + + /* + debuglog("creating annotations: " + annotations + " for member : " + member) + for (annot@ AnnotationInfo(typ, annArgs, nvPairs) <- annotations ; + if annot.isConstant) + //!typ.typeSymbol.isJavaDefined + { +// assert(consts.length <= 1, +// "too many constant arguments for annotations; "+consts.toString()) + + // Problem / TODO having the symbol of the annotations type would be nicer + // (i hope that type.typeSymbol is the same as the one in types2create) + // AND: this will crash if the annotations Type is already compiled (-> not a typeBuilder) + // when this is solved, types2create will be the same as icodes.classes, thus superfluous + val annType: TypeBuilder = getType(typ.typeSymbol).asInstanceOf[TypeBuilder] +// val annType: MsilType = getType(typ.typeSymbol) + + // Problem / TODO: i have no idea which constructor is used. This + // information should be available in AnnotationInfo. + annType.CreateType() // else, GetConstructors can't be used + val constr: ConstructorInfo = annType.GetConstructors()(0) + // prevent a second call of CreateType, only needed because there's no + // other way than GetConstructors()(0) to get the constructor, if there's + // no constructor symbol available. + + val args: Array[Byte] = + getAttributeArgs( + annArgs map (_.constant.get), + (for((n,v) <- nvPairs) yield (n, v.constant.get))) + member.SetCustomAttribute(constr, args) + } + } */ + +/* def getAttributeArgs(consts: List[Constant], nvPairs: List[(Name, Constant)]): Array[Byte] = { + val buf = ByteBuffer.allocate(2048) // FIXME: this may be not enough! + buf.order(ByteOrder.LITTLE_ENDIAN) + buf.putShort(1.toShort) // signature + + def emitSerString(str: String) = { + // this is wrong, it has to be the length of the UTF-8 byte array, which + // may be longer (see clr-book on page 302) +// val length: Int = str.length + val strBytes: Array[Byte] = try { + str.getBytes("UTF-8") + } catch { + case _: Error => abort("could not get byte-array for string: " + str) + } + val length: Int = strBytes.length //this length is stored big-endian + if (length < 128) + buf.put(length.toByte) + else if (length < (1<<14)) { + buf.put(((length >> 8) | 0x80).toByte) // the bits 14 and 15 of length are '0' + buf.put((length | 0xff).toByte) + } else if (length < (1 << 29)) { + buf.put(((length >> 24) | 0xc0).toByte) + buf.put(((length >> 16) & 0xff).toByte) + buf.put(((length >> 8) & 0xff).toByte) + buf.put(((length ) & 0xff).toByte) + } else + abort("string too long for attribute parameter: " + length) + buf.put(strBytes) + } + + def emitConst(const: Constant): Unit = const.tag match { + case BooleanTag => buf.put((if (const.booleanValue) 1 else 0).toByte) + case ByteTag => buf.put(const.byteValue) + case ShortTag => buf.putShort(const.shortValue) + case CharTag => buf.putChar(const.charValue) + case IntTag => buf.putInt(const.intValue) + case LongTag => buf.putLong(const.longValue) + case FloatTag => buf.putFloat(const.floatValue) + case DoubleTag => buf.putDouble(const.doubleValue) + case StringTag => + val str: String = const.stringValue + if (str == null) { + buf.put(0xff.toByte) + } else { + emitSerString(str) + } + case ArrayTag => + val arr: Array[Constant] = const.arrayValue + if (arr == null) { + buf.putInt(0xffffffff) + } else { + buf.putInt(arr.length) + arr.foreach(emitConst) + } + + // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag, ArrayTag ??? + + case _ => abort("could not handle attribute argument: " + const) + } + + consts foreach emitConst + buf.putShort(nvPairs.length.toShort) + def emitNamedArg(nvPair: (Name, Constant)) { + // the named argument is a property of the attribute (it can't be a field, since + // all fields in scala are private) + buf.put(0x54.toByte) + + def emitType(c: Constant) = c.tag match { // type of the constant, Ecma-335.pdf, page 151 + case BooleanTag => buf.put(0x02.toByte) + case ByteTag => buf.put(0x05.toByte) + case ShortTag => buf.put(0x06.toByte) + case CharTag => buf.put(0x07.toByte) + case IntTag => buf.put(0x08.toByte) + case LongTag => buf.put(0x0a.toByte) + case FloatTag => buf.put(0x0c.toByte) + case DoubleTag => buf.put(0x0d.toByte) + case StringTag => buf.put(0x0e.toByte) + + // TODO: other Tags: NoTag, UnitTag, ClassTag, EnumTag ??? + + // ArrayTag falls in here + case _ => abort("could not handle attribute argument: " + c) + } + + val cnst: Constant = nvPair._2 + if (cnst.tag == ArrayTag) { + buf.put(0x1d.toByte) + emitType(cnst.arrayValue(0)) // FIXME: will crash if array length = 0 + } else if (cnst.tag == EnumTag) { + buf.put(0x55.toByte) + // TODO: put a SerString (don't know what exactly, names of the enums somehow..) + } else { + buf.put(0x51.toByte) + emitType(cnst) + } + + emitSerString(nvPair._1.toString) + emitConst(nvPair._2) + } + + val length = buf.position() + buf.array().slice(0, length) + } */ + + def writeAssembly() { + if (entryPoint != null) { + assert(entryPoint.enclClass.isModuleClass, entryPoint.enclClass) + val mainMethod = methods(entryPoint) + val stringArrayTypes: Array[MsilType] = Array(MSTRING_ARRAY) + val globalMain = mmodule.DefineGlobalMethod( + "Main", MethodAttributes.Public | MethodAttributes.Static, + MVOID, stringArrayTypes) + globalMain.DefineParameter(0, ParameterAttributes.None, "args") + massembly.SetEntryPoint(globalMain) + val code = globalMain.GetILGenerator() + val moduleField = getModuleInstanceField(entryPoint.enclClass) + code.Emit(OpCodes.Ldsfld, moduleField) + code.Emit(OpCodes.Ldarg_0) + code.Emit(OpCodes.Callvirt, mainMethod) + code.Emit(OpCodes.Ret) + } + createTypes() + var outDirName: String = null + try { + if (settings.Ygenjavap.isDefault) { // we reuse the JVM-sounding setting because it's conceptually similar + outDirName = outDir.getPath() + massembly.Save(outDirName + "\\" + assemName + ".msil") /* use SingleFileILPrinterVisitor */ + } else { + outDirName = srcPath.getPath() + massembly.Save(settings.Ygenjavap.value, outDirName) /* use MultipleFilesILPrinterVisitor */ + } + } catch { + case e:IOException => abort("Could not write to " + outDirName + ": " + e.getMessage()) + } + } + + private def createTypes() { + for (sym <- classes.keys) { + val iclass = classes(sym) + val tBuilder = types(sym).asInstanceOf[TypeBuilder] + + debuglog("Calling CreatType for " + sym + ", " + tBuilder.toString) + + tBuilder.CreateType() + tBuilder.setSourceFilepath(iclass.cunit.source.file.path) + } + } + + private[GenMSIL] def ilasmFileName(iclass: IClass) : String = { + // method.sourceFile contains just the filename + iclass.cunit.source.file.toString.replace("\\", "\\\\") + } + + private[GenMSIL] def genClass(iclass: IClass) { + val sym = iclass.symbol + debuglog("Generating class " + sym + " flags: " + Flags.flagsToString(sym.flags)) + clasz = iclass + + val tBuilder = getType(sym).asInstanceOf[TypeBuilder] + if (isCloneable(sym)) { + // FIXME: why there's no nme.clone_ ? + // "Clone": if the code is non-portable, "Clone" is defined, not "clone" + // TODO: improve condition (should override AnyRef.clone) + if (iclass.methods.forall(m => { + !((m.symbol.name.toString != "clone" || m.symbol.name.toString != "Clone") && + m.symbol.tpe.paramTypes.length != 0) + })) { + debuglog("auto-generating cloneable method for " + sym) + val attrs: Short = (MethodAttributes.Public | MethodAttributes.Virtual | + MethodAttributes.HideBySig).toShort + val cloneMethod = tBuilder.DefineMethod("Clone", attrs, MOBJECT, + MsilType.EmptyTypes) + val clCode = cloneMethod.GetILGenerator() + clCode.Emit(OpCodes.Ldarg_0) + clCode.Emit(OpCodes.Call, MEMBERWISE_CLONE) + clCode.Emit(OpCodes.Ret) + } + } + + val line = sym.pos.line + tBuilder.setPosition(line, ilasmFileName(iclass)) + + if (isTopLevelModule(sym)) { + if (sym.companionClass == NoSymbol) + generateMirrorClass(sym) + else + log("No mirror class for module with linked class: " + + sym.fullName) + } + + addSymtabAttribute(sym, tBuilder) + addAttributes(tBuilder, sym.annotations) + + if (iclass.symbol != definitions.ArrayClass) + iclass.methods foreach genMethod + + } //genClass + + + private def genMethod(m: IMethod) { + debuglog("Generating method " + m.symbol + " flags: " + Flags.flagsToString(m.symbol.flags) + + " owner: " + m.symbol.owner) + method = m + localBuilders.clear + computeLocalVarsIndex(m) + + if (m.symbol.isClassConstructor) { + mcode = constructors(m.symbol).asInstanceOf[ConstructorBuilder].GetILGenerator() + } else { + val mBuilder = methods(m.symbol).asInstanceOf[MethodBuilder] + if (!mBuilder.IsAbstract()) + try { + mcode = mBuilder.GetILGenerator() + } catch { + case e: Exception => + java.lang.System.out.println("m.symbol = " + Flags.flagsToString(m.symbol.flags) + " " + m.symbol) + java.lang.System.out.println("m.symbol.owner = " + Flags.flagsToString(m.symbol.owner.flags) + " " + m.symbol.owner) + java.lang.System.out.println("mBuilder = " + mBuilder) + java.lang.System.out.println("mBuilder.DeclaringType = " + + TypeAttributes.toString(mBuilder.DeclaringType.Attributes) + + "::" + mBuilder.DeclaringType) + throw e + } + else + mcode = null + } + + if (mcode != null) { + for (local <- m.locals ; if !(m.params contains local)) { + debuglog("add local var: " + local + ", of kind " + local.kind) + val t: MsilType = msilType(local.kind) + val localBuilder = mcode.DeclareLocal(t) + localBuilder.SetLocalSymInfo(msilName(local.sym)) + localBuilders(local) = localBuilder + } + genCode(m) + } + + } + + /** Special linearizer for methods with at least one exception handler. This + * linearizer brings all basic blocks in the right order so that nested + * try-catch and try-finally blocks can be emitted. + */ + val msilLinearizer = new MSILLinearizer() + + val labels = mutable.HashMap[BasicBlock, Label]() + + /* when emitting .line, it's enough to include the full filename just once per method, thus reducing filesize. + * this scheme relies on the fact that the entry block is emitted first. */ + var dbFilenameSeen = false + + def genCode(m: IMethod) { + + def makeLabels(blocks: List[BasicBlock]) = { + debuglog("Making labels for: " + method) + for (bb <- blocks) labels(bb) = mcode.DefineLabel() + } + + labels.clear + + var linearization = if(!m.exh.isEmpty) msilLinearizer.linearize(m) + else linearizer.linearize(m) + + if (!m.exh.isEmpty) + linearization = computeExceptionMaps(linearization, m) + + makeLabels(linearization) + + // debug val blocksInM = m.code.blocks.toList.sortBy(bb => bb.label) + // debug val blocksInL = linearization.sortBy(bb => bb.label) + // debug val MButNotL = (blocksInM.toSet) diff (blocksInL.toSet) // if non-empty, a jump to B fails to find a label for B (case CJUMP, case CZJUMP) + // debug if(!MButNotL.isEmpty) { } + + dbFilenameSeen = false + genBlocks(linearization) + + // RETURN inside exception blocks are replaced by Leave. The target of the + // leave is a `Ret` outside any exception block (generated here). + if (handlerReturnMethod == m) { + mcode.MarkLabel(handlerReturnLabel) + if (handlerReturnKind != UNIT) + mcode.Emit(OpCodes.Ldloc, handlerReturnLocal) + mcode.Emit(OpCodes.Ret) + } + + beginExBlock.clear() + beginCatchBlock.clear() + endExBlock.clear() + endFinallyLabels.clear() + } + + def genBlocks(blocks: List[BasicBlock], previous: BasicBlock = null) { + blocks match { + case Nil => () + case x :: Nil => genBlock(x, prev = previous, next = null) + case x :: y :: ys => genBlock(x, prev = previous, next = y); genBlocks(y :: ys, previous = x) + } + } + + // the try blocks starting at a certain BasicBlock + val beginExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() + + // the catch blocks starting / endling at a certain BasicBlock + val beginCatchBlock = mutable.HashMap[BasicBlock, ExceptionHandler]() + val endExBlock = mutable.HashMap[BasicBlock, List[ExceptionHandler]]() + + /** When emitting the code (genBlock), the number of currently active try / catch + * blocks. When seeing a `RETURN` inside a try / catch, we need to + * - store the result in a local (if it's not UNIT) + * - emit `Leave handlerReturnLabel` instead of the Return + * - emit code at the end: load the local and return its value + */ + var currentHandlers = new mutable.Stack[ExceptionHandler] + // The IMethod the Local/Label/Kind below belong to + var handlerReturnMethod: IMethod = _ + // Stores the result when returning inside an exception block + var handlerReturnLocal: LocalBuilder = _ + // Label for a return instruction outside any exception block + var handlerReturnLabel: Label = _ + // The result kind. + var handlerReturnKind: TypeKind = _ + def returnFromHandler(kind: TypeKind): (LocalBuilder, Label) = { + if (handlerReturnMethod != method) { + handlerReturnMethod = method + if (kind != UNIT) { + handlerReturnLocal = mcode.DeclareLocal(msilType(kind)) + handlerReturnLocal.SetLocalSymInfo("$handlerReturn") + } + handlerReturnLabel = mcode.DefineLabel() + handlerReturnKind = kind + } + (handlerReturnLocal, handlerReturnLabel) + } + + /** For try/catch nested inside a finally, we can't use `Leave OutsideFinally`, the + * Leave target has to be inside the finally (and it has to be the `endfinally` instruction). + * So for every finalizer, we have a label which marks the place of the `endfinally`, + * nested try/catch blocks will leave there. + */ + val endFinallyLabels = mutable.HashMap[ExceptionHandler, Label]() + + /** Computes which blocks are the beginning / end of a try or catch block */ + private def computeExceptionMaps(blocks: List[BasicBlock], m: IMethod): List[BasicBlock] = { + val visitedBlocks = new mutable.HashSet[BasicBlock]() + + // handlers which have not been introduced so far + var openHandlers = m.exh + + + /** Example + * try { + * try { + * // *1* + * } catch { + * case h1 => + * } + * } catch { + * case h2 => + * case h3 => + * try { + * + * } catch { + * case h4 => // *2* + * case h5 => + * } + * } + */ + + // Stack of nested try blocks. Each bloc has a List of ExceptionHandler (multiple + // catch statements). Example *1*: Stack(List(h2, h3), List(h1)) + val currentTryHandlers = new mutable.Stack[List[ExceptionHandler]]() + + // Stack of nested catch blocks. The head of the list is the current catch block. The + // tail is all following catch blocks. Example *2*: Stack(List(h3), List(h4, h5)) + val currentCatchHandlers = new mutable.Stack[List[ExceptionHandler]]() + + for (b <- blocks) { + + // are we past the current catch blocks? + def endHandlers(): List[ExceptionHandler] = { + var res: List[ExceptionHandler] = Nil + if (!currentCatchHandlers.isEmpty) { + val handler = currentCatchHandlers.top.head + if (!handler.blocks.contains(b)) { + // all blocks of the handler are either visited, or not part of the linearization (i.e. dead) + assert(handler.blocks.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), + "Bad linearization of basic blocks inside catch. Found block not part of the handler\n"+ + b.fullString +"\nwhile in catch-part of\n"+ handler) + + val rest = currentCatchHandlers.pop.tail + if (rest.isEmpty) { + // all catch blocks of that exception handler are covered + res = handler :: endHandlers() + } else { + // there are more catch blocks for that try (handlers covering the same) + currentCatchHandlers.push(rest) + beginCatchBlock(b) = rest.head + } + } + } + res + } + val end = endHandlers() + if (!end.isEmpty) endExBlock(b) = end + + // are we past the current try block? + if (!currentTryHandlers.isEmpty) { + val handler = currentTryHandlers.top.head + if (!handler.covers(b)) { + // all of the covered blocks are visited, or not part of the linearization + assert(handler.covered.forall(b => visitedBlocks.contains(b) || !blocks.contains(b)), + "Bad linearization of basic blocks inside try. Found non-covered block\n"+ + b.fullString +"\nwhile in try-part of\n"+ handler) + + assert(handler.startBlock == b, + "Bad linearization of basic blocks. The entry block of a catch does not directly follow the try\n"+ + b.fullString +"\n"+ handler) + + val handlers = currentTryHandlers.pop + currentCatchHandlers.push(handlers) + beginCatchBlock(b) = handler + } + } + + // are there try blocks starting at b? + val (newHandlers, stillOpen) = openHandlers.partition(_.covers(b)) + openHandlers = stillOpen + + val newHandlersBySize = newHandlers.groupBy(_.covered.size) + // big handlers first, smaller ones are nested inside the try of the big one + // (checked by the assertions below) + val sizes = newHandlersBySize.keys.toList.sortWith(_ > _) + + val beginHandlers = new mutable.ListBuffer[ExceptionHandler] + for (s <- sizes) { + val sHandlers = newHandlersBySize(s) + for (h <- sHandlers) { + assert(h.covered == sHandlers.head.covered, + "bad nesting of exception handlers. same size, but not covering same blocks\n"+ + h +"\n"+ sHandlers.head) + assert(h.resultKind == sHandlers.head.resultKind, + "bad nesting of exception handlers. same size, but the same resultKind\n"+ + h +"\n"+ sHandlers.head) + } + for (bigger <- beginHandlers; h <- sHandlers) { + assert(h.covered.subsetOf(bigger.covered), + "bad nesting of exception handlers. try blocks of smaller handler are not nested in bigger one.\n"+ + h +"\n"+ bigger) + assert(h.blocks.toSet.subsetOf(bigger.covered), + "bad nesting of exception handlers. catch blocks of smaller handler are not nested in bigger one.\n"+ + h +"\n"+ bigger) + } + beginHandlers += sHandlers.head + currentTryHandlers.push(sHandlers) + } + beginExBlock(b) = beginHandlers.toList + visitedBlocks += b + } + + // if there handlers left (i.e. handlers covering nothing, or a + // non-existent (dead) block), remove their catch-blocks. + val liveBlocks = if (openHandlers.isEmpty) blocks else { + blocks.filter(b => openHandlers.forall(h => !h.blocks.contains(b))) + } + + /** There might be open handlers, but no more blocks. happens when try/catch end + * with `throw` or `return` + * def foo() { try { .. throw } catch { _ => .. throw } } + * + * In this case we need some code after the catch block for the auto-generated + * `leave` instruction. So we're adding a (dead) `throw new Exception`. + */ + val rest = currentCatchHandlers.map(handlers => { + assert(handlers.length == 1, handlers) + handlers.head + }).toList + + if (rest.isEmpty) { + liveBlocks + } else { + val b = m.code.newBlock + b.emit(Seq( + NEW(REFERENCE(definitions.ThrowableClass)), + DUP(REFERENCE(definitions.ObjectClass)), + CALL_METHOD(definitions.ThrowableClass.primaryConstructor, Static(true)), + THROW(definitions.ThrowableClass) + )) + b.close + endExBlock(b) = rest + liveBlocks ::: List(b) + } + } + + /** + * @param block the BasicBlock to emit code for + * @param next the following BasicBlock, `null` if `block` is the last one + */ + def genBlock(block: BasicBlock, prev: BasicBlock, next: BasicBlock) { + + def loadLocalOrAddress(local: Local, msg : String , loadAddr : Boolean) { + debuglog(msg + " for " + local) + val isArg = local.arg + val i = local.index + if (isArg) + loadArg(mcode, loadAddr)(i) + else + loadLocal(i, local, mcode, loadAddr) + } + + def loadFieldOrAddress(field: Symbol, isStatic: Boolean, msg: String, loadAddr : Boolean) { + debuglog(msg + " with owner: " + field.owner + + " flags: " + Flags.flagsToString(field.owner.flags)) + var fieldInfo = fields.get(field) match { + case Some(fInfo) => fInfo + case None => + val fInfo = getType(field.owner).GetField(msilName(field)) + fields(field) = fInfo + fInfo + } + if (fieldInfo.IsVolatile) { + mcode.Emit(OpCodes.Volatile) + } + if (!fieldInfo.IsLiteral) { + if (loadAddr) { + mcode.Emit(if (isStatic) OpCodes.Ldsflda else OpCodes.Ldflda, fieldInfo) + } else { + mcode.Emit(if (isStatic) OpCodes.Ldsfld else OpCodes.Ldfld, fieldInfo) + } + } else { + assert(!loadAddr, "can't take AddressOf a literal field (not even with readonly. prefix) because no memory was allocated to such field ...") + // TODO the above can be overcome by loading the value, boxing, and finally unboxing. An address to a copy of the raw value will be on the stack. + /* We perform `field inlining' as required by CLR. + * Emit as for a CONSTANT ICode stmt, with the twist that the constant value is available + * as a java.lang.Object and its .NET type allows constant initialization in CLR, i.e. that type + * is one of I1, I2, I4, I8, R4, R8, CHAR, BOOLEAN, STRING, or CLASS (in this last case, + * only accepting nullref as value). See Table 9-1 in Lidin's book on ILAsm. */ + val value = fieldInfo.getValue() + if (value == null) { + mcode.Emit(OpCodes.Ldnull) + } else { + val typ = if (fieldInfo.FieldType.IsEnum) fieldInfo.FieldType.getUnderlyingType + else fieldInfo.FieldType + if (typ == clrTypes.STRING) { + mcode.Emit(OpCodes.Ldstr, value.asInstanceOf[String]) + } else if (typ == clrTypes.BOOLEAN) { + mcode.Emit(if (value.asInstanceOf[Boolean]) OpCodes.Ldc_I4_1 + else OpCodes.Ldc_I4_0) + } else if (typ == clrTypes.BYTE || typ == clrTypes.UBYTE) { + loadI4(value.asInstanceOf[Byte], mcode) + } else if (typ == clrTypes.SHORT || typ == clrTypes.USHORT) { + loadI4(value.asInstanceOf[Int], mcode) + } else if (typ == clrTypes.CHAR) { + loadI4(value.asInstanceOf[Char], mcode) + } else if (typ == clrTypes.INT || typ == clrTypes.UINT) { + loadI4(value.asInstanceOf[Int], mcode) + } else if (typ == clrTypes.LONG || typ == clrTypes.ULONG) { + mcode.Emit(OpCodes.Ldc_I8, value.asInstanceOf[Long]) + } else if (typ == clrTypes.FLOAT) { + mcode.Emit(OpCodes.Ldc_R4, value.asInstanceOf[Float]) + } else if (typ == clrTypes.DOUBLE) { + mcode.Emit(OpCodes.Ldc_R8, value.asInstanceOf[Double]) + } else { + /* TODO one more case is described in Partition II, 16.2: bytearray(...) */ + abort("Unknown type for static literal field: " + fieldInfo) + } + } + } + } + + /** Creating objects works differently on .NET. On the JVM + * - NEW(type) => reference on Stack + * - DUP, load arguments, CALL_METHOD(constructor) + * + * On .NET, the NEW and DUP are ignored, but we emit a special method call + * - load arguments + * - NewObj(constructor) => reference on stack + * + * This variable tells whether the previous instruction was a NEW, + * we expect a DUP which is not emitted. */ + var previousWasNEW = false + + var lastLineNr: Int = 0 + var lastPos: Position = NoPosition + + + // EndExceptionBlock must happen before MarkLabel because it adds the + // Leave instruction. Otherwise, labels(block) points to the Leave + // (inside the catch) instead of the instruction afterwards. + for (handlers <- endExBlock.get(block); exh <- handlers) { + currentHandlers.pop() + for (l <- endFinallyLabels.get(exh)) + mcode.MarkLabel(l) + mcode.EndExceptionBlock() + } + + mcode.MarkLabel(labels(block)) + debuglog("Generating code for block: " + block) + + for (handler <- beginCatchBlock.get(block)) { + if (!currentHandlers.isEmpty && currentHandlers.top.covered == handler.covered) { + currentHandlers.pop() + currentHandlers.push(handler) + } + if (handler.cls == NoSymbol) { + // `finally` blocks are represented the same as `catch`, but with no catch-type + mcode.BeginFinallyBlock() + } else { + val t = getType(handler.cls) + mcode.BeginCatchBlock(t) + } + } + for (handlers <- beginExBlock.get(block); exh <- handlers) { + currentHandlers.push(exh) + mcode.BeginExceptionBlock() + } + + for (instr <- block) { + try { + val currentLineNr = instr.pos.line + val skip = if(instr.pos.isRange) instr.pos.sameRange(lastPos) else (currentLineNr == lastLineNr); + if(!skip || !dbFilenameSeen) { + val fileName = if(dbFilenameSeen) "" else {dbFilenameSeen = true; ilasmFileName(clasz)}; + if(instr.pos.isRange) { + val startLine = instr.pos.focusStart.line + val endLine = instr.pos.focusEnd.line + val startCol = instr.pos.focusStart.column + val endCol = instr.pos.focusEnd.column + mcode.setPosition(startLine, endLine, startCol, endCol, fileName) + } else { + mcode.setPosition(instr.pos.line, fileName) + } + lastLineNr = currentLineNr + lastPos = instr.pos + } + } catch { case _: UnsupportedOperationException => () } + + if (previousWasNEW) + assert(instr.isInstanceOf[DUP], block) + + instr match { + case THIS(clasz) => + mcode.Emit(OpCodes.Ldarg_0) + + case CONSTANT(const) => + const.tag match { + case UnitTag => () + case BooleanTag => mcode.Emit(if (const.booleanValue) OpCodes.Ldc_I4_1 + else OpCodes.Ldc_I4_0) + case ByteTag => loadI4(const.byteValue, mcode) + case ShortTag => loadI4(const.shortValue, mcode) + case CharTag => loadI4(const.charValue, mcode) + case IntTag => loadI4(const.intValue, mcode) + case LongTag => mcode.Emit(OpCodes.Ldc_I8, const.longValue) + case FloatTag => mcode.Emit(OpCodes.Ldc_R4, const.floatValue) + case DoubleTag => mcode.Emit(OpCodes.Ldc_R8, const.doubleValue) + case StringTag => mcode.Emit(OpCodes.Ldstr, const.stringValue) + case NullTag => mcode.Emit(OpCodes.Ldnull) + case ClassTag => + mcode.Emit(OpCodes.Ldtoken, msilType(const.typeValue)) + mcode.Emit(OpCodes.Call, TYPE_FROM_HANDLE) + case _ => abort("Unknown constant value: " + const) + } + + case LOAD_ARRAY_ITEM(kind) => + (kind: @unchecked) match { + case BOOL => mcode.Emit(OpCodes.Ldelem_I1) + case BYTE => mcode.Emit(OpCodes.Ldelem_I1) // I1 for System.SByte, i.e. a scala.Byte + case SHORT => mcode.Emit(OpCodes.Ldelem_I2) + case CHAR => mcode.Emit(OpCodes.Ldelem_U2) + case INT => mcode.Emit(OpCodes.Ldelem_I4) + case LONG => mcode.Emit(OpCodes.Ldelem_I8) + case FLOAT => mcode.Emit(OpCodes.Ldelem_R4) + case DOUBLE => mcode.Emit(OpCodes.Ldelem_R8) + case REFERENCE(cls) => mcode.Emit(OpCodes.Ldelem_Ref) + case ARRAY(elem) => mcode.Emit(OpCodes.Ldelem_Ref) + + // case UNIT is not possible: an Array[Unit] will be an + // Array[scala.runtime.BoxedUnit] (-> case REFERENCE) + } + + case LOAD_LOCAL(local) => loadLocalOrAddress(local, "load_local", false) + + case CIL_LOAD_LOCAL_ADDRESS(local) => loadLocalOrAddress(local, "cil_load_local_address", true) + + case LOAD_FIELD(field, isStatic) => loadFieldOrAddress(field, isStatic, "load_field", false) + + case CIL_LOAD_FIELD_ADDRESS(field, isStatic) => loadFieldOrAddress(field, isStatic, "cil_load_field_address", true) + + case CIL_LOAD_ARRAY_ITEM_ADDRESS(kind) => mcode.Emit(OpCodes.Ldelema, msilType(kind)) + + case CIL_NEWOBJ(msym) => + assert(msym.isClassConstructor) + val constructorInfo: ConstructorInfo = getConstructor(msym) + mcode.Emit(OpCodes.Newobj, constructorInfo) + + case LOAD_MODULE(module) => + debuglog("Generating LOAD_MODULE for: " + showsym(module)) + mcode.Emit(OpCodes.Ldsfld, getModuleInstanceField(module)) + + case STORE_ARRAY_ITEM(kind) => + (kind: @unchecked) match { + case BOOL => mcode.Emit(OpCodes.Stelem_I1) + case BYTE => mcode.Emit(OpCodes.Stelem_I1) + case SHORT => mcode.Emit(OpCodes.Stelem_I2) + case CHAR => mcode.Emit(OpCodes.Stelem_I2) + case INT => mcode.Emit(OpCodes.Stelem_I4) + case LONG => mcode.Emit(OpCodes.Stelem_I8) + case FLOAT => mcode.Emit(OpCodes.Stelem_R4) + case DOUBLE => mcode.Emit(OpCodes.Stelem_R8) + case REFERENCE(cls) => mcode.Emit(OpCodes.Stelem_Ref) + case ARRAY(elem) => mcode.Emit(OpCodes.Stelem_Ref) // @TODO: test this! (occurs when calling a Array[Object]* vararg param method) + + // case UNIT not possible (see comment at LOAD_ARRAY_ITEM) + } + + case STORE_LOCAL(local) => + val isArg = local.arg + val i = local.index + debuglog("store_local for " + local + ", index " + i) + + // there are some locals defined by the compiler that + // are isArg and are need to be stored. + if (isArg) { + if (i >= -128 && i <= 127) + mcode.Emit(OpCodes.Starg_S, i) + else + mcode.Emit(OpCodes.Starg, i) + } else { + i match { + case 0 => mcode.Emit(OpCodes.Stloc_0) + case 1 => mcode.Emit(OpCodes.Stloc_1) + case 2 => mcode.Emit(OpCodes.Stloc_2) + case 3 => mcode.Emit(OpCodes.Stloc_3) + case _ => + if (i >= -128 && i <= 127) + mcode.Emit(OpCodes.Stloc_S, localBuilders(local)) + else + mcode.Emit(OpCodes.Stloc, localBuilders(local)) + } + } + + case STORE_THIS(_) => + // this only works for impl classes because the self parameter comes first + // in the method signature. If that changes, this code has to be revisited. + mcode.Emit(OpCodes.Starg_S, 0) + + case STORE_FIELD(field, isStatic) => + val fieldInfo = fields.get(field) match { + case Some(fInfo) => fInfo + case None => + val fInfo = getType(field.owner).GetField(msilName(field)) + fields(field) = fInfo + fInfo + } + mcode.Emit(if (isStatic) OpCodes.Stsfld else OpCodes.Stfld, fieldInfo) + + case CALL_PRIMITIVE(primitive) => + genPrimitive(primitive, instr.pos) + + case CALL_METHOD(msym, style) => + if (msym.isClassConstructor) { + val constructorInfo: ConstructorInfo = getConstructor(msym) + (style: @unchecked) match { + // normal constructor calls are Static.. + case Static(_) => + if (method.symbol.isClassConstructor && method.symbol.owner == msym.owner) + // we're generating a constructor (method: IMethod is a constructor), and we're + // calling another constructor of the same class. + + // @LUC TODO: this can probably break, namely when having: class A { def this() { new A() } } + // instead, we should instruct the CALL_METHOD with additional information, know whether it's + // an instance creation constructor call or not. + mcode.Emit(OpCodes.Call, constructorInfo) + else + mcode.Emit(OpCodes.Newobj, constructorInfo) + case SuperCall(_) => + mcode.Emit(OpCodes.Call, constructorInfo) + if (isStaticModule(clasz.symbol) && + notInitializedModules.contains(clasz.symbol) && + method.symbol.isClassConstructor) + { + notInitializedModules -= clasz.symbol + mcode.Emit(OpCodes.Ldarg_0) + mcode.Emit(OpCodes.Stsfld, getModuleInstanceField(clasz.symbol)) + } + } + + } else { + + var doEmit = true + getTypeOpt(msym.owner) match { + case Some(typ) if (typ.IsEnum) => { + def negBool() = { + mcode.Emit(OpCodes.Ldc_I4_0) + mcode.Emit(OpCodes.Ceq) + } + doEmit = false + val name = msym.name + if (name eq nme.EQ) { mcode.Emit(OpCodes.Ceq) } + else if (name eq nme.NE) { mcode.Emit(OpCodes.Ceq); negBool } + else if (name eq nme.LT) { mcode.Emit(OpCodes.Clt) } + else if (name eq nme.LE) { mcode.Emit(OpCodes.Cgt); negBool } + else if (name eq nme.GT) { mcode.Emit(OpCodes.Cgt) } + else if (name eq nme.GE) { mcode.Emit(OpCodes.Clt); negBool } + else if (name eq nme.OR) { mcode.Emit(OpCodes.Or) } + else if (name eq nme.AND) { mcode.Emit(OpCodes.And) } + else if (name eq nme.XOR) { mcode.Emit(OpCodes.Xor) } + else + doEmit = true + } + case _ => () + } + + // method: implicit view(FunctionX[PType0, PType1, ...,PTypeN, ResType]):DelegateType + val (isDelegateView, paramType, resType) = atPhase(currentRun.typerPhase) { + msym.tpe match { + case MethodType(params, resultType) + if (params.length == 1 && msym.name == nme.view_) => + val paramType = params(0).tpe + val isDel = definitions.isCorrespondingDelegate(resultType, paramType) + (isDel, paramType, resultType) + case _ => (false, null, null) + } + } + if (doEmit && isDelegateView) { + doEmit = false + createDelegateCaller(paramType, resType) + } + + if (doEmit && + (msym.name == nme.PLUS || msym.name == nme.MINUS) + && clrTypes.isDelegateType(msilType(msym.owner.tpe))) + { + doEmit = false + val methodInfo: MethodInfo = getMethod(msym) + // call it as a static method, even if the compiler (symbol) thinks it's virtual + mcode.Emit(OpCodes.Call, methodInfo) + mcode.Emit(OpCodes.Castclass, msilType(msym.owner.tpe)) + } + + if (doEmit && definitions.Delegate_scalaCallers.contains(msym)) { + doEmit = false + val methodSym: Symbol = definitions.Delegate_scalaCallerTargets(msym) + val delegateType: Type = msym.tpe match { + case MethodType(_, retType) => retType + case _ => abort("not a method type: " + msym.tpe) + } + val methodInfo: MethodInfo = getMethod(methodSym) + val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) + if (methodSym.isStatic) { + mcode.Emit(OpCodes.Ldftn, methodInfo) + } else { + mcode.Emit(OpCodes.Dup) + mcode.Emit(OpCodes.Ldvirtftn, methodInfo) + } + mcode.Emit(OpCodes.Newobj, delegCtor) + } + + if (doEmit) { + val methodInfo: MethodInfo = getMethod(msym) + (style: @unchecked) match { + case SuperCall(_) => + mcode.Emit(OpCodes.Call, methodInfo) + case Dynamic => + // methodInfo.DeclaringType is null for global methods + val isValuetypeMethod = (methodInfo.DeclaringType ne null) && (methodInfo.DeclaringType.IsValueType) + val isValuetypeVirtualMethod = isValuetypeMethod && (methodInfo.IsVirtual) + if (dynToStatMapped(msym)) { + mcode.Emit(OpCodes.Call, methodInfo) + } else if (isValuetypeVirtualMethod) { + mcode.Emit(OpCodes.Constrained, methodInfo.DeclaringType) + mcode.Emit(OpCodes.Callvirt, methodInfo) + } else if (isValuetypeMethod) { + // otherwise error "Callvirt on a value type method" ensues + mcode.Emit(OpCodes.Call, methodInfo) + } else { + mcode.Emit(OpCodes.Callvirt, methodInfo) + } + case Static(_) => + if(methodInfo.IsVirtual && !mcode.Ldarg0WasJustEmitted) { + mcode.Emit(OpCodes.Callvirt, methodInfo) + } else mcode.Emit(OpCodes.Call, methodInfo) + } + } + } + + case BOX(boxType) => + emitBox(mcode, boxType) + + case UNBOX(boxType) => + emitUnbox(mcode, boxType) + + case CIL_UNBOX(boxType) => + mcode.Emit(OpCodes.Unbox, msilType(boxType)) + + case CIL_INITOBJ(valueType) => + mcode.Emit(OpCodes.Initobj, msilType(valueType)) + + case NEW(REFERENCE(cls)) => + // the next instruction must be a DUP, see comment on `var previousWasNEW` + previousWasNEW = true + + // works also for arrays and reference-types + case CREATE_ARRAY(elem, dims) => + // TODO: handle multi dimensional arrays + assert(dims == 1, "Can't handle multi dimensional arrays") + mcode.Emit(OpCodes.Newarr, msilType(elem)) + + // works for arrays and reference-types + case IS_INSTANCE(tpe) => + mcode.Emit(OpCodes.Isinst, msilType(tpe)) + mcode.Emit(OpCodes.Ldnull) + mcode.Emit(OpCodes.Ceq) + mcode.Emit(OpCodes.Ldc_I4_0) + mcode.Emit(OpCodes.Ceq) + + // works for arrays and reference-types + // part from the scala reference: "S <: T does not imply + // Array[S] <: Array[T] in Scala. However, it is possible + // to cast an array of S to an array of T if such a cast + // is permitted in the host environment." + case CHECK_CAST(tpknd) => + val tMSIL = msilType(tpknd) + mcode.Emit(OpCodes.Castclass, tMSIL) + + // no SWITCH is generated when there's + // - a default case ("case _ => ...") in the matching expr + // - OR is used ("case 1 | 2 => ...") + case SWITCH(tags, branches) => + // tags is List[List[Int]]; a list of integers for every label. + // if the int on stack is 4, and 4 is in the second list => jump + // to second label + // branches is List[BasicBlock] + // the labels to jump to (the last one is the default one) + + val switchLocal = mcode.DeclareLocal(MINT) + // several switch variables will appear with the same name in the + // assembly code, but this makes no truble + switchLocal.SetLocalSymInfo("$switch_var") + + mcode.Emit(OpCodes.Stloc, switchLocal) + var i = 0 + for (l <- tags) { + var targetLabel = labels(branches(i)) + for (i <- l) { + mcode.Emit(OpCodes.Ldloc, switchLocal) + loadI4(i, mcode) + mcode.Emit(OpCodes.Beq, targetLabel) + } + i += 1 + } + val defaultTarget = labels(branches(i)) + if (next != branches(i)) + mcode.Emit(OpCodes.Br, defaultTarget) + + case JUMP(whereto) => + val (leaveHandler, leaveFinally, lfTarget) = leavesHandler(block, whereto) + if (leaveHandler) { + if (leaveFinally) { + if (lfTarget.isDefined) mcode.Emit(OpCodes.Leave, lfTarget.get) + else mcode.Emit(OpCodes.Endfinally) + } else + mcode.Emit(OpCodes.Leave, labels(whereto)) + } else if (next != whereto) + mcode.Emit(OpCodes.Br, labels(whereto)) + + case CJUMP(success, failure, cond, kind) => + // cond is TestOp (see Primitives.scala), and can take + // values EQ, NE, LT, GE LE, GT + // kind is TypeKind + val isFloat = kind == FLOAT || kind == DOUBLE + val emit = (c: TestOp, l: Label) => emitBr(c, l, isFloat) + emitCondBr(block, cond, success, failure, next, emit) + + case CZJUMP(success, failure, cond, kind) => + emitCondBr(block, cond, success, failure, next, emitBrBool(_, _)) + + case RETURN(kind) => + if (currentHandlers.isEmpty) + mcode.Emit(OpCodes.Ret) + else { + val (local, label) = returnFromHandler(kind) + if (kind != UNIT) + mcode.Emit(OpCodes.Stloc, local) + mcode.Emit(OpCodes.Leave, label) + } + + case THROW(_) => + mcode.Emit(OpCodes.Throw) + + case DROP(kind) => + mcode.Emit(OpCodes.Pop) + + case DUP(kind) => + // see comment on `var previousWasNEW` + if (!previousWasNEW) + mcode.Emit(OpCodes.Dup) + else + previousWasNEW = false + + case MONITOR_ENTER() => + mcode.Emit(OpCodes.Call, MMONITOR_ENTER) + + case MONITOR_EXIT() => + mcode.Emit(OpCodes.Call, MMONITOR_EXIT) + + case SCOPE_ENTER(_) | SCOPE_EXIT(_) | LOAD_EXCEPTION(_) => + () + } + + } // end for (instr <- b) { .. } + } // end genBlock + + def genPrimitive(primitive: Primitive, pos: Position) { + primitive match { + case Negation(kind) => + kind match { + // CHECK: is ist possible to get this for BOOL? in this case, verify. + case BOOL | BYTE | CHAR | SHORT | INT | LONG | FLOAT | DOUBLE => + mcode.Emit(OpCodes.Neg) + + case _ => abort("Impossible to negate a " + kind) + } + + case Arithmetic(op, kind) => + op match { + case ADD => mcode.Emit(OpCodes.Add) + case SUB => mcode.Emit(OpCodes.Sub) + case MUL => mcode.Emit(OpCodes.Mul) + case DIV => mcode.Emit(OpCodes.Div) + case REM => mcode.Emit(OpCodes.Rem) + case NOT => mcode.Emit(OpCodes.Not) //bitwise complement (one's complement) + case _ => abort("Unknown arithmetic primitive " + primitive ) + } + + case Logical(op, kind) => op match { + case AND => mcode.Emit(OpCodes.And) + case OR => mcode.Emit(OpCodes.Or) + case XOR => mcode.Emit(OpCodes.Xor) + } + + case Shift(op, kind) => op match { + case LSL => mcode.Emit(OpCodes.Shl) + case ASR => mcode.Emit(OpCodes.Shr) + case LSR => mcode.Emit(OpCodes.Shr_Un) + } + + case Conversion(src, dst) => + debuglog("Converting from: " + src + " to: " + dst) + + dst match { + case BYTE => mcode.Emit(OpCodes.Conv_I1) // I1 for System.SByte, i.e. a scala.Byte + case SHORT => mcode.Emit(OpCodes.Conv_I2) + case CHAR => mcode.Emit(OpCodes.Conv_U2) + case INT => mcode.Emit(OpCodes.Conv_I4) + case LONG => mcode.Emit(OpCodes.Conv_I8) + case FLOAT => mcode.Emit(OpCodes.Conv_R4) + case DOUBLE => mcode.Emit(OpCodes.Conv_R8) + case _ => + Console.println("Illegal conversion at: " + clasz + + " at: " + pos.source + ":" + pos.line) + } + + case ArrayLength(_) => + mcode.Emit(OpCodes.Ldlen) + + case StartConcat => + mcode.Emit(OpCodes.Newobj, MSTRING_BUILDER_CONSTR) + + + case StringConcat(el) => + val elemType : MsilType = el match { + case REFERENCE(_) | ARRAY(_) => MOBJECT + case _ => msilType(el) + } + + val argTypes:Array[MsilType] = Array(elemType) + val stringBuilderAppend = MSTRING_BUILDER.GetMethod("Append", argTypes ) + mcode.Emit(OpCodes.Callvirt, stringBuilderAppend) + + case EndConcat => + mcode.Emit(OpCodes.Callvirt, MSTRING_BUILDER_TOSTRING) + + case _ => + abort("Unimplemented primitive " + primitive) + } + } // end genPrimitive + + + ////////////////////// loading /////////////////////// + + def loadI4(value: Int, code: ILGenerator): Unit = value match { + case -1 => code.Emit(OpCodes.Ldc_I4_M1) + case 0 => code.Emit(OpCodes.Ldc_I4_0) + case 1 => code.Emit(OpCodes.Ldc_I4_1) + case 2 => code.Emit(OpCodes.Ldc_I4_2) + case 3 => code.Emit(OpCodes.Ldc_I4_3) + case 4 => code.Emit(OpCodes.Ldc_I4_4) + case 5 => code.Emit(OpCodes.Ldc_I4_5) + case 6 => code.Emit(OpCodes.Ldc_I4_6) + case 7 => code.Emit(OpCodes.Ldc_I4_7) + case 8 => code.Emit(OpCodes.Ldc_I4_8) + case _ => + if (value >= -128 && value <= 127) + code.Emit(OpCodes.Ldc_I4_S, value) + else + code.Emit(OpCodes.Ldc_I4, value) + } + + def loadArg(code: ILGenerator, loadAddr: Boolean)(i: Int) = + if (loadAddr) { + if (i >= -128 && i <= 127) + code.Emit(OpCodes.Ldarga_S, i) + else + code.Emit(OpCodes.Ldarga, i) + } else { + i match { + case 0 => code.Emit(OpCodes.Ldarg_0) + case 1 => code.Emit(OpCodes.Ldarg_1) + case 2 => code.Emit(OpCodes.Ldarg_2) + case 3 => code.Emit(OpCodes.Ldarg_3) + case _ => + if (i >= -128 && i <= 127) + code.Emit(OpCodes.Ldarg_S, i) + else + code.Emit(OpCodes.Ldarg, i) + } + } + + def loadLocal(i: Int, local: Local, code: ILGenerator, loadAddr: Boolean) = + if (loadAddr) { + if (i >= -128 && i <= 127) + code.Emit(OpCodes.Ldloca_S, localBuilders(local)) + else + code.Emit(OpCodes.Ldloca, localBuilders(local)) + } else { + i match { + case 0 => code.Emit(OpCodes.Ldloc_0) + case 1 => code.Emit(OpCodes.Ldloc_1) + case 2 => code.Emit(OpCodes.Ldloc_2) + case 3 => code.Emit(OpCodes.Ldloc_3) + case _ => + if (i >= -128 && i <= 127) + code.Emit(OpCodes.Ldloc_S, localBuilders(local)) + else + code.Emit(OpCodes.Ldloc, localBuilders(local)) + } + } + + ////////////////////// branches /////////////////////// + + /** Returns a Triple (Boolean, Boolean, Option[Label]) + * - whether the jump leaves some exception block (try / catch / finally) + * - whether it leaves a finally handler (finally block, but not it's try / catch) + * - a label where to jump for leaving the finally handler + * . None to leave directly using `endfinally` + * . Some(label) to emit `leave label` (for try / catch inside a finally handler) + */ + def leavesHandler(from: BasicBlock, to: BasicBlock): (Boolean, Boolean, Option[Label]) = + if (currentHandlers.isEmpty) (false, false, None) + else { + val h = currentHandlers.head + val leaveHead = { h.covers(from) != h.covers(to) || + h.blocks.contains(from) != h.blocks.contains(to) } + if (leaveHead) { + // we leave the innermost exception block. + // find out if we also leave som e `finally` handler + currentHandlers.find(e => { + e.cls == NoSymbol && e.blocks.contains(from) != e.blocks.contains(to) + }) match { + case Some(finallyHandler) => + if (h == finallyHandler) { + // the finally handler is the innermost, so we can emit `endfinally` directly + (true, true, None) + } else { + // we need to `Leave` to the `endfinally` of the next outer finally handler + val l = endFinallyLabels.getOrElseUpdate(finallyHandler, mcode.DefineLabel()) + (true, true, Some(l)) + } + case None => + (true, false, None) + } + } else (false, false, None) + } + + def emitCondBr(block: BasicBlock, cond: TestOp, success: BasicBlock, failure: BasicBlock, + next: BasicBlock, emitBrFun: (TestOp, Label) => Unit) { + val (sLeaveHandler, sLeaveFinally, slfTarget) = leavesHandler(block, success) + val (fLeaveHandler, fLeaveFinally, flfTarget) = leavesHandler(block, failure) + + if (sLeaveHandler || fLeaveHandler) { + val sLabelOpt = if (sLeaveHandler) { + val leaveSLabel = mcode.DefineLabel() + emitBrFun(cond, leaveSLabel) + Some(leaveSLabel) + } else { + emitBrFun(cond, labels(success)) + None + } + + if (fLeaveHandler) { + if (fLeaveFinally) { + if (flfTarget.isDefined) mcode.Emit(OpCodes.Leave, flfTarget.get) + else mcode.Emit(OpCodes.Endfinally) + } else + mcode.Emit(OpCodes.Leave, labels(failure)) + } else + mcode.Emit(OpCodes.Br, labels(failure)) + + sLabelOpt.map(l => { + mcode.MarkLabel(l) + if (sLeaveFinally) { + if (slfTarget.isDefined) mcode.Emit(OpCodes.Leave, slfTarget.get) + else mcode.Emit(OpCodes.Endfinally) + } else + mcode.Emit(OpCodes.Leave, labels(success)) + }) + } else { + if (next == success) { + emitBrFun(cond.negate, labels(failure)) + } else { + emitBrFun(cond, labels(success)) + if (next != failure) { + mcode.Emit(OpCodes.Br, labels(failure)) + } + } + } + } + + def emitBr(condition: TestOp, dest: Label, isFloat: Boolean) { + condition match { + case EQ => mcode.Emit(OpCodes.Beq, dest) + case NE => mcode.Emit(OpCodes.Bne_Un, dest) + case LT => mcode.Emit(if (isFloat) OpCodes.Blt_Un else OpCodes.Blt, dest) + case GE => mcode.Emit(if (isFloat) OpCodes.Bge_Un else OpCodes.Bge, dest) + case LE => mcode.Emit(if (isFloat) OpCodes.Ble_Un else OpCodes.Ble, dest) + case GT => mcode.Emit(if (isFloat) OpCodes.Bgt_Un else OpCodes.Bgt, dest) + } + } + + def emitBrBool(cond: TestOp, dest: Label) { + cond match { + // EQ -> Brfalse, NE -> Brtrue; this is because we come from + // a CZJUMP. If the value on the stack is 0 (e.g. a boolean + // method returned false), and we are in the case EQ, then + // we need to emit Brfalse (EQ Zero means false). vice versa + case EQ => mcode.Emit(OpCodes.Brfalse, dest) + case NE => mcode.Emit(OpCodes.Brtrue, dest) + } + } + + ////////////////////// local vars /////////////////////// + + /** + * Compute the indexes of each local variable of the given + * method. + */ + def computeLocalVarsIndex(m: IMethod) { + var idx = if (m.symbol.isStaticMember) 0 else 1 + + val params = m.params + for (l <- params) { + debuglog("Index value for parameter " + l + ": " + idx) + l.index = idx + idx += 1 // sizeOf(l.kind) + } + + val locvars = m.locals filterNot (params contains) + idx = 0 + + for (l <- locvars) { + debuglog("Index value for local variable " + l + ": " + idx) + l.index = idx + idx += 1 // sizeOf(l.kind) + } + + } + + ////////////////////// Utilities //////////////////////// + + /** Return the a name of this symbol that can be used on the .NET + * platform. It removes spaces from names. + * + * Special handling: scala.All and scala.AllRef are 'erased' to + * scala.All$ and scala.AllRef$. This is needed because they are + * not real classes, and they mean 'abrupt termination upon evaluation + * of that expression' or 'null' respectively. This handling is + * done already in GenICode, but here we need to remove references + * from method signatures to these types, because such classes can + * not exist in the classpath: the type checker will be very confused. + */ + def msilName(sym: Symbol): String = { + val suffix = sym.moduleSuffix + // Flags.JAVA: "symbol was not defined by a scala-class" (java, or .net-class) + + if (sym == definitions.NothingClass) + return "scala.runtime.Nothing$" + else if (sym == definitions.NullClass) + return "scala.runtime.Null$" + + (if (sym.isClass || (sym.isModule && !sym.isMethod)) { + if (sym.isNestedClass) sym.simpleName + else sym.fullName + } else + sym.simpleName.toString.trim()) + suffix + } + + + ////////////////////// flags /////////////////////// + + def msilTypeFlags(sym: Symbol): Int = { + var mf: Int = TypeAttributes.AutoLayout | TypeAttributes.AnsiClass + + if(sym.isNestedClass) { + mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NestedPrivate else TypeAttributes.NestedPublic) + } else { + mf = mf | (if (sym hasFlag Flags.PRIVATE) TypeAttributes.NotPublic else TypeAttributes.Public) + } + mf = mf | (if (sym hasFlag Flags.ABSTRACT) TypeAttributes.Abstract else 0) + mf = mf | (if (sym.isTrait && !sym.isImplClass) TypeAttributes.Interface else TypeAttributes.Class) + mf = mf | (if (sym isFinal) TypeAttributes.Sealed else 0) + + sym.annotations foreach { a => a match { + case AnnotationInfo(SerializableAttr, _, _) => + // TODO: add the Serializable TypeAttribute also if the annotation + // System.SerializableAttribute is present (.net annotation, not scala) + // Best way to do it: compare with + // definitions.getClass("System.SerializableAttribute").tpe + // when frontend available + mf = mf | TypeAttributes.Serializable + case _ => () + }} + + mf + // static: not possible (or?) + } + + def msilMethodFlags(sym: Symbol): Short = { + var mf: Int = MethodAttributes.HideBySig | + (if (sym hasFlag Flags.PRIVATE) MethodAttributes.Private + else MethodAttributes.Public) + + if (!sym.isClassConstructor) { + if (sym.isStaticMember) + mf = mf | FieldAttributes.Static // coincidentally, same value as for MethodAttributes.Static ... + else { + mf = mf | MethodAttributes.Virtual + if (sym.isFinal && !getType(sym.owner).IsInterface) + mf = mf | MethodAttributes.Final + if (sym.isDeferred || getType(sym.owner).IsInterface) + mf = mf | MethodAttributes.Abstract + } + } + + if (sym.isStaticMember) { + mf = mf | MethodAttributes.Static + } + + // constructors of module classes should be private + if (sym.isPrimaryConstructor && isTopLevelModule(sym.owner)) { + mf |= MethodAttributes.Private + mf &= ~(MethodAttributes.Public) + } + + mf.toShort + } + + def msilFieldFlags(sym: Symbol): Short = { + var mf: Int = + if (sym hasFlag Flags.PRIVATE) FieldAttributes.Private + else if (sym hasFlag Flags.PROTECTED) FieldAttributes.FamORAssem + else FieldAttributes.Public + + if (sym hasFlag Flags.FINAL) + mf = mf | FieldAttributes.InitOnly + + if (sym.isStaticMember) + mf = mf | FieldAttributes.Static + + // TRANSIENT: "not serialized", VOLATILE: doesn't exist on .net + // TODO: add this annotation also if the class has the custom attribute + // System.NotSerializedAttribute + sym.annotations.foreach( a => a match { + case AnnotationInfo(TransientAtt, _, _) => + mf = mf | FieldAttributes.NotSerialized + case _ => () + }) + + mf.toShort + } + + ////////////////////// builders, types /////////////////////// + + var entryPoint: Symbol = _ + + val notInitializedModules = mutable.HashSet[Symbol]() + + // TODO: create fields also in def createType, and not in genClass, + // add a getField method (it only works as it is because fields never + // accessed from outside a class) + + val localBuilders = mutable.HashMap[Local, LocalBuilder]() + + private[GenMSIL] def findEntryPoint(cls: IClass) { + + def isEntryPoint(sym: Symbol):Boolean = { + if (isStaticModule(sym.owner) && msilName(sym) == "main") + if (sym.tpe.paramTypes.length == 1) { + toTypeKind(sym.tpe.paramTypes(0)) match { + case ARRAY(elem) => + if (elem.toType.typeSymbol == definitions.StringClass) { + return true + } + case _ => () + } + } + false + } + + if((entryPoint == null) && opt.showClass.isDefined) { // TODO introduce dedicated setting instead + val entryclass = opt.showClass.get.toString + val cfn = cls.symbol.fullName + if(cfn == entryclass) { + for (m <- cls.methods; if isEntryPoint(m.symbol)) { entryPoint = m.symbol } + if(entryPoint == null) { warning("Couldn't find main method in class " + cfn) } + } + } + + if (firstSourceName == "") + if (cls.symbol.sourceFile != null) // is null for nested classes + firstSourceName = cls.symbol.sourceFile.name + } + + // ##################################################################### + // get and create types + + private def msilType(t: TypeKind): MsilType = (t: @unchecked) match { + case UNIT => MVOID + case BOOL => MBOOL + case BYTE => MBYTE + case SHORT => MSHORT + case CHAR => MCHAR + case INT => MINT + case LONG => MLONG + case FLOAT => MFLOAT + case DOUBLE => MDOUBLE + case REFERENCE(cls) => getType(cls) + case ARRAY(elem) => + msilType(elem) match { + // For type builders, cannot call "clrTypes.mkArrayType" because this looks up + // the type "tp" in the assembly (not in the HashMap "types" of the backend). + // This can fail for nested types because the builders are not complete yet. + case tb: TypeBuilder => tb.MakeArrayType() + case tp: MsilType => clrTypes.mkArrayType(tp) + } + } + + private def msilType(tpe: Type): MsilType = msilType(toTypeKind(tpe)) + + private def msilParamTypes(sym: Symbol): Array[MsilType] = { + sym.tpe.paramTypes.map(msilType).toArray + } + + def getType(sym: Symbol) = getTypeOpt(sym).getOrElse(abort(showsym(sym))) + + /** + * Get an MSIL type from a symbol. First look in the clrTypes.types map, then + * lookup the name using clrTypes.getType + */ + def getTypeOpt(sym: Symbol): Option[MsilType] = { + val tmp = types.get(sym) + tmp match { + case typ @ Some(_) => typ + case None => + def typeString(sym: Symbol): String = { + val s = if (sym.isNestedClass) typeString(sym.owner) +"+"+ sym.simpleName + else sym.fullName + if (sym.isModuleClass && !sym.isTrait) s + "$" else s + } + val name = typeString(sym) + val typ = clrTypes.getType(name) + if (typ == null) + None + else { + types(sym) = typ + Some(typ) + } + } + } + + def mapType(sym: Symbol, mType: MsilType) { + assert(mType != null, showsym(sym)) + types(sym) = mType + } + + def createTypeBuilder(iclass: IClass) { + /** + * First look in the clrTypes.types map, if that fails check if it's a class being compiled, otherwise + * lookup by name (clrTypes.getType calls the static method msil.Type.GetType(fullname)). + */ + def msilTypeFromSym(sym: Symbol): MsilType = { + types.get(sym).getOrElse { + classes.get(sym) match { + case Some(iclass) => + msilTypeBuilderFromSym(sym) + case None => + getType(sym) + } + } + } + + def msilTypeBuilderFromSym(sym: Symbol): TypeBuilder = { + if(!(types.contains(sym) && types(sym).isInstanceOf[TypeBuilder])){ + val iclass = classes(sym) + assert(iclass != null) + createTypeBuilder(iclass) + } + types(sym).asInstanceOf[TypeBuilder] + } + + val sym = iclass.symbol + if (types.contains(sym) && types(sym).isInstanceOf[TypeBuilder]) + return + + def isInterface(s: Symbol) = s.isTrait && !s.isImplClass + val parents: List[Type] = + if (sym.info.parents.isEmpty) List(definitions.ObjectClass.tpe) + else sym.info.parents.distinct + + val superType : MsilType = if (isInterface(sym)) null else msilTypeFromSym(parents.head.typeSymbol) + debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType) + + val interfaces: Array[MsilType] = + parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray + if (parents.length > 1) { + if (settings.debug.value) { + log("interfaces:") + for (i <- 0.until(interfaces.length)) { + log(" type: " + parents(i + 1).typeSymbol + ", msil type: " + interfaces(i)) + } + } + } + + val tBuilder = if (sym.isNestedClass) { + val ownerT = msilTypeBuilderFromSym(sym.owner).asInstanceOf[TypeBuilder] + ownerT.DefineNestedType(msilName(sym), msilTypeFlags(sym), superType, interfaces) + } else { + mmodule.DefineType(msilName(sym), msilTypeFlags(sym), superType, interfaces) + } + mapType(sym, tBuilder) + } // createTypeBuilder + + def createClassMembers(iclass: IClass) { + try { + createClassMembers0(iclass) + } + catch { + case e: Throwable => + java.lang.System.err.println(showsym(iclass.symbol)) + java.lang.System.err.println("with methods = " + iclass.methods) + throw e + } + } + + def createClassMembers0(iclass: IClass) { + + val mtype = getType(iclass.symbol).asInstanceOf[TypeBuilder] + + for (ifield <- iclass.fields) { + val sym = ifield.symbol + debuglog("Adding field: " + sym.fullName) + + var attributes = msilFieldFlags(sym) + val fieldTypeWithCustomMods = + new PECustomMod(msilType(sym.tpe), + customModifiers(sym.annotations)) + val fBuilder = mtype.DefineField(msilName(sym), + fieldTypeWithCustomMods, + attributes) + fields(sym) = fBuilder + addAttributes(fBuilder, sym.annotations) + } // all iclass.fields iterated over + + if (isStaticModule(iclass.symbol)) { + val sc = iclass.lookupStaticCtor + if (sc.isDefined) { + val m = sc.get + val oldLastBlock = m.lastBlock + val lastBlock = m.newBlock() + oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock)) + // call object's private ctor from static ctor + lastBlock.emit(CIL_NEWOBJ(iclass.symbol.primaryConstructor)) + lastBlock.emit(DROP(toTypeKind(iclass.symbol.tpe))) + lastBlock emit RETURN(UNIT) + lastBlock.close + } + } + + if (iclass.symbol != definitions.ArrayClass) { + for (m: IMethod <- iclass.methods) { + val sym = m.symbol + debuglog("Creating MethodBuilder for " + Flags.flagsToString(sym.flags) + " " + + sym.owner.fullName + "::" + sym.name) + + val ownerType = getType(sym.enclClass).asInstanceOf[TypeBuilder] + assert(mtype == ownerType, "mtype = " + mtype + "; ownerType = " + ownerType) + var paramTypes = msilParamTypes(sym) + val attr = msilMethodFlags(sym) + + if (m.symbol.isClassConstructor) { + val constr = + ownerType.DefineConstructor(attr, CallingConventions.Standard, paramTypes) + for (i <- 0.until(paramTypes.length)) { + constr.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) + } + mapConstructor(sym, constr) + addAttributes(constr, sym.annotations) + } else { + var resType = msilType(m.returnType) + val method = + ownerType.DefineMethod(msilName(sym), attr, resType, paramTypes) + for (i <- 0.until(paramTypes.length)) { + method.DefineParameter(i, ParameterAttributes.None, msilName(m.params(i).sym)) + } + if (!methods.contains(sym)) + mapMethod(sym, method) + addAttributes(method, sym.annotations) + debuglog("\t created MethodBuilder " + method) + } + } + } // method builders created for non-array iclass + + if (isStaticModule(iclass.symbol)) { + addModuleInstanceField(iclass.symbol) + notInitializedModules += iclass.symbol + if (iclass.lookupStaticCtor.isEmpty) { + addStaticInit(iclass.symbol) + } + } + + } // createClassMembers0 + + private def isTopLevelModule(sym: Symbol): Boolean = + atPhase (currentRun.refchecksPhase) { + sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass + } + + // if the module is lifted it does not need to be initialized in + // its static constructor, and the MODULE$ field is not required. + // the outer class will care about it. + private def isStaticModule(sym: Symbol): Boolean = { + // .net inner classes: removed '!sym.hasFlag(Flags.LIFTED)', added + // 'sym.isStatic'. -> no longer compatible without skipping flatten! + sym.isModuleClass && sym.isStatic && !sym.isImplClass + } + + private def isCloneable(sym: Symbol): Boolean = { + !sym.annotations.forall( a => a match { + case AnnotationInfo(CloneableAttr, _, _) => false + case _ => true + }) + } + + private def addModuleInstanceField(sym: Symbol) { + debuglog("Adding Module-Instance Field for " + showsym(sym)) + val tBuilder = getType(sym).asInstanceOf[TypeBuilder] + val fb = tBuilder.DefineField(MODULE_INSTANCE_NAME, + tBuilder, + (FieldAttributes.Public | + //FieldAttributes.InitOnly | + FieldAttributes.Static).toShort) + fields(sym) = fb + } + + + // the symbol may be a object-symbol (module-symbol), or a module-class-symbol + private def getModuleInstanceField(sym: Symbol): FieldInfo = { + assert(sym.isModule || sym.isModuleClass, "Expected module: " + showsym(sym)) + + // when called by LOAD_MODULE, the corresponding type maybe doesn't + // exist yet -> make a getType + val moduleClassSym = if (sym.isModule) sym.moduleClass else sym + + // TODO: get module field for modules not defined in the + // source currently compiling (e.g. Console) + + fields get moduleClassSym match { + case Some(sym) => sym + case None => + //val mclass = types(moduleClassSym) + val nameInMetadata = nestingAwareFullClassname(moduleClassSym) + val mClass = clrTypes.getType(nameInMetadata) + val mfield = mClass.GetField("MODULE$") + assert(mfield ne null, "module not found " + showsym(moduleClassSym)) + fields(moduleClassSym) = mfield + mfield + } + + //fields(moduleClassSym) + } + + def nestingAwareFullClassname(csym: Symbol) : String = { + val suffix = csym.moduleSuffix + val res = if (csym.isNestedClass) + nestingAwareFullClassname(csym.owner) + "+" + csym.encodedName + else + csym.fullName + res + suffix + } + + /** Adds a static initializer which creates an instance of the module + * class (calls the primary constructor). A special primary constructor + * will be generated (notInitializedModules) which stores the new instance + * in the MODULE$ field right after the super call. + */ + private def addStaticInit(sym: Symbol) { + val tBuilder = getType(sym).asInstanceOf[TypeBuilder] + + val staticInit = tBuilder.DefineConstructor( + (MethodAttributes.Static | MethodAttributes.Public).toShort, + CallingConventions.Standard, + MsilType.EmptyTypes) + + val sicode = staticInit.GetILGenerator() + + val instanceConstructor = constructors(sym.primaryConstructor) + + // there are no constructor parameters. assuming the constructor takes no parameter + // is fine: we call (in the static constructor) the constructor of the module class, + // which takes no arguments - an object definition cannot take constructor arguments. + sicode.Emit(OpCodes.Newobj, instanceConstructor) + // the stsfld is done in the instance constructor, just after the super call. + sicode.Emit(OpCodes.Pop) + + sicode.Emit(OpCodes.Ret) + } + + private def generateMirrorClass(sym: Symbol) { + val tBuilder = getType(sym) + assert(sym.isModuleClass, "Can't generate Mirror-Class for the Non-Module class " + sym) + debuglog("Dumping mirror class for object: " + sym) + val moduleName = msilName(sym) + val mirrorName = moduleName.substring(0, moduleName.length() - 1) + val mirrorTypeBuilder = mmodule.DefineType(mirrorName, + TypeAttributes.Class | + TypeAttributes.Public | + TypeAttributes.Sealed, + MOBJECT, + MsilType.EmptyTypes) + + val iclass = classes(sym) + + for (m <- sym.tpe.nonPrivateMembers + if m.owner != definitions.ObjectClass && !m.isProtected && + m.isMethod && !m.isClassConstructor && !m.isStaticMember && !m.isCase && + !m.isDeferred) + { + debuglog(" Mirroring method: " + m) + val paramTypes = msilParamTypes(m) + val paramNames: Array[String] = new Array[String](paramTypes.length) + for (i <- 0 until paramTypes.length) + paramNames(i) = "x_" + i + + // CHECK: verify if getMethodName is better than msilName + val mirrorMethod = mirrorTypeBuilder.DefineMethod(msilName(m), + (MethodAttributes.Public | + MethodAttributes.Static).toShort, + msilType(m.tpe.resultType), + paramTypes) + + var i = 0 + while (i < paramTypes.length) { + mirrorMethod.DefineParameter(i, ParameterAttributes.None, paramNames(i)) + i += 1 + } + + val mirrorCode = mirrorMethod.GetILGenerator() + mirrorCode.Emit(OpCodes.Ldsfld, getModuleInstanceField(sym)) + val mInfo = getMethod(m) + for (paramidx <- 0.until(paramTypes.length)) { + val mInfoParams = mInfo.GetParameters + val loadAddr = mInfoParams(paramidx).ParameterType.IsByRef + loadArg(mirrorCode, loadAddr)(paramidx) + } + + mirrorCode.Emit(OpCodes.Callvirt, getMethod(m)) + mirrorCode.Emit(OpCodes.Ret) + } + + addSymtabAttribute(sym.sourceModule, mirrorTypeBuilder) + + mirrorTypeBuilder.CreateType() + mirrorTypeBuilder.setSourceFilepath(iclass.cunit.source.file.path) + } + + + // ##################################################################### + // delegate callers + + var delegateCallers: TypeBuilder = _ + var nbDelegateCallers: Int = 0 + + private def initDelegateCallers() = { + delegateCallers = mmodule.DefineType("$DelegateCallers", TypeAttributes.Public | + TypeAttributes.Sealed) + } + + private def createDelegateCaller(functionType: Type, delegateType: Type) = { + if (delegateCallers == null) + initDelegateCallers() + // create a field an store the function-object + val mFunctionType: MsilType = msilType(functionType) + val anonfunField: FieldBuilder = delegateCallers.DefineField( + "$anonfunField$$" + nbDelegateCallers, mFunctionType, + (FieldAttributes.InitOnly | FieldAttributes.Public | FieldAttributes.Static).toShort) + mcode.Emit(OpCodes.Stsfld, anonfunField) + + + // create the static caller method and the delegate object + val (params, returnType) = delegateType.member(nme.apply).tpe match { + case MethodType(delParams, delReturn) => (delParams, delReturn) + case _ => abort("not a delegate type: " + delegateType) + } + val caller: MethodBuilder = delegateCallers.DefineMethod( + "$delegateCaller$$" + nbDelegateCallers, + (MethodAttributes.Final | MethodAttributes.Public | MethodAttributes.Static).toShort, + msilType(returnType), (params map (_.tpe)).map(msilType).toArray) + for (i <- 0 until params.length) + caller.DefineParameter(i, ParameterAttributes.None, "arg" + i) // FIXME: use name of parameter symbol + val delegCtor = msilType(delegateType).GetConstructor(Array(MOBJECT, INT_PTR)) + mcode.Emit(OpCodes.Ldnull) + mcode.Emit(OpCodes.Ldftn, caller) + mcode.Emit(OpCodes.Newobj, delegCtor) + + + // create the static caller method body + val functionApply: MethodInfo = getMethod(functionType.member(nme.apply)) + val dcode: ILGenerator = caller.GetILGenerator() + dcode.Emit(OpCodes.Ldsfld, anonfunField) + for (i <- 0 until params.length) { + loadArg(dcode, false /* TODO confirm whether passing actual as-is to formal is correct wrt the ByRef attribute of the param */)(i) + emitBox(dcode, toTypeKind(params(i).tpe)) + } + dcode.Emit(OpCodes.Callvirt, functionApply) + emitUnbox(dcode, toTypeKind(returnType)) + dcode.Emit(OpCodes.Ret) + + nbDelegateCallers = nbDelegateCallers + 1 + + } //def createDelegateCaller + + def emitBox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { + // doesn't make sense, unit as parameter.. + case UNIT => code.Emit(OpCodes.Ldsfld, boxedUnit) + case BOOL | BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE => + code.Emit(OpCodes.Box, msilType(boxType)) + case REFERENCE(cls) if clrTypes.isValueType(cls) => + code.Emit(OpCodes.Box, (msilType(boxType))) + case REFERENCE(_) | ARRAY(_) => + warning("Tried to BOX a non-valuetype.") + () + } + + def emitUnbox(code: ILGenerator, boxType: TypeKind) = (boxType: @unchecked) match { + case UNIT => code.Emit(OpCodes.Pop) + /* (1) it's essential to keep the code emitted here (as of now plain calls to System.Convert.ToBlaBla methods) + behaviorally.equiv.wrt. BoxesRunTime.unboxToBlaBla methods + (case null: that's easy, case boxed: track changes to unboxBlaBla) + (2) See also: asInstanceOf to cast from Any to number, + tracked in http://lampsvn.epfl.ch/trac/scala/ticket/4437 */ + case BOOL => code.Emit(OpCodes.Call, toBool) + case BYTE => code.Emit(OpCodes.Call, toSByte) + case SHORT => code.Emit(OpCodes.Call, toShort) + case CHAR => code.Emit(OpCodes.Call, toChar) + case INT => code.Emit(OpCodes.Call, toInt) + case LONG => code.Emit(OpCodes.Call, toLong) + case FLOAT => code.Emit(OpCodes.Call, toFloat) + case DOUBLE => code.Emit(OpCodes.Call, toDouble) + case REFERENCE(cls) if clrTypes.isValueType(cls) => + code.Emit(OpCodes.Unbox, msilType(boxType)) + code.Emit(OpCodes.Ldobj, msilType(boxType)) + case REFERENCE(_) | ARRAY(_) => + warning("Tried to UNBOX a non-valuetype.") + () + } + + // ##################################################################### + // get and create methods / constructors + + def getConstructor(sym: Symbol): ConstructorInfo = constructors.get(sym) match { + case Some(constr) => constr + case None => + val mClass = getType(sym.owner) + val constr = mClass.GetConstructor(msilParamTypes(sym)) + if (constr eq null) { + java.lang.System.out.println("Cannot find constructor " + sym.owner + "::" + sym.name) + java.lang.System.out.println("scope = " + sym.owner.tpe.decls) + abort(sym.fullName) + } + else { + mapConstructor(sym, constr) + constr + } + } + + def mapConstructor(sym: Symbol, cInfo: ConstructorInfo) = { + constructors(sym) = cInfo + } + + private def getMethod(sym: Symbol): MethodInfo = { + + methods.get(sym) match { + case Some(method) => method + case None => + val mClass = getType(sym.owner) + try { + val method = mClass.GetMethod(msilName(sym), msilParamTypes(sym), + msilType(sym.tpe.resultType)) + if (method eq null) { + java.lang.System.out.println("Cannot find method " + sym.owner + "::" + msilName(sym)) + java.lang.System.out.println("scope = " + sym.owner.tpe.decls) + abort(sym.fullName) + } + else { + mapMethod(sym, method) + method + } + } + catch { + case e: Exception => + Console.println("While looking up " + mClass + "::" + sym.nameString) + Console.println("\t" + showsym(sym)) + throw e + } + } + } + + /* + * add a mapping between sym and mInfo + */ + private def mapMethod(sym: Symbol, mInfo: MethodInfo) { + assert (mInfo != null, mInfo) + methods(sym) = mInfo + } + + /* + * add mapping between sym and method with newName, paramTypes of newClass + */ + private def mapMethod(sym: Symbol, newClass: MsilType, newName: String, paramTypes: Array[MsilType]) { + val methodInfo = newClass.GetMethod(newName, paramTypes) + assert(methodInfo != null, "Can't find mapping for " + sym + " -> " + + newName + "(" + paramTypes + ")") + mapMethod(sym, methodInfo) + if (methodInfo.IsStatic) + dynToStatMapped += sym + } + + /* + * add mapping between method with name and paramTypes of clazz to + * method with newName and newParamTypes of newClass (used for instance + * for "wait") + */ + private def mapMethod( + clazz: Symbol, name: Name, paramTypes: Array[Type], + newClass: MsilType, newName: String, newParamTypes: Array[MsilType]) { + val methodSym = lookupMethod(clazz, name, paramTypes) + assert(methodSym != null, "cannot find method " + name + "(" + + paramTypes + ")" + " in class " + clazz) + mapMethod(methodSym, newClass, newName, newParamTypes) + } + + /* + * add mapping for member with name and paramTypes to member + * newName of newClass (same parameters) + */ + private def mapMethod( + clazz: Symbol, name: Name, paramTypes: Array[Type], + newClass: MsilType, newName: String) { + mapMethod(clazz, name, paramTypes, newClass, newName, paramTypes map msilType) + } + + /* + * add mapping for all methods with name of clazz to the corresponding + * method (same parameters) with newName of newClass + */ + private def mapMethod( + clazz: Symbol, name: Name, + newClass: MsilType, newName: String) { + val memberSym: Symbol = clazz.tpe.member(name) + memberSym.tpe match { + // alternatives: List[Symbol] + case OverloadedType(_, alternatives) => + alternatives.foreach(s => mapMethod(s, newClass, newName, msilParamTypes(s))) + + // paramTypes: List[Type], resType: Type + case MethodType(params, resType) => + mapMethod(memberSym, newClass, newName, msilParamTypes(memberSym)) + + case _ => + abort("member not found: " + clazz + ", " + name) + } + } + + + /* + * find the method in clazz with name and paramTypes + */ + private def lookupMethod(clazz: Symbol, name: Name, paramTypes: Array[Type]): Symbol = { + val memberSym = clazz.tpe.member(name) + memberSym.tpe match { + case OverloadedType(_, alternatives) => + alternatives.find(s => { + var i: Int = 0 + var typesOK: Boolean = true + if (paramTypes.length == s.tpe.paramTypes.length) { + while(i < paramTypes.length) { + if (paramTypes(i) != s.tpe.paramTypes(i)) + typesOK = false + i += 1 + } + } else { + typesOK = false + } + typesOK + }) match { + case Some(sym) => sym + case None => abort("member of " + clazz + ", " + name + "(" + + paramTypes + ") not found") + } + + case MethodType(_, _) => memberSym + + case _ => abort("member not found: " + name + " of " + clazz) + } + } + + private def showsym(sym: Symbol): String = (sym.toString + + "\n symbol = " + Flags.flagsToString(sym.flags) + " " + sym + + "\n owner = " + Flags.flagsToString(sym.owner.flags) + " " + sym.owner + ) + + } // class BytecodeGenerator + +} // class GenMSIL +*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala index 2982812fdd..aeaa1b759b 100644 --- a/src/compiler/scala/tools/nsc/io/MsilFile.scala +++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala @@ -1,18 +1,19 @@ -// /* NSC -- new Scala compiler -// * Copyright 2005-2011 LAMP/EPFL -// * @author Paul Phillips -// */ -// -// package scala.tools.nsc -// package io -// +/* NSC -- new Scala compiler + * Copyright 2005-2011 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools.nsc +package io + // import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } -// -// /** This class wraps an MsilType. It exists only so -// * ClassPath can treat all of JVM/MSIL/bin/src files -// * uniformly, as AbstractFiles. -// */ -// class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { -// } -// -// object NoMsilFile extends MsilFile(null) { } + +/** This class wraps an MsilType. It exists only so + * ClassPath can treat all of JVM/MSIL/bin/src files + * uniformly, as AbstractFiles. + */ +class MsilFile /* (val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { +} + +object NoMsilFile extends MsilFile(null) { } +*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala index 4346cb6f8d..469f7ce3ab 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala @@ -1,137 +1,138 @@ -// /* NSC -- new scala compiler -// * Copyright 2004-2011 LAMP/EPFL -// */ -// -// -// package scala.tools.nsc -// package symtab -// package clr -// +/* NSC -- new scala compiler + * Copyright 2004-2011 LAMP/EPFL + */ + + +package scala.tools.nsc +package symtab +package clr + // import java.io.File // import java.util.{Comparator, StringTokenizer} // import scala.util.Sorting // import ch.epfl.lamp.compiler.msil._ // import scala.collection.{ mutable, immutable } // import scala.tools.nsc.util.{Position, NoPosition} -// -// /** -// * Collects all types from all reference assemblies. -// */ -// abstract class CLRTypes { -// -// val global: Global -// import global.Symbol -// import global.definitions -// -// //########################################################################## -// -// var BYTE: Type = _ -// var UBYTE: Type = _ -// var SHORT: Type = _ -// var USHORT: Type = _ -// var CHAR: Type = _ -// var INT: Type = _ -// var UINT: Type = _ -// var LONG: Type = _ -// var ULONG: Type = _ -// var FLOAT: Type = _ -// var DOUBLE: Type = _ -// var BOOLEAN: Type = _ -// var VOID: Type = _ -// var ENUM: Type = _ -// var DELEGATE: Type = _ -// -// var OBJECT: Type = _ -// var STRING: Type = _ -// var STRING_ARRAY: Type = _ -// -// var VALUE_TYPE: Type = _ -// -// var SCALA_SYMTAB_ATTR: Type = _ -// var SYMTAB_CONSTR: ConstructorInfo = _ -// var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _ -// -// var DELEGATE_COMBINE: MethodInfo = _ -// var DELEGATE_REMOVE: MethodInfo = _ -// -// val types: mutable.Map[Symbol,Type] = new mutable.HashMap -// val constructors: mutable.Map[Symbol,ConstructorInfo] = new mutable.HashMap -// val methods: mutable.Map[Symbol,MethodInfo] = new mutable.HashMap -// val fields: mutable.Map[Symbol, FieldInfo] = new mutable.HashMap -// val sym2type: mutable.Map[Type,Symbol] = new mutable.HashMap -// val addressOfViews = new mutable.HashSet[Symbol] -// val mdgptrcls4clssym: mutable.Map[ /*cls*/ Symbol, /*cls*/ Symbol] = new mutable.HashMap -// -// def isAddressOf(msym : Symbol) = addressOfViews.contains(msym) -// -// def isNonEnumValuetype(cls: Symbol) = { -// val msilTOpt = types.get(cls) -// val res = msilTOpt.isDefined && { -// val msilT = msilTOpt.get -// msilT.IsValueType && !msilT.IsEnum -// } -// res -// } -// -// def isValueType(cls: Symbol): Boolean = { -// val opt = types.get(cls) -// opt.isDefined && opt.get.IsValueType -// } -// -// def init() = try { // initialize -// // the MsilClasspath (nsc/util/Classpath.scala) initializes the msil-library by calling -// // Assembly.LoadFrom("mscorlib.dll"), so this type should be found -// Type.initMSCORLIB(getTypeSafe("System.String").Assembly) -// -// BYTE = getTypeSafe("System.SByte") -// UBYTE = getTypeSafe("System.Byte") -// CHAR = getTypeSafe("System.Char") -// SHORT = getTypeSafe("System.Int16") -// USHORT = getTypeSafe("System.UInt16") -// INT = getTypeSafe("System.Int32") -// UINT = getTypeSafe("System.UInt32") -// LONG = getTypeSafe("System.Int64") -// ULONG = getTypeSafe("System.UInt64") -// FLOAT = getTypeSafe("System.Single") -// DOUBLE = getTypeSafe("System.Double") -// BOOLEAN = getTypeSafe("System.Boolean") -// VOID = getTypeSafe("System.Void") -// ENUM = getTypeSafe("System.Enum") -// DELEGATE = getTypeSafe("System.MulticastDelegate") -// -// OBJECT = getTypeSafe("System.Object") -// STRING = getTypeSafe("System.String") -// STRING_ARRAY = getTypeSafe("System.String[]") -// VALUE_TYPE = getTypeSafe("System.ValueType") -// -// SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute") -// val bytearray: Array[Type] = Array(Type.GetType("System.Byte[]")) -// SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray) -// SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes) -// -// val delegate: Type = getTypeSafe("System.Delegate") -// val dargs: Array[Type] = Array(delegate, delegate) -// DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs) -// DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs) -// } -// catch { -// case e: RuntimeException => -// Console.println(e.getMessage) -// throw e -// } -// -// //########################################################################## -// // type mapping and lookup -// -// def getType(name: String): Type = Type.GetType(name) -// -// def getTypeSafe(name: String): Type = { -// val t = Type.GetType(name) -// assert(t != null, name) -// t -// } -// -// def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]") -// -// def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE } -// } // CLRTypes + +/** + * Collects all types from all reference assemblies. + */ +abstract class CLRTypes /*{ + + val global: Global + import global.Symbol + import global.definitions + + //########################################################################## + + var BYTE: Type = _ + var UBYTE: Type = _ + var SHORT: Type = _ + var USHORT: Type = _ + var CHAR: Type = _ + var INT: Type = _ + var UINT: Type = _ + var LONG: Type = _ + var ULONG: Type = _ + var FLOAT: Type = _ + var DOUBLE: Type = _ + var BOOLEAN: Type = _ + var VOID: Type = _ + var ENUM: Type = _ + var DELEGATE: Type = _ + + var OBJECT: Type = _ + var STRING: Type = _ + var STRING_ARRAY: Type = _ + + var VALUE_TYPE: Type = _ + + var SCALA_SYMTAB_ATTR: Type = _ + var SYMTAB_CONSTR: ConstructorInfo = _ + var SYMTAB_DEFAULT_CONSTR: ConstructorInfo = _ + + var DELEGATE_COMBINE: MethodInfo = _ + var DELEGATE_REMOVE: MethodInfo = _ + + val types: mutable.Map[Symbol,Type] = new mutable.HashMap + val constructors: mutable.Map[Symbol,ConstructorInfo] = new mutable.HashMap + val methods: mutable.Map[Symbol,MethodInfo] = new mutable.HashMap + val fields: mutable.Map[Symbol, FieldInfo] = new mutable.HashMap + val sym2type: mutable.Map[Type,Symbol] = new mutable.HashMap + val addressOfViews = new mutable.HashSet[Symbol] + val mdgptrcls4clssym: mutable.Map[ /*cls*/ Symbol, /*cls*/ Symbol] = new mutable.HashMap + + def isAddressOf(msym : Symbol) = addressOfViews.contains(msym) + + def isNonEnumValuetype(cls: Symbol) = { + val msilTOpt = types.get(cls) + val res = msilTOpt.isDefined && { + val msilT = msilTOpt.get + msilT.IsValueType && !msilT.IsEnum + } + res + } + + def isValueType(cls: Symbol): Boolean = { + val opt = types.get(cls) + opt.isDefined && opt.get.IsValueType + } + + def init() = try { // initialize + // the MsilClasspath (nsc/util/Classpath.scala) initializes the msil-library by calling + // Assembly.LoadFrom("mscorlib.dll"), so this type should be found + Type.initMSCORLIB(getTypeSafe("System.String").Assembly) + + BYTE = getTypeSafe("System.SByte") + UBYTE = getTypeSafe("System.Byte") + CHAR = getTypeSafe("System.Char") + SHORT = getTypeSafe("System.Int16") + USHORT = getTypeSafe("System.UInt16") + INT = getTypeSafe("System.Int32") + UINT = getTypeSafe("System.UInt32") + LONG = getTypeSafe("System.Int64") + ULONG = getTypeSafe("System.UInt64") + FLOAT = getTypeSafe("System.Single") + DOUBLE = getTypeSafe("System.Double") + BOOLEAN = getTypeSafe("System.Boolean") + VOID = getTypeSafe("System.Void") + ENUM = getTypeSafe("System.Enum") + DELEGATE = getTypeSafe("System.MulticastDelegate") + + OBJECT = getTypeSafe("System.Object") + STRING = getTypeSafe("System.String") + STRING_ARRAY = getTypeSafe("System.String[]") + VALUE_TYPE = getTypeSafe("System.ValueType") + + SCALA_SYMTAB_ATTR = getTypeSafe("scala.runtime.SymtabAttribute") + val bytearray: Array[Type] = Array(Type.GetType("System.Byte[]")) + SYMTAB_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(bytearray) + SYMTAB_DEFAULT_CONSTR = SCALA_SYMTAB_ATTR.GetConstructor(Type.EmptyTypes) + + val delegate: Type = getTypeSafe("System.Delegate") + val dargs: Array[Type] = Array(delegate, delegate) + DELEGATE_COMBINE = delegate.GetMethod("Combine", dargs) + DELEGATE_REMOVE = delegate.GetMethod("Remove", dargs) + } + catch { + case e: RuntimeException => + Console.println(e.getMessage) + throw e + } + + //########################################################################## + // type mapping and lookup + + def getType(name: String): Type = Type.GetType(name) + + def getTypeSafe(name: String): Type = { + val t = Type.GetType(name) + assert(t != null, name) + t + } + + def mkArrayType(elemType: Type): Type = getType(elemType.FullName + "[]") + + def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE } +} // CLRTypes +*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index 82d1dd6bc3..d16c9980d5 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -1,851 +1,852 @@ -// /* NSC -- new scala compiler -// * Copyright 2004-2011 LAMP/EPFL -// */ -// -// package scala.tools.nsc -// package symtab -// package clr -// +/* NSC -- new scala compiler + * Copyright 2004-2011 LAMP/EPFL + */ + +package scala.tools.nsc +package symtab +package clr + // import java.io.IOException // import io.MsilFile // import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _} // import scala.collection.{ mutable, immutable } // import scala.reflect.internal.pickling.UnPickler // import ch.epfl.lamp.compiler.msil.Type.TMVarUsage -// -// /** -// * @author Nikolay Mihaylov -// */ -// abstract class TypeParser { -// -// val global: Global -// -// import global._ -// import loaders.clrTypes -// -// //########################################################################## -// -// private var clazz: Symbol = _ -// private var instanceDefs: Scope = _ // was members -// private var staticModule: Symbol = _ // was staticsClass -// private var staticDefs: Scope = _ // was statics -// -// protected def statics: Symbol = staticModule.moduleClass -// -// protected var busy: Boolean = false // lock to detect recursive reads -// -// private implicit def stringToTermName(s: String): TermName = newTermName(s) -// -// private object unpickler extends UnPickler { -// val global: TypeParser.this.global.type = TypeParser.this.global -// } -// -// def parse(typ: MSILType, root: Symbol) { -// -// def handleError(e: Throwable) = { -// if (settings.debug.value) e.printStackTrace() //debug -// throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")") -// } -// assert(!busy) -// busy = true -// -// if (root.isModule) { -// this.clazz = root.companionClass -// this.staticModule = root -// } else { -// this.clazz = root -// this.staticModule = root.companionModule -// } -// try { -// parseClass(typ) -// } catch { -// case e: FatalError => handleError(e) -// case e: RuntimeException => handleError(e) -// } -// busy = false -// } -// -// class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { -// override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } -// } -// -// /* the names `classTParams` and `newTParams` stem from the forJVM version (ClassfileParser.sigToType()) -// * but there are differences that should be kept in mind. -// * forMSIL, a nested class knows nothing about any type-params in the nesting class, -// * therefore newTParams is redundant (other than for recording lexical order), -// * it always contains the same elements as classTParams.value */ -// val classTParams = scala.collection.mutable.Map[Int,Symbol]() // TODO should this be a stack? (i.e., is it possible for >1 invocation to getCLRType on the same TypeParser instance be active ) -// val newTParams = new scala.collection.mutable.ListBuffer[Symbol]() -// val methodTParams = scala.collection.mutable.Map[Int,Symbol]() -// -// private def sig2typeBounds(tvarCILDef: GenericParamAndConstraints): Type = { -// val ts = new scala.collection.mutable.ListBuffer[Type] -// for (cnstrnt <- tvarCILDef.Constraints) { -// ts += getCLRType(cnstrnt) // TODO we're definitely not at or after erasure, no need to call objToAny, right? -// } -// TypeBounds.upper(intersectionType(ts.toList, clazz)) -// // TODO variance??? -// } -// -// private def createViewFromTo(viewSuffix : String, fromTpe : Type, toTpe : Type, -// addToboxMethodMap : Boolean, isAddressOf : Boolean) : Symbol = { -// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? -// val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(List(fromTpe)), toTpe) -// val vmsym = createMethod(nme.view_ + viewSuffix, flags, viewMethodType, null, true); -// // !!! this used to mutate a mutable map in definitions, but that map became -// // immutable and this kept "working" with a no-op. So now it's commented out -// // since I retired the deprecated code which allowed for that bug. -// // -// // if (addToboxMethodMap) definitions.boxMethod(clazz) = vmsym -// -// if (isAddressOf) clrTypes.addressOfViews += vmsym -// vmsym -// } -// -// private def createDefaultConstructor(typ: MSILType) { -// val attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName // TODO instance -// val declType= typ -// val method = new ConstructorInfo(declType, attrs, Array[MSILType]()) -// val flags = Flags.JAVA -// val owner = clazz -// val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags) -// val rettype = clazz.tpe -// val mtype = methodType(Array[MSILType](), rettype); -// val mInfo = mtype(methodSym) -// methodSym.setInfo(mInfo) -// instanceDefs.enter(methodSym); -// clrTypes.constructors(methodSym) = method -// } -// -// private def parseClass(typ: MSILType) { -// -// { -// val t4c = clrTypes.types.get(clazz) -// assert(t4c == None || t4c == Some(typ)) -// } -// clrTypes.types(clazz) = typ -// -// { -// val c4t = clrTypes.sym2type.get(typ) -// assert(c4t == None || c4t == Some(clazz)) -// } -// clrTypes.sym2type(typ) = clazz -// -// if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) { -// val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false); -// assert (attrs.length == 1, attrs.length); -// val a = attrs(0).asInstanceOf[MSILAttribute]; -// assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR); -// val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]] -// unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName); -// val mClass = clrTypes.getType(typ.FullName + "$"); -// if (mClass != null) { -// clrTypes.types(statics) = mClass; -// val moduleInstance = mClass.GetField("MODULE$"); -// assert (moduleInstance != null, mClass); -// clrTypes.fields(statics) = moduleInstance; -// } -// return -// } -// val flags = translateAttributes(typ) -// -// var clazzBoxed : Symbol = NoSymbol -// var clazzMgdPtr : Symbol = NoSymbol -// -// val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum") -// -// if(canBeTakenAddressOf) { -// clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed")) -// clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr")) -// clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr -// /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed, -// before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */ -// val typMgdPtr = MSILType.mkByRef(typ) -// clrTypes.types(clazzMgdPtr) = typMgdPtr -// clrTypes.sym2type(typMgdPtr) = clazzMgdPtr -// /* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance, -// because there's no metadata-level representation for a "boxed valuetype" */ -// val instanceDefsMgdPtr = newScope -// val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr) -// clazzMgdPtr.setFlag(flags) -// clazzMgdPtr.setInfo(classInfoMgdPtr) -// } -// -// /* START CLR generics (snippet 1) */ -// // first pass -// for (tvarCILDef <- typ.getSortedTVars() ) { -// val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) -// val tpsym = clazz.newTypeParameter(tpname) -// classTParams.put(tvarCILDef.Number, tpsym) -// newTParams += tpsym -// // TODO wouldn't the following also be needed later, i.e. during getCLRType -// tpsym.setInfo(definitions.AnyClass.tpe) -// } -// // second pass -// for (tvarCILDef <- typ.getSortedTVars() ) { -// val tpsym = classTParams(tvarCILDef.Number) -// tpsym.setInfo(sig2typeBounds(tvarCILDef)) // we never skip bounds unlike in forJVM -// } -// /* END CLR generics (snippet 1) */ -// val ownTypeParams = newTParams.toList -// /* START CLR generics (snippet 2) */ -// if (!ownTypeParams.isEmpty) { -// clazz.setInfo(new TypeParamsType(ownTypeParams)) -// if(typ.IsValueType && !typ.IsEnum) { -// clazzBoxed.setInfo(new TypeParamsType(ownTypeParams)) -// } -// } -// /* END CLR generics (snippet 2) */ -// instanceDefs = newScope -// staticDefs = newScope -// -// val classInfoAsInMetadata = { -// val ifaces: Array[MSILType] = typ.getInterfaces() -// val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType()) -// else if (typ.IsInterface()) definitions.ObjectClass.tpe -// else definitions.AnyClass.tpe; // this branch activates for System.Object only. -// // parents (i.e., base type and interfaces) -// val parents = new scala.collection.mutable.ListBuffer[Type]() -// parents += superType -// for (iface <- ifaces) { -// parents += getCLRType(iface) // here the variance doesn't matter -// } -// // methods, properties, events, fields are entered in a moment -// if (canBeTakenAddressOf) { -// val instanceDefsBoxed = newScope -// ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed) -// } else -// ClassInfoType(parents.toList, instanceDefs, clazz) -// } -// -// val staticInfo = ClassInfoType(List(), staticDefs, statics) -// -// clazz.setFlag(flags) -// -// if (canBeTakenAddressOf) { -// clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata -// else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) -// clazzBoxed.setFlag(flags) -// val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) -// clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType -// else GenPolyType(ownTypeParams, rawValueInfoType) ) -// } else { -// clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata -// else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) -// } -// -// // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params -// statics.setFlag(Flags.JAVA) -// statics.setInfo(staticInfo) -// staticModule.setFlag(Flags.JAVA) -// staticModule.setInfo(statics.tpe) -// -// -// if (canBeTakenAddressOf) { -// // implicit conversions are owned by staticModule.moduleClass -// createViewFromTo("2Boxed", clazz.tpe, clazzBoxed.tpe, addToboxMethodMap = true, isAddressOf = false) -// // createViewFromTo("2Object", clazz.tpe, definitions.ObjectClass.tpe, addToboxMethodMap = true, isAddressOf = false) -// createViewFromTo("2MgdPtr", clazz.tpe, clazzMgdPtr.tpe, addToboxMethodMap = false, isAddressOf = true) -// // a return can't have type managed-pointer, thus a dereference-conversion is not needed -// // similarly, a method can't declare as return type "boxed valuetype" -// if (!typ.IsEnum) { -// // a synthetic default constructor for raw-type allows `new X' syntax -// createDefaultConstructor(typ) -// } -// } -// -// // import nested types -// for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem) -// || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) -// { -// val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) -// val nclazz = statics.newClass(ntype.Name.toTypeName) -// val nmodule = statics.newModule(ntype.Name) -// nclazz.setInfo(loader) -// nmodule.setInfo(loader) -// staticDefs.enter(nclazz) -// staticDefs.enter(nmodule) -// -// assert(nclazz.companionModule == nmodule, nmodule) -// assert(nmodule.companionClass == nclazz, nclazz) -// } -// -// val fields = typ.getFields() -// for (field <- fields -// if !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly) -// if (getCLRType(field.FieldType) != null) -// ) { -// assert (!field.FieldType.IsPointer && !field.FieldType.IsByRef, "CLR requirement") -// val flags = translateAttributes(field); -// val name = newTermName(field.Name); -// val fieldType = -// if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType))) -// ConstantType(getConstant(getCLRType(field.FieldType), field.getValue)) -// else -// getCLRType(field.FieldType) -// val owner = if (field.IsStatic()) statics else clazz; -// val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType); -// // TODO: set private within!!! -> look at typechecker/Namers.scala -// (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym); -// clrTypes.fields(sym) = field; -// } -// -// for (constr <- typ.getConstructors() if !constr.IsStatic() && !constr.IsPrivate() && -// !constr.IsAssembly() && !constr.IsFamilyAndAssembly() && !constr.HasPtrParamOrRetType()) -// createMethod(constr); -// -// // initially also contains getters and setters of properties. -// val methodsSet = new mutable.HashSet[MethodInfo](); -// methodsSet ++= typ.getMethods(); -// -// for (prop <- typ.getProperties) { -// val propType: Type = getCLSType(prop.PropertyType); -// if (propType != null) { -// val getter: MethodInfo = prop.GetGetMethod(true); -// val setter: MethodInfo = prop.GetSetMethod(true); -// var gparamsLength: Int = -1; -// if (!(getter == null || getter.IsPrivate || getter.IsAssembly -// || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType)) -// { -// assert(prop.PropertyType == getter.ReturnType); -// val gparams: Array[ParameterInfo] = getter.GetParameters(); -// gparamsLength = gparams.length; -// val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; -// val flags = translateAttributes(getter); -// val owner: Symbol = if (getter.IsStatic) statics else clazz; -// val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) -// val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic -// else methodType(getter, getter.ReturnType)(methodSym) -// methodSym.setInfo(mtype); -// methodSym.setFlag(Flags.ACCESSOR); -// (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) -// clrTypes.methods(methodSym) = getter; -// methodsSet -= getter; -// } -// if (!(setter == null || setter.IsPrivate || setter.IsAssembly -// || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType)) -// { -// val sparams: Array[ParameterInfo] = setter.GetParameters() -// if(getter != null) -// assert(getter.IsStatic == setter.IsStatic); -// assert(setter.ReturnType == clrTypes.VOID); -// if(getter != null) -// assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter); -// -// val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) -// else nme.update; -// val flags = translateAttributes(setter); -// val mtype = methodType(setter, definitions.UnitClass.tpe); -// val owner: Symbol = if (setter.IsStatic) statics else clazz; -// val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) -// methodSym.setInfo(mtype(methodSym)) -// methodSym.setFlag(Flags.ACCESSOR); -// (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); -// clrTypes.methods(methodSym) = setter; -// methodsSet -= setter; -// } -// } -// } -// -// /* for (event <- typ.GetEvents) { -// // adding += and -= methods to add delegates to an event. -// // raising the event ist not possible from outside the class (this is so -// // generally in .net world) -// val adder: MethodInfo = event.GetAddMethod(); -// val remover: MethodInfo = event.GetRemoveMethod(); -// if (!(adder == null || adder.IsPrivate || adder.IsAssembly -// || adder.IsFamilyAndAssembly)) -// { -// assert(adder.ReturnType == clrTypes.VOID); -// assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); -// val name = encode("+="); -// val flags = translateAttributes(adder); -// val mtype: Type = methodType(adder, adder.ReturnType); -// createMethod(name, flags, mtype, adder, adder.IsStatic) -// methodsSet -= adder; -// } -// if (!(remover == null || remover.IsPrivate || remover.IsAssembly -// || remover.IsFamilyAndAssembly)) -// { -// assert(remover.ReturnType == clrTypes.VOID); -// assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); -// val name = encode("-="); -// val flags = translateAttributes(remover); -// val mtype: Type = methodType(remover, remover.ReturnType); -// createMethod(name, flags, mtype, remover, remover.IsStatic) -// methodsSet -= remover; -// } -// } */ -// -// /* Adds view amounting to syntax sugar for a CLR implicit overload. -// The long-form syntax can also be supported if "methodsSet -= method" (last statement) is removed. -// -// /* remember, there's typ.getMethods and type.GetMethods */ -// for (method <- typ.getMethods) -// if(!method.HasPtrParamOrRetType && -// method.IsPublic && method.IsStatic && method.IsSpecialName && -// method.Name == "op_Implicit") { -// // create a view: typ => method's return type -// val viewRetType: Type = getCLRType(method.ReturnType) -// val viewParamTypes: List[Type] = method.GetParameters().map(_.ParameterType).map(getCLSType).toList; -// /* The spec says "The operator method shall be defined as a static method on either the operand or return type." -// * We don't consider the declaring type for the purposes of definitions.functionType, -// * instead we regard op_Implicit's argument type and return type as defining the view's signature. -// */ -// if (viewRetType != null && !viewParamTypes.contains(null)) { -// /* The check above applies e.g. to System.Decimal that has a conversion from UInt16, a non-CLS type, whose CLS-mapping returns null */ -// val funType: Type = definitions.functionType(viewParamTypes, viewRetType); -// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? -// val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(viewParamTypes), funType) -// val vmsym = createMethod(nme.view_, flags, viewMethodType, method, true); -// methodsSet -= method; -// } -// } -// */ -// -// for (method <- methodsSet.iterator) -// if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly() -// && !method.HasPtrParamOrRetType) -// createMethod(method); -// -// // Create methods and views for delegate support -// if (clrTypes.isDelegateType(typ)) { -// createDelegateView(typ) -// createDelegateChainers(typ) -// } -// -// // for enumerations introduce comparison and bitwise logical operations; -// // the backend will recognize them and replace them with comparison or -// // bitwise logical operations on the primitive underlying type -// -// if (typ.IsEnum) { -// val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE); -// val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR); -// -// val flags = Flags.JAVA | Flags.FINAL -// for (cmpName <- ENUM_CMP_NAMES) { -// val enumCmp = clazz.newMethod(NoPosition, cmpName) -// val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe) -// enumCmp.setFlag(flags).setInfo(enumCmpType) -// instanceDefs.enter(enumCmp) -// } -// -// for (bitLogName <- ENUM_BIT_LOG_NAMES) { -// val enumBitLog = clazz.newMethod(NoPosition, bitLogName) -// val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */) -// enumBitLog.setFlag(flags).setInfo(enumBitLogType) -// instanceDefs.enter(enumBitLog) -// } -// } -// -// } // parseClass -// -// private def populateMethodTParams(method: MethodBase, methodSym: MethodSymbol) : List[Symbol] = { -// if(!method.IsGeneric) Nil -// else { -// methodTParams.clear -// val newMethodTParams = new scala.collection.mutable.ListBuffer[Symbol]() -// -// // first pass -// for (mvarCILDef <- method.getSortedMVars() ) { -// val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO) -// val mtpsym = methodSym.newTypeParameter(mtpname) -// methodTParams.put(mvarCILDef.Number, mtpsym) -// newMethodTParams += mtpsym -// // TODO wouldn't the following also be needed later, i.e. during getCLRType -// mtpsym.setInfo(definitions.AnyClass.tpe) -// } -// // second pass -// for (mvarCILDef <- method.getSortedMVars() ) { -// val mtpsym = methodTParams(mvarCILDef.Number) -// mtpsym.setInfo(sig2typeBounds(mvarCILDef)) // we never skip bounds unlike in forJVM -// } -// -// newMethodTParams.toList -// } -// } -// -// private def createMethod(method: MethodBase) { -// -// val flags = translateAttributes(method); -// val owner = if (method.IsStatic()) statics else clazz; -// val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags) -// /* START CLR generics (snippet 3) */ -// val newMethodTParams = populateMethodTParams(method, methodSym) -// /* END CLR generics (snippet 3) */ -// -// val rettype = if (method.IsConstructor()) clazz.tpe -// else getCLSType(method.asInstanceOf[MethodInfo].ReturnType); -// if (rettype == null) return; -// val mtype = methodType(method, rettype); -// if (mtype == null) return; -// /* START CLR generics (snippet 4) */ -// val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) -// else mtype(methodSym) -// /* END CLR generics (snippet 4) */ -// /* START CLR non-generics (snippet 4) -// val mInfo = mtype(methodSym) -// END CLR non-generics (snippet 4) */ -// methodSym.setInfo(mInfo) -// (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym); -// if (method.IsConstructor()) -// clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo] -// else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo]; -// } -// -// private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = { -// val mtype = methodType(args, getCLSType(retType)) -// assert(mtype != null) -// createMethod(name, flags, mtype, method, statik) -// } -// -// private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = { -// val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name) -// methodSym.setFlag(flags).setInfo(mtype(methodSym)) -// (if (statik) staticDefs else instanceDefs).enter(methodSym) -// if (method != null) -// clrTypes.methods(methodSym) = method -// methodSym -// } -// -// private def createDelegateView(typ: MSILType) = { -// val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo]; -// val invokeRetType: Type = getCLRType(invoke.ReturnType); -// val invokeParamTypes: List[Type] =invoke.GetParameters().map(_.ParameterType).map(getCLSType).toList; -// val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType); -// -// val typClrType: Type = getCLRType(typ); -// val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed -// -// // create the forward view: delegate => function -// val delegateParamTypes: List[Type] = List(typClrType); -// // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods) -// val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType) -// val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true); -// -// // create the backward view: function => delegate -// val functionParamTypes: List[Type] = List(funType); -// val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType) -// val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true); -// } -// -// private def createDelegateChainers(typ: MSILType) = { -// val flags: Long = Flags.JAVA | Flags.FINAL -// val args: Array[MSILType] = Array(typ) -// -// var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false); -// s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false); -// -// s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false); -// s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false); -// } -// -// private def getName(method: MethodBase): Name = { -// -// def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match { -// case 1 => name match { -// // PartitionI.10.3.1 -// case "op_Decrement" => Some(encode("--")) -// case "op_Increment" => Some(encode("++")) -// case "op_UnaryNegation" => Some(nme.UNARY_-) -// case "op_UnaryPlus" => Some(nme.UNARY_+) -// case "op_LogicalNot" => Some(nme.UNARY_!) -// case "op_OnesComplement" => Some(nme.UNARY_~) -// /* op_True and op_False have no operator symbol assigned, -// Other methods that will have to be written in full are: -// op_AddressOf & (unary) -// op_PointerDereference * (unary) */ -// case _ => None -// } -// case 2 => name match { -// // PartitionI.10.3.2 -// case "op_Addition" => Some(nme.ADD) -// case "op_Subtraction" => Some(nme.SUB) -// case "op_Multiply" => Some(nme.MUL) -// case "op_Division" => Some(nme.DIV) -// case "op_Modulus" => Some(nme.MOD) -// case "op_ExclusiveOr" => Some(nme.XOR) -// case "op_BitwiseAnd" => Some(nme.AND) -// case "op_BitwiseOr" => Some(nme.OR) -// case "op_LogicalAnd" => Some(nme.ZAND) -// case "op_LogicalOr" => Some(nme.ZOR) -// case "op_LeftShift" => Some(nme.LSL) -// case "op_RightShift" => Some(nme.ASR) -// case "op_Equality" => Some(nme.EQ) -// case "op_GreaterThan" => Some(nme.GT) -// case "op_LessThan" => Some(nme.LT) -// case "op_Inequality" => Some(nme.NE) -// case "op_GreaterThanOrEqual" => Some(nme.GE) -// case "op_LessThanOrEqual" => Some(nme.LE) -// -// /* op_MemberSelection is reserved in Scala */ -// -// /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift , -// * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */ -// -// /* -// The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full. -// -// op_RightShiftAssignment >>= -// op_MultiplicationAssignment *= -// op_PointerToMemberSelection ->* -// op_SubtractionAssignment -= -// op_ExclusiveOrAssignment ^= -// op_LeftShiftAssignment <<= -// op_ModulusAssignment %= -// op_AdditionAssignment += -// op_BitwiseAndAssignment &= -// op_BitwiseOrAssignment |= -// op_Comma , -// op_DivisionAssignment /= -// */ -// case _ => None -// } -// case _ => None -// } -// -// if (method.IsConstructor()) return nme.CONSTRUCTOR; -// val name = method.Name; -// if (method.IsStatic()) { -// if(method.IsSpecialName) { -// val paramsArity = method.GetParameters().size -// // handle operator overload, otherwise handle as any static method -// val operName = operatorOverload(name, paramsArity) -// if (operName.isDefined) { return operName.get; } -// } -// return newTermName(name); -// } -// val params = method.GetParameters(); -// name match { -// case "GetHashCode" if (params.length == 0) => nme.hashCode_; -// case "ToString" if (params.length == 0) => nme.toString_; -// case "Finalize" if (params.length == 0) => nme.finalize_; -// case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) => -// nme.equals_; -// case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply; -// case _ => newTermName(name); -// } -// } -// -// //########################################################################## -// -// private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = { -// val rtype = getCLSType(rettype); -// if (rtype == null) null else methodType(method, rtype); -// } -// -// /** Return a method type for the given method. */ -// private def methodType(method: MethodBase, rettype: Type): Symbol => Type = -// methodType(method.GetParameters().map(_.ParameterType), rettype); -// -// /** Return a method type for the provided argument types and return type. */ -// private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = { -// def paramType(typ: MSILType): Type = -// if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe // TODO a hack to compile scalalib, should be definitions.AnyRefClass.tpe -// else getCLSType(typ); -// val ptypes = argtypes.map(paramType).toList; -// if (ptypes.contains(null)) null -// else method => JavaMethodType(method.newSyntheticValueParams(ptypes), rettype); -// } -// -// //########################################################################## -// -// private def getClassType(typ: MSILType): Type = { -// assert(typ != null); -// val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe; -// //if (res.isError()) -// // global.reporter.error("unknown class reference " + type.FullName); -// res -// } -// -// private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not -// if (typ.IsTMVarUsage()) -// /* START CLR generics (snippet 5) */ -// getCLRType(typ) -// /* END CLR generics (snippet 5) */ -// /* START CLR non-generics (snippet 5) -// null -// END CLR non-generics (snippet 5) */ -// else if ( /* TODO hack if UBYE, uncommented, "ambiguous reference to overloaded definition" ensues, for example for System.Math.Max(x, y) */ -// typ == clrTypes.USHORT || typ == clrTypes.UINT || typ == clrTypes.ULONG -// /* || typ == clrTypes.UBYTE */ -// || typ.IsNotPublic() || typ.IsNestedPrivate() -// || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem() -// || typ.IsPointer() -// || (typ.IsArray() && getCLRType(typ.GetElementType()) == null) /* TODO hack: getCLR instead of getCLS */ -// || (typ.IsByRef() && !typ.GetElementType().CanBeTakenAddressOf())) -// null -// else -// getCLRType(typ) -// } -// -// private def getCLRTypeIfPrimitiveNullOtherwise(typ: MSILType): Type = -// if (typ == clrTypes.OBJECT) -// definitions.ObjectClass.tpe; -// else if (typ == clrTypes.VALUE_TYPE) -// definitions.AnyValClass.tpe -// else if (typ == clrTypes.STRING) -// definitions.StringClass.tpe; -// else if (typ == clrTypes.VOID) -// definitions.UnitClass.tpe -// else if (typ == clrTypes.BOOLEAN) -// definitions.BooleanClass.tpe -// else if (typ == clrTypes.CHAR) -// definitions.CharClass.tpe -// else if ((typ == clrTypes.BYTE) || (typ == clrTypes.UBYTE)) // TODO U... is a hack to compile scalalib -// definitions.ByteClass.tpe -// else if ((typ == clrTypes.SHORT) || (typ == clrTypes.SHORT)) // TODO U... is a hack to compile scalalib -// definitions.ShortClass.tpe -// else if ((typ == clrTypes.INT) || (typ == clrTypes.UINT)) // TODO U... is a hack to compile scalalib -// definitions.IntClass.tpe -// else if ((typ == clrTypes.LONG) || (typ == clrTypes.LONG)) // TODO U... is a hack to compile scalalib -// definitions.LongClass.tpe -// else if (typ == clrTypes.FLOAT) -// definitions.FloatClass.tpe -// else if (typ == clrTypes.DOUBLE) -// definitions.DoubleClass.tpe -// else null -// -// -// private def getCLRType(tMSIL: MSILType): Type = { -// var res = getCLRTypeIfPrimitiveNullOtherwise(tMSIL) -// if (res != null) res -// else if (tMSIL.isInstanceOf[ConstructedType]) { -// val ct = tMSIL.asInstanceOf[ConstructedType] -// /* START CLR generics (snippet 6) */ -// val cttpArgs = ct.typeArgs.map(tmsil => getCLRType(tmsil)).toList -// appliedType(getCLRType(ct.instantiatedType), cttpArgs) -// /* END CLR generics (snippet 6) */ -// /* START CLR non-generics (snippet 6) -// getCLRType(ct.instantiatedType) -// END CLR non-generics (snippet 6) */ -// } else if (tMSIL.isInstanceOf[TMVarUsage]) { -// /* START CLR generics (snippet 7) */ -// val tVarUsage = tMSIL.asInstanceOf[TMVarUsage] -// val tVarNumber = tVarUsage.Number -// if (tVarUsage.isTVar) classTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst -// else methodTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst -// /* END CLR generics (snippet 7) */ -// /* START CLR non-generics (snippet 7) -// null // definitions.ObjectClass.tpe -// END CLR non-generics (snippet 7) */ -// } else if (tMSIL.IsArray()) { -// var elemtp = getCLRType(tMSIL.GetElementType()) -// // cut&pasted from ClassfileParser -// // make unbounded Array[T] where T is a type variable into Array[T with Object] -// // (this is necessary because such arrays have a representation which is incompatible -// // with arrays of primitive types). -// // TODO does that incompatibility also apply to .NET? -// if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) -// elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe)) -// appliedType(definitions.ArrayClass.tpe, List(elemtp)) -// } else { -// res = clrTypes.sym2type.get(tMSIL) match { -// case Some(sym) => sym.tpe -// case None => if (tMSIL.IsByRef && tMSIL.GetElementType.IsValueType) { -// val addressed = getCLRType(tMSIL.GetElementType) -// val clasym = addressed.typeSymbolDirect // TODO should be .typeSymbol? -// clasym.info.load(clasym) -// val secondAttempt = clrTypes.sym2type.get(tMSIL) -// secondAttempt match { case Some(sym) => sym.tpe -// case None => null -// } -// } else getClassType(tMSIL) -// } -// if (res == null) -// null // TODO new RuntimeException() -// else res -// } -// } -// -// // the values are Java-Box-Classes (e.g. Integer, Boolean, Character) -// // java.lang.Number to get the value (if a number, not for boolean, character) -// // see ch.epfl.lamp.compiler.msil.util.PEStream.java -// def getConstant(constType: Type, value: Object): Constant = { -// val typeClass = constType.typeSymbol -// if (typeClass == definitions.BooleanClass) -// Constant(value.asInstanceOf[java.lang.Boolean].booleanValue) -// else if (typeClass == definitions.ByteClass) -// Constant(value.asInstanceOf[java.lang.Number].byteValue) -// else if (typeClass == definitions.ShortClass) -// Constant(value.asInstanceOf[java.lang.Number].shortValue) -// else if (typeClass == definitions.CharClass) -// Constant(value.asInstanceOf[java.lang.Character].charValue) -// else if (typeClass == definitions.IntClass) -// Constant(value.asInstanceOf[java.lang.Number].intValue) -// else if (typeClass == definitions.LongClass) -// Constant(value.asInstanceOf[java.lang.Number].longValue) -// else if (typeClass == definitions.FloatClass) -// Constant(value.asInstanceOf[java.lang.Number].floatValue) -// else if (typeClass == definitions.DoubleClass) -// Constant(value.asInstanceOf[java.lang.Number].doubleValue) -// else if (typeClass == definitions.StringClass) -// Constant(value.asInstanceOf[java.lang.String]) -// else -// abort("illegal value: " + value + ", class-symbol: " + typeClass) -// } -// -// def isDefinedAtgetConstant(constType: Type): Boolean = { -// val typeClass = constType.typeSymbol -// if ( (typeClass == definitions.BooleanClass) -// || (typeClass == definitions.ByteClass) -// || (typeClass == definitions.ShortClass) -// || (typeClass == definitions.CharClass) -// || (typeClass == definitions.IntClass) -// || (typeClass == definitions.LongClass) -// || (typeClass == definitions.FloatClass) -// || (typeClass == definitions.DoubleClass) -// || (typeClass == definitions.StringClass) -// ) -// true -// else -// false -// } -// -// private def translateAttributes(typ: MSILType): Long = { -// var flags: Long = Flags.JAVA; -// if (typ.IsNotPublic() || typ.IsNestedPrivate() -// || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()) -// flags = flags | Flags.PRIVATE; -// else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem()) -// flags = flags | Flags.PROTECTED; -// if (typ.IsAbstract()) -// flags = flags | Flags.ABSTRACT; -// if (typ.IsSealed()) -// flags = flags | Flags.FINAL; -// if (typ.IsInterface()) -// flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT; -// -// flags -// } -// -// private def translateAttributes(field: FieldInfo): Long = { -// var flags: Long = Flags.JAVA; -// if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly()) -// flags = flags | Flags.PRIVATE; -// else if (field.IsFamily() || field.IsFamilyOrAssembly()) -// flags = flags | Flags.PROTECTED; -// if (field.IsInitOnly() || field.IsLiteral()) -// flags = flags | Flags.FINAL; -// else -// flags = flags | Flags.MUTABLE; -// if (field.IsStatic) -// flags = flags | Flags.STATIC -// -// flags -// } -// -// private def translateAttributes(method: MethodBase): Long = { -// var flags: Long = Flags.JAVA; -// if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly()) -// flags = flags | Flags.PRIVATE; -// else if (method.IsFamily() || method.IsFamilyOrAssembly()) -// flags = flags | Flags.PROTECTED; -// if (method.IsAbstract()) -// flags = flags | Flags.DEFERRED; -// if (method.IsStatic) -// flags = flags | Flags.STATIC -// -// flags -// } -// } + +/** + * @author Nikolay Mihaylov + */ +abstract class TypeParser /*{ + + val global: Global + + import global._ + import loaders.clrTypes + + //########################################################################## + + private var clazz: Symbol = _ + private var instanceDefs: Scope = _ // was members + private var staticModule: Symbol = _ // was staticsClass + private var staticDefs: Scope = _ // was statics + + protected def statics: Symbol = staticModule.moduleClass + + protected var busy: Boolean = false // lock to detect recursive reads + + private implicit def stringToTermName(s: String): TermName = newTermName(s) + + private object unpickler extends UnPickler { + val global: TypeParser.this.global.type = TypeParser.this.global + } + + def parse(typ: MSILType, root: Symbol) { + + def handleError(e: Throwable) = { + if (settings.debug.value) e.printStackTrace() //debug + throw new IOException("type '" + typ.FullName + "' is broken\n(" + e.getMessage() + ")") + } + assert(!busy) + busy = true + + if (root.isModule) { + this.clazz = root.companionClass + this.staticModule = root + } else { + this.clazz = root + this.staticModule = root.companionModule + } + try { + parseClass(typ) + } catch { + case e: FatalError => handleError(e) + case e: RuntimeException => handleError(e) + } + busy = false + } + + class TypeParamsType(override val typeParams: List[Symbol]) extends LazyType { + override def complete(sym: Symbol) { throw new AssertionError("cyclic type dereferencing") } + } + + /* the names `classTParams` and `newTParams` stem from the forJVM version (ClassfileParser.sigToType()) + * but there are differences that should be kept in mind. + * forMSIL, a nested class knows nothing about any type-params in the nesting class, + * therefore newTParams is redundant (other than for recording lexical order), + * it always contains the same elements as classTParams.value */ + val classTParams = scala.collection.mutable.Map[Int,Symbol]() // TODO should this be a stack? (i.e., is it possible for >1 invocation to getCLRType on the same TypeParser instance be active ) + val newTParams = new scala.collection.mutable.ListBuffer[Symbol]() + val methodTParams = scala.collection.mutable.Map[Int,Symbol]() + + private def sig2typeBounds(tvarCILDef: GenericParamAndConstraints): Type = { + val ts = new scala.collection.mutable.ListBuffer[Type] + for (cnstrnt <- tvarCILDef.Constraints) { + ts += getCLRType(cnstrnt) // TODO we're definitely not at or after erasure, no need to call objToAny, right? + } + TypeBounds.upper(intersectionType(ts.toList, clazz)) + // TODO variance??? + } + + private def createViewFromTo(viewSuffix : String, fromTpe : Type, toTpe : Type, + addToboxMethodMap : Boolean, isAddressOf : Boolean) : Symbol = { + val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? + val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(List(fromTpe)), toTpe) + val vmsym = createMethod(nme.view_ + viewSuffix, flags, viewMethodType, null, true); + // !!! this used to mutate a mutable map in definitions, but that map became + // immutable and this kept "working" with a no-op. So now it's commented out + // since I retired the deprecated code which allowed for that bug. + // + // if (addToboxMethodMap) definitions.boxMethod(clazz) = vmsym + + if (isAddressOf) clrTypes.addressOfViews += vmsym + vmsym + } + + private def createDefaultConstructor(typ: MSILType) { + val attrs = MethodAttributes.Public | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName // TODO instance + val declType= typ + val method = new ConstructorInfo(declType, attrs, Array[MSILType]()) + val flags = Flags.JAVA + val owner = clazz + val methodSym = owner.newMethod(NoPosition, nme.CONSTRUCTOR).setFlag(flags) + val rettype = clazz.tpe + val mtype = methodType(Array[MSILType](), rettype); + val mInfo = mtype(methodSym) + methodSym.setInfo(mInfo) + instanceDefs.enter(methodSym); + clrTypes.constructors(methodSym) = method + } + + private def parseClass(typ: MSILType) { + + { + val t4c = clrTypes.types.get(clazz) + assert(t4c == None || t4c == Some(typ)) + } + clrTypes.types(clazz) = typ + + { + val c4t = clrTypes.sym2type.get(typ) + assert(c4t == None || c4t == Some(clazz)) + } + clrTypes.sym2type(typ) = clazz + + if (typ.IsDefined(clrTypes.SCALA_SYMTAB_ATTR, false)) { + val attrs = typ.GetCustomAttributes(clrTypes.SCALA_SYMTAB_ATTR, false); + assert (attrs.length == 1, attrs.length); + val a = attrs(0).asInstanceOf[MSILAttribute]; + assert (a.getConstructor() == clrTypes.SYMTAB_CONSTR); + val symtab = a.getConstructorArguments()(0).asInstanceOf[Array[Byte]] + unpickler.unpickle(symtab, 0, clazz, staticModule, typ.FullName); + val mClass = clrTypes.getType(typ.FullName + "$"); + if (mClass != null) { + clrTypes.types(statics) = mClass; + val moduleInstance = mClass.GetField("MODULE$"); + assert (moduleInstance != null, mClass); + clrTypes.fields(statics) = moduleInstance; + } + return + } + val flags = translateAttributes(typ) + + var clazzBoxed : Symbol = NoSymbol + var clazzMgdPtr : Symbol = NoSymbol + + val canBeTakenAddressOf = (typ.IsValueType || typ.IsEnum) && (typ.FullName != "System.Enum") + + if(canBeTakenAddressOf) { + clazzBoxed = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("Boxed")) + clazzMgdPtr = clazz.owner.newClass(clazz.name.toTypeName append newTypeName("MgdPtr")) + clrTypes.mdgptrcls4clssym(clazz) = clazzMgdPtr + /* adding typMgdPtr to clrTypes.sym2type should happen early (before metadata for supertypes is parsed, + before metadata for members are parsed) so that clazzMgdPtr can be found by getClRType. */ + val typMgdPtr = MSILType.mkByRef(typ) + clrTypes.types(clazzMgdPtr) = typMgdPtr + clrTypes.sym2type(typMgdPtr) = clazzMgdPtr + /* clazzMgdPtr but not clazzBoxed is mapped by clrTypes.types into an msil.Type instance, + because there's no metadata-level representation for a "boxed valuetype" */ + val instanceDefsMgdPtr = newScope + val classInfoMgdPtr = ClassInfoType(definitions.anyvalparam, instanceDefsMgdPtr, clazzMgdPtr) + clazzMgdPtr.setFlag(flags) + clazzMgdPtr.setInfo(classInfoMgdPtr) + } + +/* START CLR generics (snippet 1) */ + // first pass + for (tvarCILDef <- typ.getSortedTVars() ) { + val tpname = newTypeName(tvarCILDef.Name.replaceAll("!", "")) // TODO are really all type-params named in all assemblies out there? (NO) + val tpsym = clazz.newTypeParameter(tpname) + classTParams.put(tvarCILDef.Number, tpsym) + newTParams += tpsym + // TODO wouldn't the following also be needed later, i.e. during getCLRType + tpsym.setInfo(definitions.AnyClass.tpe) + } + // second pass + for (tvarCILDef <- typ.getSortedTVars() ) { + val tpsym = classTParams(tvarCILDef.Number) + tpsym.setInfo(sig2typeBounds(tvarCILDef)) // we never skip bounds unlike in forJVM + } +/* END CLR generics (snippet 1) */ + val ownTypeParams = newTParams.toList +/* START CLR generics (snippet 2) */ + if (!ownTypeParams.isEmpty) { + clazz.setInfo(new TypeParamsType(ownTypeParams)) + if(typ.IsValueType && !typ.IsEnum) { + clazzBoxed.setInfo(new TypeParamsType(ownTypeParams)) + } + } +/* END CLR generics (snippet 2) */ + instanceDefs = newScope + staticDefs = newScope + + val classInfoAsInMetadata = { + val ifaces: Array[MSILType] = typ.getInterfaces() + val superType = if (typ.BaseType() != null) getCLRType(typ.BaseType()) + else if (typ.IsInterface()) definitions.ObjectClass.tpe + else definitions.AnyClass.tpe; // this branch activates for System.Object only. + // parents (i.e., base type and interfaces) + val parents = new scala.collection.mutable.ListBuffer[Type]() + parents += superType + for (iface <- ifaces) { + parents += getCLRType(iface) // here the variance doesn't matter + } + // methods, properties, events, fields are entered in a moment + if (canBeTakenAddressOf) { + val instanceDefsBoxed = newScope + ClassInfoType(parents.toList, instanceDefsBoxed, clazzBoxed) + } else + ClassInfoType(parents.toList, instanceDefs, clazz) + } + + val staticInfo = ClassInfoType(List(), staticDefs, statics) + + clazz.setFlag(flags) + + if (canBeTakenAddressOf) { + clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata + else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) + clazzBoxed.setFlag(flags) + val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) + clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType + else GenPolyType(ownTypeParams, rawValueInfoType) ) + } else { + clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata + else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) + } + + // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params + statics.setFlag(Flags.JAVA) + statics.setInfo(staticInfo) + staticModule.setFlag(Flags.JAVA) + staticModule.setInfo(statics.tpe) + + + if (canBeTakenAddressOf) { + // implicit conversions are owned by staticModule.moduleClass + createViewFromTo("2Boxed", clazz.tpe, clazzBoxed.tpe, addToboxMethodMap = true, isAddressOf = false) + // createViewFromTo("2Object", clazz.tpe, definitions.ObjectClass.tpe, addToboxMethodMap = true, isAddressOf = false) + createViewFromTo("2MgdPtr", clazz.tpe, clazzMgdPtr.tpe, addToboxMethodMap = false, isAddressOf = true) + // a return can't have type managed-pointer, thus a dereference-conversion is not needed + // similarly, a method can't declare as return type "boxed valuetype" + if (!typ.IsEnum) { + // a synthetic default constructor for raw-type allows `new X' syntax + createDefaultConstructor(typ) + } + } + + // import nested types + for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem) + || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) + { + val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) + val nclazz = statics.newClass(ntype.Name.toTypeName) + val nmodule = statics.newModule(ntype.Name) + nclazz.setInfo(loader) + nmodule.setInfo(loader) + staticDefs.enter(nclazz) + staticDefs.enter(nmodule) + + assert(nclazz.companionModule == nmodule, nmodule) + assert(nmodule.companionClass == nclazz, nclazz) + } + + val fields = typ.getFields() + for (field <- fields + if !(field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly) + if (getCLRType(field.FieldType) != null) + ) { + assert (!field.FieldType.IsPointer && !field.FieldType.IsByRef, "CLR requirement") + val flags = translateAttributes(field); + val name = newTermName(field.Name); + val fieldType = + if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType))) + ConstantType(getConstant(getCLRType(field.FieldType), field.getValue)) + else + getCLRType(field.FieldType) + val owner = if (field.IsStatic()) statics else clazz; + val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType); + // TODO: set private within!!! -> look at typechecker/Namers.scala + (if (field.IsStatic()) staticDefs else instanceDefs).enter(sym); + clrTypes.fields(sym) = field; + } + + for (constr <- typ.getConstructors() if !constr.IsStatic() && !constr.IsPrivate() && + !constr.IsAssembly() && !constr.IsFamilyAndAssembly() && !constr.HasPtrParamOrRetType()) + createMethod(constr); + + // initially also contains getters and setters of properties. + val methodsSet = new mutable.HashSet[MethodInfo](); + methodsSet ++= typ.getMethods(); + + for (prop <- typ.getProperties) { + val propType: Type = getCLSType(prop.PropertyType); + if (propType != null) { + val getter: MethodInfo = prop.GetGetMethod(true); + val setter: MethodInfo = prop.GetSetMethod(true); + var gparamsLength: Int = -1; + if (!(getter == null || getter.IsPrivate || getter.IsAssembly + || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType)) + { + assert(prop.PropertyType == getter.ReturnType); + val gparams: Array[ParameterInfo] = getter.GetParameters(); + gparamsLength = gparams.length; + val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; + val flags = translateAttributes(getter); + val owner: Symbol = if (getter.IsStatic) statics else clazz; + val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) + val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic + else methodType(getter, getter.ReturnType)(methodSym) + methodSym.setInfo(mtype); + methodSym.setFlag(Flags.ACCESSOR); + (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) + clrTypes.methods(methodSym) = getter; + methodsSet -= getter; + } + if (!(setter == null || setter.IsPrivate || setter.IsAssembly + || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType)) + { + val sparams: Array[ParameterInfo] = setter.GetParameters() + if(getter != null) + assert(getter.IsStatic == setter.IsStatic); + assert(setter.ReturnType == clrTypes.VOID); + if(getter != null) + assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter); + + val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) + else nme.update; + val flags = translateAttributes(setter); + val mtype = methodType(setter, definitions.UnitClass.tpe); + val owner: Symbol = if (setter.IsStatic) statics else clazz; + val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) + methodSym.setInfo(mtype(methodSym)) + methodSym.setFlag(Flags.ACCESSOR); + (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); + clrTypes.methods(methodSym) = setter; + methodsSet -= setter; + } + } + } + +/* for (event <- typ.GetEvents) { + // adding += and -= methods to add delegates to an event. + // raising the event ist not possible from outside the class (this is so + // generally in .net world) + val adder: MethodInfo = event.GetAddMethod(); + val remover: MethodInfo = event.GetRemoveMethod(); + if (!(adder == null || adder.IsPrivate || adder.IsAssembly + || adder.IsFamilyAndAssembly)) + { + assert(adder.ReturnType == clrTypes.VOID); + assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); + val name = encode("+="); + val flags = translateAttributes(adder); + val mtype: Type = methodType(adder, adder.ReturnType); + createMethod(name, flags, mtype, adder, adder.IsStatic) + methodsSet -= adder; + } + if (!(remover == null || remover.IsPrivate || remover.IsAssembly + || remover.IsFamilyAndAssembly)) + { + assert(remover.ReturnType == clrTypes.VOID); + assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); + val name = encode("-="); + val flags = translateAttributes(remover); + val mtype: Type = methodType(remover, remover.ReturnType); + createMethod(name, flags, mtype, remover, remover.IsStatic) + methodsSet -= remover; + } + } */ + +/* Adds view amounting to syntax sugar for a CLR implicit overload. + The long-form syntax can also be supported if "methodsSet -= method" (last statement) is removed. + + /* remember, there's typ.getMethods and type.GetMethods */ + for (method <- typ.getMethods) + if(!method.HasPtrParamOrRetType && + method.IsPublic && method.IsStatic && method.IsSpecialName && + method.Name == "op_Implicit") { + // create a view: typ => method's return type + val viewRetType: Type = getCLRType(method.ReturnType) + val viewParamTypes: List[Type] = method.GetParameters().map(_.ParameterType).map(getCLSType).toList; + /* The spec says "The operator method shall be defined as a static method on either the operand or return type." + * We don't consider the declaring type for the purposes of definitions.functionType, + * instead we regard op_Implicit's argument type and return type as defining the view's signature. + */ + if (viewRetType != null && !viewParamTypes.contains(null)) { + /* The check above applies e.g. to System.Decimal that has a conversion from UInt16, a non-CLS type, whose CLS-mapping returns null */ + val funType: Type = definitions.functionType(viewParamTypes, viewRetType); + val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? shouldn't be final instead? + val viewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(viewParamTypes), funType) + val vmsym = createMethod(nme.view_, flags, viewMethodType, method, true); + methodsSet -= method; + } + } +*/ + + for (method <- methodsSet.iterator) + if (!method.IsPrivate() && !method.IsAssembly() && !method.IsFamilyAndAssembly() + && !method.HasPtrParamOrRetType) + createMethod(method); + + // Create methods and views for delegate support + if (clrTypes.isDelegateType(typ)) { + createDelegateView(typ) + createDelegateChainers(typ) + } + + // for enumerations introduce comparison and bitwise logical operations; + // the backend will recognize them and replace them with comparison or + // bitwise logical operations on the primitive underlying type + + if (typ.IsEnum) { + val ENUM_CMP_NAMES = List(nme.EQ, nme.NE, nme.LT, nme.LE, nme.GT, nme.GE); + val ENUM_BIT_LOG_NAMES = List(nme.OR, nme.AND, nme.XOR); + + val flags = Flags.JAVA | Flags.FINAL + for (cmpName <- ENUM_CMP_NAMES) { + val enumCmp = clazz.newMethod(NoPosition, cmpName) + val enumCmpType = JavaMethodType(enumCmp.newSyntheticValueParams(List(clazz.tpe)), definitions.BooleanClass.tpe) + enumCmp.setFlag(flags).setInfo(enumCmpType) + instanceDefs.enter(enumCmp) + } + + for (bitLogName <- ENUM_BIT_LOG_NAMES) { + val enumBitLog = clazz.newMethod(NoPosition, bitLogName) + val enumBitLogType = JavaMethodType(enumBitLog.newSyntheticValueParams(List(clazz.tpe)), clazz.tpe /* was classInfo, infinite typer */) + enumBitLog.setFlag(flags).setInfo(enumBitLogType) + instanceDefs.enter(enumBitLog) + } + } + + } // parseClass + + private def populateMethodTParams(method: MethodBase, methodSym: MethodSymbol) : List[Symbol] = { + if(!method.IsGeneric) Nil + else { + methodTParams.clear + val newMethodTParams = new scala.collection.mutable.ListBuffer[Symbol]() + + // first pass + for (mvarCILDef <- method.getSortedMVars() ) { + val mtpname = newTypeName(mvarCILDef.Name.replaceAll("!", "")) // TODO are really all method-level-type-params named in all assemblies out there? (NO) + val mtpsym = methodSym.newTypeParameter(mtpname) + methodTParams.put(mvarCILDef.Number, mtpsym) + newMethodTParams += mtpsym + // TODO wouldn't the following also be needed later, i.e. during getCLRType + mtpsym.setInfo(definitions.AnyClass.tpe) + } + // second pass + for (mvarCILDef <- method.getSortedMVars() ) { + val mtpsym = methodTParams(mvarCILDef.Number) + mtpsym.setInfo(sig2typeBounds(mvarCILDef)) // we never skip bounds unlike in forJVM + } + + newMethodTParams.toList + } + } + + private def createMethod(method: MethodBase) { + + val flags = translateAttributes(method); + val owner = if (method.IsStatic()) statics else clazz; + val methodSym = owner.newMethod(NoPosition, getName(method)).setFlag(flags) + /* START CLR generics (snippet 3) */ + val newMethodTParams = populateMethodTParams(method, methodSym) + /* END CLR generics (snippet 3) */ + + val rettype = if (method.IsConstructor()) clazz.tpe + else getCLSType(method.asInstanceOf[MethodInfo].ReturnType); + if (rettype == null) return; + val mtype = methodType(method, rettype); + if (mtype == null) return; +/* START CLR generics (snippet 4) */ + val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) + else mtype(methodSym) +/* END CLR generics (snippet 4) */ +/* START CLR non-generics (snippet 4) + val mInfo = mtype(methodSym) + END CLR non-generics (snippet 4) */ + methodSym.setInfo(mInfo) + (if (method.IsStatic()) staticDefs else instanceDefs).enter(methodSym); + if (method.IsConstructor()) + clrTypes.constructors(methodSym) = method.asInstanceOf[ConstructorInfo] + else clrTypes.methods(methodSym) = method.asInstanceOf[MethodInfo]; + } + + private def createMethod(name: Name, flags: Long, args: Array[MSILType], retType: MSILType, method: MethodInfo, statik: Boolean): Symbol = { + val mtype = methodType(args, getCLSType(retType)) + assert(mtype != null) + createMethod(name, flags, mtype, method, statik) + } + + private def createMethod(name: Name, flags: Long, mtype: Symbol => Type, method: MethodInfo, statik: Boolean): Symbol = { + val methodSym: Symbol = (if (statik) statics else clazz).newMethod(NoPosition, name) + methodSym.setFlag(flags).setInfo(mtype(methodSym)) + (if (statik) staticDefs else instanceDefs).enter(methodSym) + if (method != null) + clrTypes.methods(methodSym) = method + methodSym + } + + private def createDelegateView(typ: MSILType) = { + val invoke: MethodInfo = typ.GetMember("Invoke")(0).asInstanceOf[MethodInfo]; + val invokeRetType: Type = getCLRType(invoke.ReturnType); + val invokeParamTypes: List[Type] =invoke.GetParameters().map(_.ParameterType).map(getCLSType).toList; + val funType: Type = definitions.functionType(invokeParamTypes, invokeRetType); + + val typClrType: Type = getCLRType(typ); + val flags = Flags.JAVA | Flags.STATIC | Flags.IMPLICIT; // todo: static? think not needed + + // create the forward view: delegate => function + val delegateParamTypes: List[Type] = List(typClrType); + // not ImplicitMethodType, this is for methods with implicit parameters (not implicit methods) + val forwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(delegateParamTypes), funType) + val fmsym = createMethod(nme.view_, flags, forwardViewMethodType, null, true); + + // create the backward view: function => delegate + val functionParamTypes: List[Type] = List(funType); + val backwardViewMethodType = (msym: Symbol) => JavaMethodType(msym.newSyntheticValueParams(functionParamTypes), typClrType) + val bmsym = createMethod(nme.view_, flags, backwardViewMethodType, null, true); + } + + private def createDelegateChainers(typ: MSILType) = { + val flags: Long = Flags.JAVA | Flags.FINAL + val args: Array[MSILType] = Array(typ) + + var s = createMethod(encode("+="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_COMBINE, false); + s = createMethod(encode("-="), flags, args, clrTypes.VOID, clrTypes.DELEGATE_REMOVE, false); + + s = createMethod(nme.PLUS, flags, args, typ, clrTypes.DELEGATE_COMBINE, false); + s = createMethod(nme.MINUS, flags, args, typ, clrTypes.DELEGATE_REMOVE, false); + } + + private def getName(method: MethodBase): Name = { + + def operatorOverload(name : String, paramsArity : Int) : Option[Name] = paramsArity match { + case 1 => name match { + // PartitionI.10.3.1 + case "op_Decrement" => Some(encode("--")) + case "op_Increment" => Some(encode("++")) + case "op_UnaryNegation" => Some(nme.UNARY_-) + case "op_UnaryPlus" => Some(nme.UNARY_+) + case "op_LogicalNot" => Some(nme.UNARY_!) + case "op_OnesComplement" => Some(nme.UNARY_~) + /* op_True and op_False have no operator symbol assigned, + Other methods that will have to be written in full are: + op_AddressOf & (unary) + op_PointerDereference * (unary) */ + case _ => None + } + case 2 => name match { + // PartitionI.10.3.2 + case "op_Addition" => Some(nme.ADD) + case "op_Subtraction" => Some(nme.SUB) + case "op_Multiply" => Some(nme.MUL) + case "op_Division" => Some(nme.DIV) + case "op_Modulus" => Some(nme.MOD) + case "op_ExclusiveOr" => Some(nme.XOR) + case "op_BitwiseAnd" => Some(nme.AND) + case "op_BitwiseOr" => Some(nme.OR) + case "op_LogicalAnd" => Some(nme.ZAND) + case "op_LogicalOr" => Some(nme.ZOR) + case "op_LeftShift" => Some(nme.LSL) + case "op_RightShift" => Some(nme.ASR) + case "op_Equality" => Some(nme.EQ) + case "op_GreaterThan" => Some(nme.GT) + case "op_LessThan" => Some(nme.LT) + case "op_Inequality" => Some(nme.NE) + case "op_GreaterThanOrEqual" => Some(nme.GE) + case "op_LessThanOrEqual" => Some(nme.LE) + + /* op_MemberSelection is reserved in Scala */ + + /* The standard does not assign operator symbols to op_Assign , op_SignedRightShift , op_UnsignedRightShift , + * and op_UnsignedRightShiftAssignment so those names will be used instead to invoke those methods. */ + + /* + The remaining binary operators are not overloaded in C# and are therefore not in widespread use. They have to be written in full. + + op_RightShiftAssignment >>= + op_MultiplicationAssignment *= + op_PointerToMemberSelection ->* + op_SubtractionAssignment -= + op_ExclusiveOrAssignment ^= + op_LeftShiftAssignment <<= + op_ModulusAssignment %= + op_AdditionAssignment += + op_BitwiseAndAssignment &= + op_BitwiseOrAssignment |= + op_Comma , + op_DivisionAssignment /= + */ + case _ => None + } + case _ => None + } + + if (method.IsConstructor()) return nme.CONSTRUCTOR; + val name = method.Name; + if (method.IsStatic()) { + if(method.IsSpecialName) { + val paramsArity = method.GetParameters().size + // handle operator overload, otherwise handle as any static method + val operName = operatorOverload(name, paramsArity) + if (operName.isDefined) { return operName.get; } + } + return newTermName(name); + } + val params = method.GetParameters(); + name match { + case "GetHashCode" if (params.length == 0) => nme.hashCode_; + case "ToString" if (params.length == 0) => nme.toString_; + case "Finalize" if (params.length == 0) => nme.finalize_; + case "Equals" if (params.length == 1 && params(0).ParameterType == clrTypes.OBJECT) => + nme.equals_; + case "Invoke" if (clrTypes.isDelegateType(method.DeclaringType)) => nme.apply; + case _ => newTermName(name); + } + } + + //########################################################################## + + private def methodType(method: MethodBase, rettype: MSILType): Symbol => Type = { + val rtype = getCLSType(rettype); + if (rtype == null) null else methodType(method, rtype); + } + + /** Return a method type for the given method. */ + private def methodType(method: MethodBase, rettype: Type): Symbol => Type = + methodType(method.GetParameters().map(_.ParameterType), rettype); + + /** Return a method type for the provided argument types and return type. */ + private def methodType(argtypes: Array[MSILType], rettype: Type): Symbol => Type = { + def paramType(typ: MSILType): Type = + if (typ eq clrTypes.OBJECT) definitions.AnyClass.tpe // TODO a hack to compile scalalib, should be definitions.AnyRefClass.tpe + else getCLSType(typ); + val ptypes = argtypes.map(paramType).toList; + if (ptypes.contains(null)) null + else method => JavaMethodType(method.newSyntheticValueParams(ptypes), rettype); + } + + //########################################################################## + + private def getClassType(typ: MSILType): Type = { + assert(typ != null); + val res = definitions.getClass(typ.FullName.replace('+', '.')).tpe; + //if (res.isError()) + // global.reporter.error("unknown class reference " + type.FullName); + res + } + + private def getCLSType(typ: MSILType): Type = { // getCLS returns non-null for types GenMSIL can handle, be they CLS-compliant or not + if (typ.IsTMVarUsage()) + /* START CLR generics (snippet 5) */ + getCLRType(typ) + /* END CLR generics (snippet 5) */ + /* START CLR non-generics (snippet 5) + null + END CLR non-generics (snippet 5) */ + else if ( /* TODO hack if UBYE, uncommented, "ambiguous reference to overloaded definition" ensues, for example for System.Math.Max(x, y) */ + typ == clrTypes.USHORT || typ == clrTypes.UINT || typ == clrTypes.ULONG + /* || typ == clrTypes.UBYTE */ + || typ.IsNotPublic() || typ.IsNestedPrivate() + || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem() + || typ.IsPointer() + || (typ.IsArray() && getCLRType(typ.GetElementType()) == null) /* TODO hack: getCLR instead of getCLS */ + || (typ.IsByRef() && !typ.GetElementType().CanBeTakenAddressOf())) + null + else + getCLRType(typ) + } + + private def getCLRTypeIfPrimitiveNullOtherwise(typ: MSILType): Type = + if (typ == clrTypes.OBJECT) + definitions.ObjectClass.tpe; + else if (typ == clrTypes.VALUE_TYPE) + definitions.AnyValClass.tpe + else if (typ == clrTypes.STRING) + definitions.StringClass.tpe; + else if (typ == clrTypes.VOID) + definitions.UnitClass.tpe + else if (typ == clrTypes.BOOLEAN) + definitions.BooleanClass.tpe + else if (typ == clrTypes.CHAR) + definitions.CharClass.tpe + else if ((typ == clrTypes.BYTE) || (typ == clrTypes.UBYTE)) // TODO U... is a hack to compile scalalib + definitions.ByteClass.tpe + else if ((typ == clrTypes.SHORT) || (typ == clrTypes.SHORT)) // TODO U... is a hack to compile scalalib + definitions.ShortClass.tpe + else if ((typ == clrTypes.INT) || (typ == clrTypes.UINT)) // TODO U... is a hack to compile scalalib + definitions.IntClass.tpe + else if ((typ == clrTypes.LONG) || (typ == clrTypes.LONG)) // TODO U... is a hack to compile scalalib + definitions.LongClass.tpe + else if (typ == clrTypes.FLOAT) + definitions.FloatClass.tpe + else if (typ == clrTypes.DOUBLE) + definitions.DoubleClass.tpe + else null + + + private def getCLRType(tMSIL: MSILType): Type = { + var res = getCLRTypeIfPrimitiveNullOtherwise(tMSIL) + if (res != null) res + else if (tMSIL.isInstanceOf[ConstructedType]) { + val ct = tMSIL.asInstanceOf[ConstructedType] + /* START CLR generics (snippet 6) */ + val cttpArgs = ct.typeArgs.map(tmsil => getCLRType(tmsil)).toList + appliedType(getCLRType(ct.instantiatedType), cttpArgs) + /* END CLR generics (snippet 6) */ + /* START CLR non-generics (snippet 6) + getCLRType(ct.instantiatedType) + END CLR non-generics (snippet 6) */ + } else if (tMSIL.isInstanceOf[TMVarUsage]) { + /* START CLR generics (snippet 7) */ + val tVarUsage = tMSIL.asInstanceOf[TMVarUsage] + val tVarNumber = tVarUsage.Number + if (tVarUsage.isTVar) classTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst + else methodTParams(tVarNumber).typeConstructor // shouldn't fail, just return definitions.AnyClass.tpe at worst + /* END CLR generics (snippet 7) */ + /* START CLR non-generics (snippet 7) + null // definitions.ObjectClass.tpe + END CLR non-generics (snippet 7) */ + } else if (tMSIL.IsArray()) { + var elemtp = getCLRType(tMSIL.GetElementType()) + // cut&pasted from ClassfileParser + // make unbounded Array[T] where T is a type variable into Array[T with Object] + // (this is necessary because such arrays have a representation which is incompatible + // with arrays of primitive types). + // TODO does that incompatibility also apply to .NET? + if (elemtp.typeSymbol.isAbstractType && !(elemtp <:< definitions.ObjectClass.tpe)) + elemtp = intersectionType(List(elemtp, definitions.ObjectClass.tpe)) + appliedType(definitions.ArrayClass.tpe, List(elemtp)) + } else { + res = clrTypes.sym2type.get(tMSIL) match { + case Some(sym) => sym.tpe + case None => if (tMSIL.IsByRef && tMSIL.GetElementType.IsValueType) { + val addressed = getCLRType(tMSIL.GetElementType) + val clasym = addressed.typeSymbolDirect // TODO should be .typeSymbol? + clasym.info.load(clasym) + val secondAttempt = clrTypes.sym2type.get(tMSIL) + secondAttempt match { case Some(sym) => sym.tpe + case None => null + } + } else getClassType(tMSIL) + } + if (res == null) + null // TODO new RuntimeException() + else res + } + } + + // the values are Java-Box-Classes (e.g. Integer, Boolean, Character) + // java.lang.Number to get the value (if a number, not for boolean, character) + // see ch.epfl.lamp.compiler.msil.util.PEStream.java + def getConstant(constType: Type, value: Object): Constant = { + val typeClass = constType.typeSymbol + if (typeClass == definitions.BooleanClass) + Constant(value.asInstanceOf[java.lang.Boolean].booleanValue) + else if (typeClass == definitions.ByteClass) + Constant(value.asInstanceOf[java.lang.Number].byteValue) + else if (typeClass == definitions.ShortClass) + Constant(value.asInstanceOf[java.lang.Number].shortValue) + else if (typeClass == definitions.CharClass) + Constant(value.asInstanceOf[java.lang.Character].charValue) + else if (typeClass == definitions.IntClass) + Constant(value.asInstanceOf[java.lang.Number].intValue) + else if (typeClass == definitions.LongClass) + Constant(value.asInstanceOf[java.lang.Number].longValue) + else if (typeClass == definitions.FloatClass) + Constant(value.asInstanceOf[java.lang.Number].floatValue) + else if (typeClass == definitions.DoubleClass) + Constant(value.asInstanceOf[java.lang.Number].doubleValue) + else if (typeClass == definitions.StringClass) + Constant(value.asInstanceOf[java.lang.String]) + else + abort("illegal value: " + value + ", class-symbol: " + typeClass) + } + + def isDefinedAtgetConstant(constType: Type): Boolean = { + val typeClass = constType.typeSymbol + if ( (typeClass == definitions.BooleanClass) + || (typeClass == definitions.ByteClass) + || (typeClass == definitions.ShortClass) + || (typeClass == definitions.CharClass) + || (typeClass == definitions.IntClass) + || (typeClass == definitions.LongClass) + || (typeClass == definitions.FloatClass) + || (typeClass == definitions.DoubleClass) + || (typeClass == definitions.StringClass) + ) + true + else + false + } + + private def translateAttributes(typ: MSILType): Long = { + var flags: Long = Flags.JAVA; + if (typ.IsNotPublic() || typ.IsNestedPrivate() + || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()) + flags = flags | Flags.PRIVATE; + else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem()) + flags = flags | Flags.PROTECTED; + if (typ.IsAbstract()) + flags = flags | Flags.ABSTRACT; + if (typ.IsSealed()) + flags = flags | Flags.FINAL; + if (typ.IsInterface()) + flags = flags | Flags.INTERFACE | Flags.TRAIT | Flags.ABSTRACT; + + flags + } + + private def translateAttributes(field: FieldInfo): Long = { + var flags: Long = Flags.JAVA; + if (field.IsPrivate() || field.IsAssembly() || field.IsFamilyAndAssembly()) + flags = flags | Flags.PRIVATE; + else if (field.IsFamily() || field.IsFamilyOrAssembly()) + flags = flags | Flags.PROTECTED; + if (field.IsInitOnly() || field.IsLiteral()) + flags = flags | Flags.FINAL; + else + flags = flags | Flags.MUTABLE; + if (field.IsStatic) + flags = flags | Flags.STATIC + + flags + } + + private def translateAttributes(method: MethodBase): Long = { + var flags: Long = Flags.JAVA; + if (method.IsPrivate() || method.IsAssembly() || method.IsFamilyAndAssembly()) + flags = flags | Flags.PRIVATE; + else if (method.IsFamily() || method.IsFamilyOrAssembly()) + flags = flags | Flags.PROTECTED; + if (method.IsAbstract()) + flags = flags | Flags.DEFERRED; + if (method.IsStatic) + flags = flags | Flags.STATIC + + flags + } +} +*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala index 260c350ede..e46f3cbc77 100644 --- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -1,13 +1,13 @@ -// /* NSC -- new Scala compiler -// * Copyright 2006-2011 LAMP/EPFL -// * @author Martin Odersky -// */ -// -// // $Id$ -// -// package scala.tools.nsc -// package util -// +/* NSC -- new Scala compiler + * Copyright 2006-2011 LAMP/EPFL + * @author Martin Odersky + */ + +// $Id$ + +package scala.tools.nsc +package util + // import java.io.File // import java.net.URL // import java.util.StringTokenizer @@ -16,154 +16,155 @@ // import scala.tools.nsc.io.{ AbstractFile, MsilFile } // import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly } // import ClassPath.{ ClassPathContext, isTraitImplementation } -// -// /** Keeping the MSIL classpath code in its own file is important to make sure -// * we don't accidentally introduce a dependency on msil.jar in the jvm. -// */ -// -// object MsilClassPath { -// def collectTypes(assemFile: AbstractFile) = { -// var res: Array[MSILType] = MSILType.EmptyTypes -// val assem = Assembly.LoadFrom(assemFile.path) -// if (assem != null) { -// // DeclaringType == null: true for non-inner classes -// res = assem.GetTypes() filter (_.DeclaringType == null) -// Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0) -// } -// res -// } -// -// /** On the java side this logic is in PathResolver, but as I'm not really -// * up to folding MSIL into that, I am encapsulating it here. -// */ -// def fromSettings(settings: Settings): MsilClassPath = { -// val context = -// if (settings.inline.value) new MsilContext -// else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) } -// -// import settings._ -// new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context) -// } -// -// class MsilContext extends ClassPathContext[MsilFile] { -// def toBinaryName(rep: MsilFile) = rep.msilType.Name -// def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this) -// } -// -// private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MsilFile]] = { -// import ClassPath._ -// val etr = new mutable.ListBuffer[ClassPath[MsilFile]] -// val names = new mutable.HashSet[String] -// -// // 1. Assemblies from -Xassem-extdirs -// for (dirName <- expandPath(ext, expandStar = false)) { -// val dir = AbstractFile.getDirectory(dirName) -// if (dir ne null) { -// for (file <- dir) { -// val name = file.name.toLowerCase -// if (name.endsWith(".dll") || name.endsWith(".exe")) { -// names += name -// etr += context.newClassPath(file) -// } -// } -// } -// } -// -// // 2. Assemblies from -Xassem-path -// for (fileName <- expandPath(user, expandStar = false)) { -// val file = AbstractFile.getFile(fileName) -// if (file ne null) { -// val name = file.name.toLowerCase -// if (name.endsWith(".dll") || name.endsWith(".exe")) { -// names += name -// etr += context.newClassPath(file) -// } -// } -// } -// -// def check(n: String) { -// if (!names.contains(n)) -// throw new AssertionError("Cannot find assembly "+ n + -// ". Use -Xassem-extdirs or -Xassem-path to specify its location") -// } -// check("mscorlib.dll") -// check("scalaruntime.dll") -// -// // 3. Source path -// for (dirName <- expandPath(source, expandStar = false)) { -// val file = AbstractFile.getDirectory(dirName) -// if (file ne null) etr += new SourcePath[MsilFile](file, context) -// } -// -// etr.toList -// } -// } -// import MsilClassPath._ -// -// /** -// * A assembly file (dll / exe) containing classes and namespaces -// */ -// class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MsilFile] { -// def name = { -// val i = namespace.lastIndexOf('.') -// if (i < 0) namespace -// else namespace drop (i + 1) -// } -// def asURLs = List(new java.net.URL(name)) -// def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here? -// -// private lazy val first: Int = { -// var m = 0 -// var n = types.length - 1 -// while (m < n) { -// val l = (m + n) / 2 -// val res = types(l).FullName.compareTo(namespace) -// if (res < 0) m = l + 1 -// else n = l -// } -// if (types(m).FullName.startsWith(namespace)) m else types.length -// } -// -// lazy val classes = { -// val cls = new mutable.ListBuffer[ClassRep] -// var i = first -// while (i < types.length && types(i).Namespace.startsWith(namespace)) { -// // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..) -// if (types(i).Namespace == namespace) -// cls += ClassRep(Some(new MsilFile(types(i))), None) -// i += 1 -// } -// cls.toIndexedSeq -// } -// -// lazy val packages = { -// val nsSet = new mutable.HashSet[String] -// var i = first -// while (i < types.length && types(i).Namespace.startsWith(namespace)) { -// val subns = types(i).Namespace -// if (subns.length > namespace.length) { -// // example: namespace = "System", subns = "System.Reflection.Emit" -// // => find second "." and "System.Reflection" to nsSet. -// val end = subns.indexOf('.', namespace.length + 1) -// nsSet += (if (end < 0) subns -// else subns.substring(0, end)) -// } -// i += 1 -// } -// val xs = for (ns <- nsSet.toList) -// yield new AssemblyClassPath(types, ns, context) -// -// xs.toIndexedSeq -// } -// -// val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq() -// -// override def toString() = "assembly classpath "+ namespace -// } -// -// /** -// * The classpath when compiling with target:msil. Binary files are represented as -// * MSILType values. -// */ -// class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) -// extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } \ No newline at end of file + +/** Keeping the MSIL classpath code in its own file is important to make sure + * we don't accidentally introduce a dependency on msil.jar in the jvm. + */ + +object MsilClassPath /*{ + def collectTypes(assemFile: AbstractFile) = { + var res: Array[MSILType] = MSILType.EmptyTypes + val assem = Assembly.LoadFrom(assemFile.path) + if (assem != null) { + // DeclaringType == null: true for non-inner classes + res = assem.GetTypes() filter (_.DeclaringType == null) + Sorting.stableSort(res, (t1: MSILType, t2: MSILType) => (t1.FullName compareTo t2.FullName) < 0) + } + res + } + + /** On the java side this logic is in PathResolver, but as I'm not really + * up to folding MSIL into that, I am encapsulating it here. + */ + def fromSettings(settings: Settings): MsilClassPath = { + val context = + if (settings.inline.value) new MsilContext + else new MsilContext { override def isValidName(name: String) = !isTraitImplementation(name) } + + import settings._ + new MsilClassPath(assemextdirs.value, assemrefs.value, sourcepath.value, context) + } + + class MsilContext extends ClassPathContext[MsilFile] { + def toBinaryName(rep: MsilFile) = rep.msilType.Name + def newClassPath(assemFile: AbstractFile) = new AssemblyClassPath(MsilClassPath collectTypes assemFile, "", this) + } + + private def assembleEntries(ext: String, user: String, source: String, context: MsilContext): List[ClassPath[MsilFile]] = { + import ClassPath._ + val etr = new mutable.ListBuffer[ClassPath[MsilFile]] + val names = new mutable.HashSet[String] + + // 1. Assemblies from -Xassem-extdirs + for (dirName <- expandPath(ext, expandStar = false)) { + val dir = AbstractFile.getDirectory(dirName) + if (dir ne null) { + for (file <- dir) { + val name = file.name.toLowerCase + if (name.endsWith(".dll") || name.endsWith(".exe")) { + names += name + etr += context.newClassPath(file) + } + } + } + } + + // 2. Assemblies from -Xassem-path + for (fileName <- expandPath(user, expandStar = false)) { + val file = AbstractFile.getFile(fileName) + if (file ne null) { + val name = file.name.toLowerCase + if (name.endsWith(".dll") || name.endsWith(".exe")) { + names += name + etr += context.newClassPath(file) + } + } + } + + def check(n: String) { + if (!names.contains(n)) + throw new AssertionError("Cannot find assembly "+ n + + ". Use -Xassem-extdirs or -Xassem-path to specify its location") + } + check("mscorlib.dll") + check("scalaruntime.dll") + + // 3. Source path + for (dirName <- expandPath(source, expandStar = false)) { + val file = AbstractFile.getDirectory(dirName) + if (file ne null) etr += new SourcePath[MsilFile](file, context) + } + + etr.toList + } +} +import MsilClassPath._ + +/** + * A assembly file (dll / exe) containing classes and namespaces + */ +class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: MsilContext) extends ClassPath[MsilFile] { + def name = { + val i = namespace.lastIndexOf('.') + if (i < 0) namespace + else namespace drop (i + 1) + } + def asURLs = List(new java.net.URL(name)) + def asClasspathString = sys.error("Unknown") // I don't know what if anything makes sense here? + + private lazy val first: Int = { + var m = 0 + var n = types.length - 1 + while (m < n) { + val l = (m + n) / 2 + val res = types(l).FullName.compareTo(namespace) + if (res < 0) m = l + 1 + else n = l + } + if (types(m).FullName.startsWith(namespace)) m else types.length + } + + lazy val classes = { + val cls = new mutable.ListBuffer[ClassRep] + var i = first + while (i < types.length && types(i).Namespace.startsWith(namespace)) { + // CLRTypes used to exclude java.lang.Object and java.lang.String (no idea why..) + if (types(i).Namespace == namespace) + cls += ClassRep(Some(new MsilFile(types(i))), None) + i += 1 + } + cls.toIndexedSeq + } + + lazy val packages = { + val nsSet = new mutable.HashSet[String] + var i = first + while (i < types.length && types(i).Namespace.startsWith(namespace)) { + val subns = types(i).Namespace + if (subns.length > namespace.length) { + // example: namespace = "System", subns = "System.Reflection.Emit" + // => find second "." and "System.Reflection" to nsSet. + val end = subns.indexOf('.', namespace.length + 1) + nsSet += (if (end < 0) subns + else subns.substring(0, end)) + } + i += 1 + } + val xs = for (ns <- nsSet.toList) + yield new AssemblyClassPath(types, ns, context) + + xs.toIndexedSeq + } + + val sourcepaths: IndexedSeq[AbstractFile] = IndexedSeq() + + override def toString() = "assembly classpath "+ namespace +} + +/** + * The classpath when compiling with target:msil. Binary files are represented as + * MSILType values. + */ +class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) +extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } +*/ \ No newline at end of file -- cgit v1.2.3 From 6b8aed72e4f7a7135a434533399a772bf7078101 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 11:23:16 -0800 Subject: Made Any parents work more. Working on type printing logic. --- .../scala/reflect/internal/Definitions.scala | 42 +++++++++++++++---- src/compiler/scala/reflect/internal/Types.scala | 49 ++++++++++++---------- .../scala/reflect/internal/transform/Erasure.scala | 8 +--- .../scala/tools/nsc/ast/parser/Parsers.scala | 13 +++--- .../scala/tools/nsc/ast/parser/TreeBuilder.scala | 10 +++-- .../scala/tools/nsc/transform/Erasure.scala | 2 +- .../tools/nsc/typechecker/NamesDefaults.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 22 +++++----- src/library/scala/AnyVal.scala | 8 ++-- src/library/scala/NotNull.scala | 2 +- 10 files changed, 91 insertions(+), 67 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 47c711e81c..82d7f947e6 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -232,14 +232,15 @@ trait Definitions extends reflect.api.StandardDefinitions { private var oldValueScheme = true - lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse { -// println("new anyval") - oldValueScheme = true - val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, anyparam, 0L) - val av_constr = anyval.newClassConstructor(NoPosition) - anyval.info.decls enter av_constr - anyval - } + lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal +// lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse { +// // println("new anyval") +// oldValueScheme = true +// val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, anyparam, 0L) +// val av_constr = anyval.newClassConstructor(NoPosition) +// anyval.info.decls enter av_constr +// anyval +// } lazy val AnyVal_getClass = enterNewMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe)) // bottom types @@ -722,6 +723,31 @@ trait Definitions extends reflect.api.StandardDefinitions { } } + /** Remove references to class Object (other than the head) in a list of parents */ + def removeLaterObjects(tps: List[Type]): List[Type] = tps match { + case Nil => Nil + case x :: xs => x :: xs.filter(_.typeSymbol != ObjectClass) + } + /** Order a list of types with non-trait classes before others. */ + def classesFirst(tps: List[Type]): List[Type] = { + val (classes, others) = tps partition (t => t.typeSymbol.isClass && !t.typeSymbol.isTrait) + if (classes.isEmpty || others.isEmpty || (tps startsWith classes)) tps + else classes ::: others + } + /** The following transformations applied to a list of parents. + * If any parent is a class/trait, all parents which are Object + * or an alias of it are discarded. Otherwise, all Objects other + * the head of the list are discarded. + */ + def normalizedParents(parents: List[Type]): List[Type] = { + if (parents exists (t => (t.typeSymbol ne ObjectClass) && t.typeSymbol.isClass)) + parents filterNot (_.typeSymbol eq ObjectClass) + else + removeLaterObjects(parents) + } + def parentsString(parents: List[Type]) = + normalizedParents(parents) mkString " with " + // members of class java.lang.{ Object, String } lazy val Object_## = enterNewMethod(ObjectClass, nme.HASHHASH, Nil, inttype, FINAL) lazy val Object_== = enterNewMethod(ObjectClass, nme.EQ, anyrefparam, booltype, FINAL) diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 3ed6544613..89664bad9f 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -410,6 +410,11 @@ trait Types extends api.Types { self: SymbolTable => * inherited by typerefs, singleton types, and refinement types, * The empty list for all other types */ def parents: List[Type] = List() + + /** For a class with nonEmpty parents, the first parent. + * Otherwise some specific fixed top type. + */ + def firstParent = if (parents.nonEmpty) parents.head else ObjectClass.tpe /** For a typeref or single-type, the prefix of the normalized type (@see normalize). * NoType for all other types. */ @@ -1412,10 +1417,10 @@ trait Types extends api.Types { self: SymbolTable => // override def isNullable: Boolean = // parents forall (p => p.isNullable && !p.typeSymbol.isAbstractType); - override def safeToString: String = - parents.mkString(" with ") + + override def safeToString: String = parentsString(parents) + ( (if (settings.debug.value || parents.isEmpty || (decls.elems ne null)) decls.mkString("{", "; ", "}") else "") + ) } protected def defineBaseTypeSeqOfCompoundType(tpe: CompoundType) = { @@ -1477,7 +1482,7 @@ trait Types extends api.Types { self: SymbolTable => else { //Console.println("computing base classes of " + typeSymbol + " at phase " + phase);//DEBUG // optimized, since this seems to be performance critical - val superclazz = tpe.parents.head + val superclazz = tpe.firstParent var mixins = tpe.parents.tail val sbcs = superclazz.baseClasses var bcs = sbcs @@ -1524,7 +1529,7 @@ trait Types extends api.Types { self: SymbolTable => ) override def typeParams = - if (isHigherKinded) parents.head.typeParams + if (isHigherKinded) firstParent.typeParams else super.typeParams //@M may result in an invalid type (references to higher-order args become dangling ) @@ -2142,12 +2147,12 @@ trait Types extends api.Types { self: SymbolTable => ) else "" ) + private def finishPrefix(rest: String) = ( if (sym.isPackageClass) packagePrefix + rest else if (sym.isModuleClass) objectPrefix + rest else if (!sym.isInitialized) rest - else if (sym.isAnonymousClass && !phase.erasedTypes) - thisInfo.parents.mkString("", " with ", refinementString) + else if (sym.isAnonymousClass && !phase.erasedTypes) parentsString(thisInfo.parents) + refinementString else if (sym.isRefinementClass) "" + thisInfo else rest ) @@ -3225,11 +3230,21 @@ trait Types extends api.Types { self: SymbolTable => * comment or in the code? */ def intersectionType(tps: List[Type], owner: Symbol): Type = tps match { - case List(tp) => - tp - case _ => - refinedType(tps, owner) -/* + case tp :: Nil => tp + case _ => refinedType(tps, owner) + } + /** A creator for intersection type where intersections of a single type are + * replaced by the type itself. + */ + def intersectionType(tps: List[Type]): Type = tps match { + case tp :: Nil => tp + case _ => refinedType(tps, commonOwner(tps)) + } + +/**** This implementation to merge parents was checked in in commented-out + form and has languished unaltered for five years. I think we should + use it or lose it. + def merge(tps: List[Type]): List[Type] = tps match { case tp :: tps1 => val tps1a = tps1 filter (_.typeSymbol.==(tp.typeSymbol)) @@ -3244,14 +3259,6 @@ trait Types extends api.Types { self: SymbolTable => } refinedType(merge(tps), owner) */ - } - - /** A creator for intersection type where intersections of a single type are - * replaced by the type itself. */ - def intersectionType(tps: List[Type]): Type = tps match { - case List(tp) => tp - case _ => refinedType(tps, commonOwner(tps)) - } /** A creator for type applications */ def appliedType(tycon: Type, args: List[Type]): Type = @@ -4504,9 +4511,7 @@ trait Types extends api.Types { self: SymbolTable => else { commonOwnerMap.clear() tps foreach (commonOwnerMap traverse _) - val result = if (commonOwnerMap.result ne null) commonOwnerMap.result else NoSymbol - debuglog(tps.mkString("commonOwner(", ", ", ") == " + result)) - result + if (commonOwnerMap.result ne null) commonOwnerMap.result else NoSymbol } } diff --git a/src/compiler/scala/reflect/internal/transform/Erasure.scala b/src/compiler/scala/reflect/internal/transform/Erasure.scala index 4775541855..7c360e1f25 100644 --- a/src/compiler/scala/reflect/internal/transform/Erasure.scala +++ b/src/compiler/scala/reflect/internal/transform/Erasure.scala @@ -225,13 +225,7 @@ trait Erasure { /** Type reference after erasure */ def erasedTypeRef(sym: Symbol): Type = - typeRef(erasure(sym, sym.owner.tpe), sym, List()) - - /** Remove duplicate references to class Object in a list of parent classes */ - private def removeLaterObjects(tps: List[Type]): List[Type] = tps match { - case tp :: rest => tp :: (rest filter (_.typeSymbol != ObjectClass)) - case _ => tps - } + typeRef(erasure(sym, sym.owner.tpe), sym, Nil) /** The symbol's erased info. This is the type's erasure, except for the following symbols: * diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 40e7d88a3b..8e5a0139a5 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2753,19 +2753,18 @@ self => val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { - if (isPrimitiveType(name)) { - Template(List(scalaDot(tpnme.AnyVal)), self, body) - } + if (isPrimitiveType(name)) + Template(List(scalaAnyValConstr), self, body) else if (parents0 exists isReferenceToAnyVal) { // @inline and other restrictions enforced in refchecks Template(parents0, self, body) } - else if (name == tpnme.AnyVal) { - Template(List(scalaDot(tpnme.Any)), self, body) - } else { val parents = ( - if (parents0.isEmpty) List(scalaAnyRefConstr) + if (parents0.isEmpty) { + if (inScalaPackage && name == tpnme.AnyVal) List(scalaAnyConstr) + else List(scalaAnyRefConstr) + } /*if (!isInterface(mods, body) && !isScalaArray(name)) parents0 /* :+ scalaScalaObjectConstr*/ else*/ diff --git a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala index 906932f591..40389466e2 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/TreeBuilder.scala @@ -29,11 +29,13 @@ abstract class TreeBuilder { def rootId(name: Name) = gen.rootId(name) def rootScalaDot(name: Name) = gen.rootScalaDot(name) def scalaDot(name: Name) = gen.scalaDot(name) - def scalaAnyRefConstr = gen.scalaAnyRefConstr - def scalaUnitConstr = gen.scalaUnitConstr - def productConstr = gen.productConstr + def scalaAnyRefConstr = scalaDot(tpnme.AnyRef) + def scalaAnyValConstr = scalaDot(tpnme.AnyVal) + def scalaAnyConstr = scalaDot(tpnme.Any) + def scalaUnitConstr = scalaDot(tpnme.Unit) + def productConstr = scalaDot(tpnme.Product) def productConstrN(n: Int) = scalaDot(newTypeName("Product" + n)) - def serializableConstr = gen.serializableConstr + def serializableConstr = scalaDot(tpnme.Serializable) def convertToTypeName(t: Tree) = gen.convertToTypeName(t) diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 30bfdbaf5b..efbfe4da41 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -714,7 +714,7 @@ abstract class Erasure extends AddInterfaces var bridges: List[Tree] = List() val opc = atPhase(currentRun.explicitouterPhase) { new overridingPairs.Cursor(owner) { - override def parents: List[Type] = List(owner.info.parents.head) + override def parents: List[Type] = List(owner.info.firstParent) override def exclude(sym: Symbol): Boolean = !sym.isMethod || sym.isPrivate || super.exclude(sym) } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 3a3c244d1c..359e72e3e4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -228,7 +228,7 @@ trait NamesDefaults { self: Analyzer => case Select(sp @ Super(_, _), _) if isConstr => // 'moduleQual' fixes #3207. selection of the companion module of the // superclass needs to have the same prefix as the superclass. - blockWithoutQualifier(moduleQual(baseFun.pos, sp.symbol.tpe.parents.head)) + blockWithoutQualifier(moduleQual(baseFun.pos, sp.symbol.tpe.firstParent)) // self constructor calls (in secondary constructors) case Select(tp, name) if isConstr => diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index a20e78a81f..fdeab7b565 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1208,7 +1208,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { val supertpt1 = typedType(supertpt) if (!supertpt1.isErrorTyped) { mixins = supertpt1 :: mixins - supertpt = TypeTree(supertpt1.tpe.parents.head) setPos supertpt.pos.focus + supertpt = TypeTree(supertpt1.tpe.firstParent) setPos supertpt.pos.focus } } if (supertpt.tpe.typeSymbol == AnyClass && firstParent.isTrait && firstParent != AnyValClass) @@ -1302,12 +1302,15 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { else xs ) } + fixDuplicates(supertpt :: mixins) mapConserve (tpt => checkNoEscaping.privates(clazz, tpt)) } catch { case ex: TypeError => // fallback in case of cyclic errors // @H none of the tests enter here but I couldn't rule it out + log("Type error calculating parents in template " + templ) + log("Error: " + ex) ParentTypesError(templ, ex) List(TypeTree(AnyRefClass.tpe)) } @@ -1415,7 +1418,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { _.typedTemplate(cdef.impl, parentTypes(cdef.impl)) } val impl2 = finishMethodSynthesis(impl1, clazz, context) - if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.parents.head.typeSymbol == AnyClass) + if (clazz.isTrait && clazz.info.parents.nonEmpty && clazz.info.firstParent.typeSymbol == AnyClass) for (stat <- impl2.body) if (!treeInfo.isAllowedInAnyTrait(stat)) unit.error(stat.pos, "this statement is not allowed in trait extending from class Any: "+stat) @@ -3670,16 +3673,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - val owntype = - if (mix.isEmpty) { - if ((mode & SUPERCONSTRmode) != 0) - if (clazz.info.parents.isEmpty) AnyRefClass.tpe // can happen due to cyclic references ==> #1036 - else clazz.info.parents.head - else intersectionType(clazz.info.parents) - } else { - findMixinSuper(clazz.tpe) - } - + val owntype = ( + if (!mix.isEmpty) findMixinSuper(clazz.tpe) + else if ((mode & SUPERCONSTRmode) != 0) clazz.info.firstParent + else intersectionType(clazz.info.parents) + ) treeCopy.Super(tree, qual1, mix) setType SuperType(clazz.thisType, owntype) } diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index ed32fb7302..daad6f6f5e 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -25,8 +25,8 @@ package scala * The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ -trait AnyVal extends NotNull { -// disabled for now to make the standard build go through. -// Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. -// def getClass(): Class[_ <: AnyVal] = ??? +trait AnyVal extends Any with NotNull { + // disabled for now to make the standard build go through. + // Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. + def getClass(): Class[_ <: AnyVal] = ??? } diff --git a/src/library/scala/NotNull.scala b/src/library/scala/NotNull.scala index f90b95c789..64f999a932 100644 --- a/src/library/scala/NotNull.scala +++ b/src/library/scala/NotNull.scala @@ -12,4 +12,4 @@ package scala * A marker trait for things that are not allowed to be null * @since 2.5 */ -trait NotNull {} +trait NotNull extends Any {} -- cgit v1.2.3 From 3a6b1124f18acf95923e228f6f41bdf3c23e0173 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 11:56:16 -0800 Subject: Guard List_apply from premature forcitude. Solved the annotation cycle puzzle. Was being burned again by the hack which preferentially treats List() as Nil to avoid List's extractor. This commit includes a new starr which fully bootstraps. Also at this point traits can extend Any and will not be given an AnyRef parent (until erasure.) This is the case for AnyVal and NotNull. --- lib/scala-compiler.jar.desired.sha1 | 2 +- lib/scala-library-src.jar.desired.sha1 | 2 +- lib/scala-library.jar.desired.sha1 | 2 +- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 5 ++++- 4 files changed, 7 insertions(+), 4 deletions(-) (limited to 'src/compiler') diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1 index cc8631c6d4..22e714ad41 100644 --- a/lib/scala-compiler.jar.desired.sha1 +++ b/lib/scala-compiler.jar.desired.sha1 @@ -1 +1 @@ -65ea33d0d4cc4aab5472f123524640fd1fab0a85 ?scala-compiler.jar +83df84e719c0f966c67855a1b453aaff2c01e4f7 ?scala-compiler.jar diff --git a/lib/scala-library-src.jar.desired.sha1 b/lib/scala-library-src.jar.desired.sha1 index 81d1f677a5..cb39ee8604 100644 --- a/lib/scala-library-src.jar.desired.sha1 +++ b/lib/scala-library-src.jar.desired.sha1 @@ -1 +1 @@ -d92a0fd350a661b4ba55f1aeea43a2ba5dec4629 ?scala-library-src.jar +04d9d47973b10ec7353e2a8199b1bd5c62fb540a ?scala-library-src.jar diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1 index 975649f4b4..009d5f82ea 100644 --- a/lib/scala-library.jar.desired.sha1 +++ b/lib/scala-library.jar.desired.sha1 @@ -1 +1 @@ -ff3132990962fd0b779a5e8ceef163acdf0c3e29 ?scala-library.jar +c8e01ec6416bd883e996cf8c6916bf0173c31486 ?scala-library.jar diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index fdeab7b565..1d84f7fdaf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -2525,8 +2525,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { /** This is translating uses of List() into Nil. This is less * than ideal from a consistency standpoint, but it shouldn't be * altered without due caution. + * ... this also causes bootstrapping cycles if List_apply is + * forced during kind-arity checking, so it is guarded by additional + * tests to ensure we're sufficiently far along. */ - if (fun.symbol == List_apply && args.isEmpty && !forInteractive) + if (args.isEmpty && !forInteractive && fun.symbol.isInitialized && ListModule.hasCompleteInfo && (fun.symbol == List_apply)) atPos(tree.pos)(gen.mkNil setType restpe) else constfold(treeCopy.Apply(tree, fun, args1) setType ifPatternSkipFormals(restpe)) -- cgit v1.2.3 From c6a783ac089d8cf5a60a98946af5e80aff5a7d32 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 14:36:14 -0800 Subject: Making AnyVal into a class instead of a trait. -- traits can extend Any, AnyRef, or AnyVal -- classes can extend AnyRef or AnyVal but not Any. This breaks reflection for the moment as it smuggles AnyVal so far downstream that it's reflecting its way into bytecode (or something) but the following test case goes five for six as anticipated. trait Foo1 extends Any trait Foo2 extends AnyVal trait Foo3 extends AnyRef class Bar1 extends Any // fail @inline class Bar2 extends AnyVal class Bar3 extends AnyRef Eliminated various hijinx from definitions. --- lib/scala-compiler.jar.desired.sha1 | 2 +- lib/scala-library-src.jar.desired.sha1 | 2 +- lib/scala-library.jar.desired.sha1 | 2 +- .../scala/reflect/internal/Definitions.scala | 29 +++++----------------- .../scala/tools/nsc/ast/parser/Parsers.scala | 11 ++++---- .../scala/tools/nsc/transform/AddInterfaces.scala | 12 ++++++--- .../scala/tools/nsc/transform/Constructors.scala | 13 ++++++---- .../scala/tools/nsc/typechecker/Typers.scala | 2 ++ src/library/scala/AnyVal.scala | 2 +- test/files/neg/anyval-anyref-parent.check | 4 +++ test/files/neg/anyval-anyref-parent.scala | 7 ++++++ 11 files changed, 45 insertions(+), 41 deletions(-) create mode 100644 test/files/neg/anyval-anyref-parent.check create mode 100644 test/files/neg/anyval-anyref-parent.scala (limited to 'src/compiler') diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1 index 22e714ad41..79f6de5e27 100644 --- a/lib/scala-compiler.jar.desired.sha1 +++ b/lib/scala-compiler.jar.desired.sha1 @@ -1 +1 @@ -83df84e719c0f966c67855a1b453aaff2c01e4f7 ?scala-compiler.jar +40f87533e0d03ad04ca632119286d347ee54d8ae ?scala-compiler.jar diff --git a/lib/scala-library-src.jar.desired.sha1 b/lib/scala-library-src.jar.desired.sha1 index cb39ee8604..cfb865f1e8 100644 --- a/lib/scala-library-src.jar.desired.sha1 +++ b/lib/scala-library-src.jar.desired.sha1 @@ -1 +1 @@ -04d9d47973b10ec7353e2a8199b1bd5c62fb540a ?scala-library-src.jar +4a34794dd9a45cd2e8603de559f565535e7aa74b ?scala-library-src.jar diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1 index 009d5f82ea..28a2c586a0 100644 --- a/lib/scala-library.jar.desired.sha1 +++ b/lib/scala-library.jar.desired.sha1 @@ -1 +1 @@ -c8e01ec6416bd883e996cf8c6916bf0173c31486 ?scala-library.jar +3516dc2e17bf72b1e4bc665e59f6b7ec51cba48d ?scala-library.jar diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 82d7f947e6..7bd0c0f919 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -230,17 +230,12 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val AnyCompanionClass = getRequiredClass("scala.AnyCompanion") initFlags (SEALED | ABSTRACT | TRAIT) lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") initFlags (SEALED | ABSTRACT | TRAIT) - private var oldValueScheme = true - - lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal -// lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse { -// // println("new anyval") -// oldValueScheme = true -// val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, anyparam, 0L) -// val av_constr = anyval.newClassConstructor(NoPosition) -// anyval.info.decls enter av_constr -// anyval -// } + lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse { + val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, List(AnyClass.tpe, NotNullClass.tpe), 0L) + val av_constr = anyval.newClassConstructor(NoPosition) + anyval.info.decls enter av_constr + anyval + } lazy val AnyVal_getClass = enterNewMethod(AnyValClass, nme.getClass_, Nil, getClassReturnType(AnyValClass.tpe)) // bottom types @@ -1077,22 +1072,10 @@ trait Definitions extends reflect.api.StandardDefinitions { Object_synchronized, Object_isInstanceOf, Object_asInstanceOf, - //AnyVal_getClass, String_+, ComparableClass ) - /* Removing the anyref parent they acquire from having a source file. - */ - if (oldValueScheme) { - setParents(AnyValClass, List(NotNullClass.tpe, AnyClass.tpe)) - } else { - AnyVal_getClass // force it! - } - ScalaValueClasses foreach { sym => - setParents(sym, anyvalparam) - } - isInitialized = true } //init diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 8e5a0139a5..f7401c813a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2753,7 +2753,11 @@ self => val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { - if (isPrimitiveType(name)) + if (inScalaPackage && name == tpnme.AnyVal) { + val constructor = DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(), Block(Nil, Literal(Constant()))) + Template(parents0, self, constructor :: body) + } + else if (isPrimitiveType(name)) Template(List(scalaAnyValConstr), self, body) else if (parents0 exists isReferenceToAnyVal) { // @inline and other restrictions enforced in refchecks @@ -2761,10 +2765,7 @@ self => } else { val parents = ( - if (parents0.isEmpty) { - if (inScalaPackage && name == tpnme.AnyVal) List(scalaAnyConstr) - else List(scalaAnyRefConstr) - } + if (parents0.isEmpty) List(scalaAnyRefConstr) /*if (!isInterface(mods, body) && !isScalaArray(name)) parents0 /* :+ scalaScalaObjectConstr*/ else*/ diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 89dfbfd317..8fe82258e2 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -301,12 +301,16 @@ abstract class AddInterfaces extends InfoTransform { if mc.hasFlag(lateINTERFACE)) yield mixinConstructorCall(implClass(mc)) } - (tree: @unchecked) match { + tree match { case Block(stats, expr) => // needs `hasSymbol` check because `supercall` could be a block (named / default args) - val (presuper, supercall :: rest) = stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) - // assert(supercall.symbol.isClassConstructor, supercall) - treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) + stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) match { + case (presuper, supercall :: rest) => + stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) + treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) + case (Nil, Nil) => // AnyVal constructor + Literal(Constant()) + } } } diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index 256f13b3fb..a672059211 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -44,11 +44,14 @@ abstract class Constructors extends Transform with ast.TreeDSL { ) // decompose primary constructor into the three entities above. val constrInfo: ConstrInfo = { - val primary = stats find (_.symbol.isPrimaryConstructor) - assert(primary.isDefined, "no constructor in template: impl = " + impl) - - val ddef @ DefDef(_, _, _, List(vparams), _, rhs @ Block(_, _)) = primary.get - ConstrInfo(ddef, vparams map (_.symbol), rhs) + stats find (_.symbol.isPrimaryConstructor) match { + case Some(ddef @ DefDef(_, _, _, List(vparams), _, rhs @ Block(_, _))) => + ConstrInfo(ddef, vparams map (_.symbol), rhs) + case x => + // assert(false, "no constructor in template: impl = " + impl) + // AnyVal constructor + return impl + } } import constrInfo._ diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1d84f7fdaf..ba3172dd06 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1610,6 +1610,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { * @param rhs ... */ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { + if (clazz eq AnyValClass) + return debuglog("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => diff --git a/src/library/scala/AnyVal.scala b/src/library/scala/AnyVal.scala index daad6f6f5e..393f0899f4 100644 --- a/src/library/scala/AnyVal.scala +++ b/src/library/scala/AnyVal.scala @@ -25,7 +25,7 @@ package scala * The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. * The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. */ -trait AnyVal extends Any with NotNull { +abstract class AnyVal extends Any with NotNull { // disabled for now to make the standard build go through. // Once we have a new strap we can uncomment this and delete the AnyVal_getClass entry in Definitions. def getClass(): Class[_ <: AnyVal] = ??? diff --git a/test/files/neg/anyval-anyref-parent.check b/test/files/neg/anyval-anyref-parent.check new file mode 100644 index 0000000000..b40a0f2710 --- /dev/null +++ b/test/files/neg/anyval-anyref-parent.check @@ -0,0 +1,4 @@ +anyval-anyref-parent.scala:5: error: Any does not have a constructor +class Bar1 extends Any // fail + ^ +one error found diff --git a/test/files/neg/anyval-anyref-parent.scala b/test/files/neg/anyval-anyref-parent.scala new file mode 100644 index 0000000000..b7bb122ea8 --- /dev/null +++ b/test/files/neg/anyval-anyref-parent.scala @@ -0,0 +1,7 @@ +trait Foo1 extends Any +trait Foo2 extends AnyVal +trait Foo3 extends AnyRef + +class Bar1 extends Any // fail +@inline class Bar2 extends AnyVal +class Bar3 extends AnyRef -- cgit v1.2.3 From dcb5fe93162fcf7112d95733ecb78075dbd34f90 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 21:06:13 -0800 Subject: Utilizing convenience methods martin hasn't discovered yet. --- src/compiler/scala/reflect/internal/Definitions.scala | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index 7bd0c0f919..a06f2d07bf 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -206,11 +206,6 @@ trait Definitions extends reflect.api.StandardDefinitions { case _ => null } - private def fixupAsAnyTrait(clazz: Symbol): Symbol = { - clazz setInfo fixupAsAnyTrait(clazz.info) - clazz - } - private def fixupAsAnyTrait(tpe: Type): Type = tpe match { case ClassInfoType(parents, decls, clazz) => if (parents.head.typeSymbol == AnyClass) tpe @@ -231,7 +226,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val AnyValCompanionClass = getRequiredClass("scala.AnyValCompanion") initFlags (SEALED | ABSTRACT | TRAIT) lazy val AnyValClass = ScalaPackageClass.info member tpnme.AnyVal orElse { - val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, List(AnyClass.tpe, NotNullClass.tpe), 0L) + val anyval = enterNewClass(ScalaPackageClass, tpnme.AnyVal, List(AnyClass.tpe, NotNullClass.tpe), 0L) val av_constr = anyval.newClassConstructor(NoPosition) anyval.info.decls enter av_constr anyval @@ -339,7 +334,7 @@ trait Definitions extends reflect.api.StandardDefinitions { lazy val SingletonClass = enterNewClass(ScalaPackageClass, tpnme.Singleton, anyparam, ABSTRACT | TRAIT | FINAL) lazy val SerializableClass = getRequiredClass("scala.Serializable") lazy val JavaSerializableClass = getClass(sn.JavaSerializable) - lazy val ComparableClass = fixupAsAnyTrait(getRequiredClass("java.lang.Comparable")) + lazy val ComparableClass = getRequiredClass("java.lang.Comparable") modifyInfo fixupAsAnyTrait lazy val JavaCloneableClass = getRequiredClass("java.lang.Cloneable") lazy val RemoteInterfaceClass = getRequiredClass("java.rmi.Remote") lazy val RemoteExceptionClass = getRequiredClass("java.rmi.RemoteException") -- cgit v1.2.3 From 6ba9411c7c6abdbd907ca93208ac58b474b201d0 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 21:06:42 -0800 Subject: Restored msil. --- build.xml | 12 +- lib/msil.jar.desired.sha1 | 2 +- .../scala/tools/nsc/backend/MSILPlatform.scala | 11 +- .../scala/tools/nsc/backend/icode/GenICode.scala | 322 ++++++++++----------- .../scala/tools/nsc/backend/icode/Opcodes.scala | 114 ++++---- .../scala/tools/nsc/backend/icode/TypeKinds.scala | 13 +- .../scala/tools/nsc/backend/msil/GenMSIL.scala | 25 +- src/compiler/scala/tools/nsc/io/MsilFile.scala | 5 +- .../scala/tools/nsc/symtab/SymbolLoaders.scala | 32 +- .../scala/tools/nsc/symtab/clr/CLRTypes.scala | 15 +- .../scala/tools/nsc/symtab/clr/TypeParser.scala | 165 ++++++----- .../scala/tools/nsc/util/MsilClassPath.scala | 21 +- 12 files changed, 366 insertions(+), 371 deletions(-) (limited to 'src/compiler') diff --git a/build.xml b/build.xml index f50d51e80a..57d2eed1c0 100644 --- a/build.xml +++ b/build.xml @@ -281,7 +281,7 @@ INITIALISATION - + @@ -490,7 +490,7 @@ PACKED LOCKER BUILD (PALO) - + @@ -640,12 +640,12 @@ QUICK BUILD (QUICK) - + - + @@ -968,7 +968,7 @@ PACKED QUICK BUILD (PACK) - + @@ -1901,7 +1901,7 @@ STABLE REFERENCE (STARR) - + diff --git a/lib/msil.jar.desired.sha1 b/lib/msil.jar.desired.sha1 index 7dd6b5d66b..ac09965566 100644 --- a/lib/msil.jar.desired.sha1 +++ b/lib/msil.jar.desired.sha1 @@ -1 +1 @@ -58f64cd00399c724e7d526e5bdcbce3e2b79f78b ?msil.jar +046beeda12838b9ad34306caad71a523d06b1f31 ?msil.jar diff --git a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala index d5a02f9242..65b1fbc229 100644 --- a/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala +++ b/src/compiler/scala/tools/nsc/backend/MSILPlatform.scala @@ -6,12 +6,12 @@ package scala.tools.nsc package backend -// import ch.epfl.lamp.compiler.{ msil => msillib } -// import util.{ ClassPath, MsilClassPath } -// import msil.GenMSIL -// import io.{ AbstractFile, MsilFile } +import ch.epfl.lamp.compiler.{ msil => msillib } +import util.{ ClassPath, MsilClassPath } +import msil.GenMSIL +import io.{ AbstractFile, MsilFile } -trait MSILPlatform /*extends Platform { +trait MSILPlatform extends Platform { import global._ import definitions.{ ComparatorClass, BoxedNumberClass, getMember } @@ -63,4 +63,3 @@ trait MSILPlatform /*extends Platform { def needCompile(bin: MsilFile, src: AbstractFile) = false // always use compiled file on .net } -*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index acb20b4627..3baff7da9e 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -160,8 +160,8 @@ abstract class GenICode extends SubComponent { case Assign(lhs @ Select(_, _), rhs) => val isStatic = lhs.symbol.isStaticMember var ctx1 = if (isStatic) ctx - // else if (forMSIL && msil_IsValuetypeInstField(lhs.symbol)) - // msil_genLoadQualifierAddress(lhs, ctx) + else if (forMSIL && msil_IsValuetypeInstField(lhs.symbol)) + msil_genLoadQualifierAddress(lhs, ctx) else genLoadQualifier(lhs, ctx) ctx1 = genLoad(rhs, ctx1, toTypeKind(lhs.symbol.info)) @@ -460,132 +460,132 @@ abstract class GenICode extends SubComponent { fun.symbol.simpleName + ") " + " at: " + (tree.pos) ) } - // - // /** - // * forMSIL - // */ - // private def msil_IsValuetypeInstMethod(msym: Symbol) = ( - // loaders.clrTypes.methods get msym exists (mMSIL => - // mMSIL.IsInstance && mMSIL.DeclaringType.IsValueType - // ) - // ) - // private def msil_IsValuetypeInstField(fsym: Symbol) = ( - // loaders.clrTypes.fields get fsym exists (fMSIL => - // !fMSIL.IsStatic && fMSIL.DeclaringType.IsValueType - // ) - // ) - // - // /** - // * forMSIL: Adds a local var, the emitted code requires one more slot on the stack as on entry - // */ - // private def msil_genLoadZeroOfNonEnumValuetype(ctx: Context, kind: TypeKind, pos: Position, leaveAddressOnStackInstead: Boolean) { - // val REFERENCE(clssym) = kind - // assert(loaders.clrTypes.isNonEnumValuetype(clssym), clssym) - // val local = ctx.makeLocal(pos, clssym.tpe, "tmp") - // ctx.method.addLocal(local) - // ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(local), pos) - // ctx.bb.emit(CIL_INITOBJ(kind), pos) - // val instr = if (leaveAddressOnStackInstead) - // CIL_LOAD_LOCAL_ADDRESS(local) - // else - // LOAD_LOCAL(local) - // ctx.bb.emit(instr, pos) - // } - // - // /** - // * forMSIL - // */ - // private def msil_genLoadAddressOf(tree: Tree, ctx: Context, expectedType: TypeKind, butRawValueIsAlsoGoodEnough: Boolean): Context = { - // var generatedType = expectedType - // var addressTaken = false - // debuglog("at line: " + (if (tree.pos.isDefined) tree.pos.line else tree.pos)) - // - // var resCtx: Context = tree match { - // - // // emits CIL_LOAD_FIELD_ADDRESS - // case Select(qualifier, selector) if (!tree.symbol.isModule) => - // addressTaken = true - // val sym = tree.symbol - // generatedType = toTypeKind(sym.info) - // - // if (sym.isStaticMember) { - // ctx.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, true), tree.pos) - // ctx - // } else { - // val ctx1 = genLoadQualifier(tree, ctx) - // ctx1.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, false), tree.pos) - // ctx1 - // } - // - // // emits CIL_LOAD_LOCAL_ADDRESS - // case Ident(name) if (!tree.symbol.isPackage && !tree.symbol.isModule)=> - // addressTaken = true - // val sym = tree.symbol - // try { - // val Some(l) = ctx.method.lookupLocal(sym) - // ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(l), tree.pos) - // generatedType = l.kind // actually, should be "V&" but the callsite is aware of this - // } catch { - // case ex: MatchError => - // abort("symbol " + sym + " does not exist in " + ctx.method) - // } - // ctx - // - // // emits CIL_LOAD_ARRAY_ITEM_ADDRESS - // case Apply(fun, args) => - // if (isPrimitive(fun.symbol)) { - // - // val sym = tree.symbol - // val Apply(fun @ Select(receiver, _), args) = tree - // val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) - // - // if (isArrayOp(code)) { - // val arrayObj = receiver - // val k = toTypeKind(arrayObj.tpe) - // val ARRAY(elementType) = k - // if (scalaPrimitives.isArrayGet(code)) { - // var ctx1 = genLoad(arrayObj, ctx, k) - // // load argument on stack - // debugassert(args.length == 1, "Too many arguments for array get operation: " + tree) - // ctx1 = genLoad(args.head, ctx1, INT) - // generatedType = elementType // actually "managed pointer to element type" but the callsite is aware of this - // ctx1.bb.emit(CIL_LOAD_ARRAY_ITEM_ADDRESS(elementType), tree.pos) - // addressTaken = true - // ctx1 - // } else null - // } else null - // } else null - // - // case This(qual) => - // /* TODO: this case handler is a placeholder for the time when Level 2 support for valuetypes is in place, - // in particular when invoking other methods on this where this is a valuetype value (boxed or not). - // As receiver, a managed pointer is expected, and a plain ldarg.0 achieves just that. */ - // addressTaken = true - // genLoad(tree, ctx, expectedType) - // - // case _ => - // null /* A method returning ByRef won't pass peverify, so I guess this case handler is dead code. - // Even if it's not, the code below to handler !addressTaken below. */ - // } - // - // if (!addressTaken) { - // resCtx = genLoad(tree, ctx, expectedType) - // if (!butRawValueIsAlsoGoodEnough) { - // // raw value on stack (must be an intermediate result, e.g. returned by method call), take address - // addressTaken = true - // val boxType = expectedType // toTypeKind(expectedType /* TODO FIXME */) - // resCtx.bb.emit(BOX(boxType), tree.pos) - // resCtx.bb.emit(CIL_UNBOX(boxType), tree.pos) - // } - // } - // - // // emit conversion - // if (generatedType != expectedType) - // abort("Unexpected tree in msil_genLoadAddressOf: " + tree + " at: " + tree.pos) - // - // resCtx - // } - // + + /** + * forMSIL + */ + private def msil_IsValuetypeInstMethod(msym: Symbol) = ( + loaders.clrTypes.methods get msym exists (mMSIL => + mMSIL.IsInstance && mMSIL.DeclaringType.IsValueType + ) + ) + private def msil_IsValuetypeInstField(fsym: Symbol) = ( + loaders.clrTypes.fields get fsym exists (fMSIL => + !fMSIL.IsStatic && fMSIL.DeclaringType.IsValueType + ) + ) + + /** + * forMSIL: Adds a local var, the emitted code requires one more slot on the stack as on entry + */ + private def msil_genLoadZeroOfNonEnumValuetype(ctx: Context, kind: TypeKind, pos: Position, leaveAddressOnStackInstead: Boolean) { + val REFERENCE(clssym) = kind + assert(loaders.clrTypes.isNonEnumValuetype(clssym), clssym) + val local = ctx.makeLocal(pos, clssym.tpe, "tmp") + ctx.method.addLocal(local) + ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(local), pos) + ctx.bb.emit(CIL_INITOBJ(kind), pos) + val instr = if (leaveAddressOnStackInstead) + CIL_LOAD_LOCAL_ADDRESS(local) + else + LOAD_LOCAL(local) + ctx.bb.emit(instr, pos) + } + + /** + * forMSIL + */ + private def msil_genLoadAddressOf(tree: Tree, ctx: Context, expectedType: TypeKind, butRawValueIsAlsoGoodEnough: Boolean): Context = { + var generatedType = expectedType + var addressTaken = false + debuglog("at line: " + (if (tree.pos.isDefined) tree.pos.line else tree.pos)) + + var resCtx: Context = tree match { + + // emits CIL_LOAD_FIELD_ADDRESS + case Select(qualifier, selector) if (!tree.symbol.isModule) => + addressTaken = true + val sym = tree.symbol + generatedType = toTypeKind(sym.info) + + if (sym.isStaticMember) { + ctx.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, true), tree.pos) + ctx + } else { + val ctx1 = genLoadQualifier(tree, ctx) + ctx1.bb.emit(CIL_LOAD_FIELD_ADDRESS(sym, false), tree.pos) + ctx1 + } + + // emits CIL_LOAD_LOCAL_ADDRESS + case Ident(name) if (!tree.symbol.isPackage && !tree.symbol.isModule)=> + addressTaken = true + val sym = tree.symbol + try { + val Some(l) = ctx.method.lookupLocal(sym) + ctx.bb.emit(CIL_LOAD_LOCAL_ADDRESS(l), tree.pos) + generatedType = l.kind // actually, should be "V&" but the callsite is aware of this + } catch { + case ex: MatchError => + abort("symbol " + sym + " does not exist in " + ctx.method) + } + ctx + + // emits CIL_LOAD_ARRAY_ITEM_ADDRESS + case Apply(fun, args) => + if (isPrimitive(fun.symbol)) { + + val sym = tree.symbol + val Apply(fun @ Select(receiver, _), args) = tree + val code = scalaPrimitives.getPrimitive(sym, receiver.tpe) + + if (isArrayOp(code)) { + val arrayObj = receiver + val k = toTypeKind(arrayObj.tpe) + val ARRAY(elementType) = k + if (scalaPrimitives.isArrayGet(code)) { + var ctx1 = genLoad(arrayObj, ctx, k) + // load argument on stack + debugassert(args.length == 1, "Too many arguments for array get operation: " + tree) + ctx1 = genLoad(args.head, ctx1, INT) + generatedType = elementType // actually "managed pointer to element type" but the callsite is aware of this + ctx1.bb.emit(CIL_LOAD_ARRAY_ITEM_ADDRESS(elementType), tree.pos) + addressTaken = true + ctx1 + } else null + } else null + } else null + + case This(qual) => + /* TODO: this case handler is a placeholder for the time when Level 2 support for valuetypes is in place, + in particular when invoking other methods on this where this is a valuetype value (boxed or not). + As receiver, a managed pointer is expected, and a plain ldarg.0 achieves just that. */ + addressTaken = true + genLoad(tree, ctx, expectedType) + + case _ => + null /* A method returning ByRef won't pass peverify, so I guess this case handler is dead code. + Even if it's not, the code below to handler !addressTaken below. */ + } + + if (!addressTaken) { + resCtx = genLoad(tree, ctx, expectedType) + if (!butRawValueIsAlsoGoodEnough) { + // raw value on stack (must be an intermediate result, e.g. returned by method call), take address + addressTaken = true + val boxType = expectedType // toTypeKind(expectedType /* TODO FIXME */) + resCtx.bb.emit(BOX(boxType), tree.pos) + resCtx.bb.emit(CIL_UNBOX(boxType), tree.pos) + } + } + + // emit conversion + if (generatedType != expectedType) + abort("Unexpected tree in msil_genLoadAddressOf: " + tree + " at: " + tree.pos) + + resCtx + } + /** * Generate code for trees that produce values on the stack @@ -793,19 +793,19 @@ abstract class GenICode extends SubComponent { debugassert(ctor.owner == cls, "Symbol " + ctor.owner.fullName + " is different than " + tpt) - // val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) { - // /* parameterful constructors are the only possible custom constructors, - // a default constructor can't be defined for valuetypes, CLR dixit */ - // val isDefaultConstructor = args.isEmpty - // if (isDefaultConstructor) { - // msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false) - // ctx - // } else { - // val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx) - // ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos) - // ctx1 - // } - // } else { + val ctx2 = if (forMSIL && loaders.clrTypes.isNonEnumValuetype(cls)) { + /* parameterful constructors are the only possible custom constructors, + a default constructor can't be defined for valuetypes, CLR dixit */ + val isDefaultConstructor = args.isEmpty + if (isDefaultConstructor) { + msil_genLoadZeroOfNonEnumValuetype(ctx, rt, tree.pos, leaveAddressOnStackInstead = false) + ctx + } else { + val ctx1 = genLoadArguments(args, ctor.info.paramTypes, ctx) + ctx1.bb.emit(CIL_NEWOBJ(ctor), tree.pos) + ctx1 + } + } else { val nw = NEW(rt) ctx.bb.emit(nw, tree.pos) ctx.bb.emit(DUP(generatedType)) @@ -815,8 +815,8 @@ abstract class GenICode extends SubComponent { nw.init = init ctx1.bb.emit(init, tree.pos) ctx1 - // } - // ctx2 + } + ctx2 case _ => abort("Cannot instantiate " + tpt + "of kind: " + generatedType) @@ -845,12 +845,12 @@ abstract class GenICode extends SubComponent { generatedType = boxType ctx1.bb.emit(UNBOX(boxType), expr.pos) ctx1 - // - // case Apply(fun @ _, List(expr)) if (forMSIL && loaders.clrTypes.isAddressOf(fun.symbol)) => - // debuglog("ADDRESSOF : " + fun.symbol.fullName); - // val ctx1 = msil_genLoadAddressOf(expr, ctx, toTypeKind(expr.tpe), butRawValueIsAlsoGoodEnough = false) - // generatedType = toTypeKind(fun.symbol.tpe.resultType) - // ctx1 + + case Apply(fun @ _, List(expr)) if (forMSIL && loaders.clrTypes.isAddressOf(fun.symbol)) => + debuglog("ADDRESSOF : " + fun.symbol.fullName); + val ctx1 = msil_genLoadAddressOf(expr, ctx, toTypeKind(expr.tpe), butRawValueIsAlsoGoodEnough = false) + generatedType = toTypeKind(fun.symbol.tpe.resultType) + ctx1 case app @ Apply(fun, args) => val sym = fun.symbol @@ -887,9 +887,9 @@ abstract class GenICode extends SubComponent { var ctx1 = if (invokeStyle.hasInstance) { - // if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym)) - // msil_genLoadQualifierAddress(fun, ctx) - // else + if (forMSIL && !(invokeStyle.isInstanceOf[SuperCall]) && msil_IsValuetypeInstMethod(sym)) + msil_genLoadQualifierAddress(fun, ctx) + else genLoadQualifier(fun, ctx) } else ctx @@ -1150,15 +1150,15 @@ abstract class GenICode extends SubComponent { case _ => abort("Unknown qualifier " + tree) } - // - // /** forMSIL */ - // private def msil_genLoadQualifierAddress(tree: Tree, ctx: Context): Context = - // tree match { - // case Select(qualifier, _) => - // msil_genLoadAddressOf(qualifier, ctx, toTypeKind(qualifier.tpe), butRawValueIsAlsoGoodEnough = false) - // case _ => - // abort("Unknown qualifier " + tree) - // } + + /** forMSIL */ + private def msil_genLoadQualifierAddress(tree: Tree, ctx: Context): Context = + tree match { + case Select(qualifier, _) => + msil_genLoadAddressOf(qualifier, ctx, toTypeKind(qualifier.tpe), butRawValueIsAlsoGoodEnough = false) + case _ => + abort("Unknown qualifier " + tree) + } /** * Generate code that loads args into label parameters. diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala index bf8580b903..2bcfb9d4a9 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala @@ -636,63 +636,63 @@ trait Opcodes { self: ICodes => // CLR backend -// -// case class CIL_LOAD_LOCAL_ADDRESS(local: Local) extends Instruction { -// /** Returns a string representation of this instruction */ -// override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local //+isArgument?" (argument)":""; -// -// override def consumed = 0 -// override def produced = 1 -// -// override def producedTypes = List(msil_mgdptr(local.kind)) -// } -// -// case class CIL_LOAD_FIELD_ADDRESS(field: Symbol, isStatic: Boolean) extends Instruction { -// /** Returns a string representation of this instruction */ -// override def toString(): String = -// "CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString) -// -// override def consumed = if (isStatic) 0 else 1 -// override def produced = 1 -// -// override def consumedTypes = if (isStatic) Nil else List(REFERENCE(field.owner)); -// override def producedTypes = List(msil_mgdptr(REFERENCE(field.owner))); -// } -// -// case class CIL_LOAD_ARRAY_ITEM_ADDRESS(kind: TypeKind) extends Instruction { -// /** Returns a string representation of this instruction */ -// override def toString(): String = "CIL_LOAD_ARRAY_ITEM_ADDRESS (" + kind + ")" -// -// override def consumed = 2 -// override def produced = 1 -// -// override def consumedTypes = List(ARRAY(kind), INT) -// override def producedTypes = List(msil_mgdptr(kind)) -// } -// -// case class CIL_UNBOX(valueType: TypeKind) extends Instruction { -// override def toString(): String = "CIL_UNBOX " + valueType -// override def consumed = 1 -// override def consumedTypes = ObjectReference :: Nil // actually consumes a 'boxed valueType' -// override def produced = 1 -// override def producedTypes = List(msil_mgdptr(valueType)) -// } -// -// case class CIL_INITOBJ(valueType: TypeKind) extends Instruction { -// override def toString(): String = "CIL_INITOBJ " + valueType -// override def consumed = 1 -// override def consumedTypes = ObjectReference :: Nil // actually consumes a managed pointer -// override def produced = 0 -// } -// -// case class CIL_NEWOBJ(method: Symbol) extends Instruction { -// override def toString(): String = "CIL_NEWOBJ " + hostClass.fullName + method.fullName -// var hostClass: Symbol = method.owner; -// override def consumed = method.tpe.paramTypes.length -// override def consumedTypes = method.tpe.paramTypes map toTypeKind -// override def produced = 1 -// override def producedTypes = List(toTypeKind(method.tpe.resultType)) -// } + + case class CIL_LOAD_LOCAL_ADDRESS(local: Local) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "CIL_LOAD_LOCAL_ADDRESS "+local //+isArgument?" (argument)":""; + + override def consumed = 0 + override def produced = 1 + + override def producedTypes = List(msil_mgdptr(local.kind)) + } + + case class CIL_LOAD_FIELD_ADDRESS(field: Symbol, isStatic: Boolean) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = + "CIL_LOAD_FIELD_ADDRESS " + (if (isStatic) field.fullName else field.toString) + + override def consumed = if (isStatic) 0 else 1 + override def produced = 1 + + override def consumedTypes = if (isStatic) Nil else List(REFERENCE(field.owner)); + override def producedTypes = List(msil_mgdptr(REFERENCE(field.owner))); +} + + case class CIL_LOAD_ARRAY_ITEM_ADDRESS(kind: TypeKind) extends Instruction { + /** Returns a string representation of this instruction */ + override def toString(): String = "CIL_LOAD_ARRAY_ITEM_ADDRESS (" + kind + ")" + + override def consumed = 2 + override def produced = 1 + + override def consumedTypes = List(ARRAY(kind), INT) + override def producedTypes = List(msil_mgdptr(kind)) + } + + case class CIL_UNBOX(valueType: TypeKind) extends Instruction { + override def toString(): String = "CIL_UNBOX " + valueType + override def consumed = 1 + override def consumedTypes = ObjectReference :: Nil // actually consumes a 'boxed valueType' + override def produced = 1 + override def producedTypes = List(msil_mgdptr(valueType)) + } + + case class CIL_INITOBJ(valueType: TypeKind) extends Instruction { + override def toString(): String = "CIL_INITOBJ " + valueType + override def consumed = 1 + override def consumedTypes = ObjectReference :: Nil // actually consumes a managed pointer + override def produced = 0 + } + + case class CIL_NEWOBJ(method: Symbol) extends Instruction { + override def toString(): String = "CIL_NEWOBJ " + hostClass.fullName + method.fullName + var hostClass: Symbol = method.owner; + override def consumed = method.tpe.paramTypes.length + override def consumedTypes = method.tpe.paramTypes map toTypeKind + override def produced = 1 + override def producedTypes = List(toTypeKind(method.tpe.resultType)) + } } } diff --git a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala index 998ac90778..a485272ca6 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/TypeKinds.scala @@ -423,10 +423,11 @@ trait TypeKinds { self: ICodes => primitiveTypeMap.getOrElse(sym, newReference(sym)) private def primitiveOrClassType(sym: Symbol, targs: List[Type]) = primitiveTypeMap.getOrElse(sym, arrayOrClassType(sym, targs)) - // - // def msil_mgdptr(tk: TypeKind): TypeKind = (tk: @unchecked) match { - // case REFERENCE(cls) => REFERENCE(loaders.clrTypes.mdgptrcls4clssym(cls)) - // // TODO have ready class-symbols for the by-ref versions of built-in valuetypes - // case _ => abort("cannot obtain a managed pointer for " + tk) - // } + + def msil_mgdptr(tk: TypeKind): TypeKind = (tk: @unchecked) match { + case REFERENCE(cls) => REFERENCE(loaders.clrTypes.mdgptrcls4clssym(cls)) + // TODO have ready class-symbols for the by-ref versions of built-in valuetypes + case _ => abort("cannot obtain a managed pointer for " + tk) + } + } diff --git a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala index aba537f3bd..d2e54ff3f1 100644 --- a/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala +++ b/src/compiler/scala/tools/nsc/backend/msil/GenMSIL.scala @@ -7,16 +7,16 @@ package scala.tools.nsc package backend.msil -// import java.io.{File, IOException} -// import java.nio.{ByteBuffer, ByteOrder} -// import scala.collection.{ mutable, immutable } -// import scala.tools.nsc.symtab._ -// -// import ch.epfl.lamp.compiler.msil.{Type => MsilType, _} -// import ch.epfl.lamp.compiler.msil.emit._ -// import ch.epfl.lamp.compiler.msil.util.PECustomMod - -abstract class GenMSIL /*extends SubComponent { +import java.io.{File, IOException} +import java.nio.{ByteBuffer, ByteOrder} +import scala.collection.{ mutable, immutable } +import scala.tools.nsc.symtab._ + +import ch.epfl.lamp.compiler.msil.{Type => MsilType, _} +import ch.epfl.lamp.compiler.msil.emit._ +import ch.epfl.lamp.compiler.msil.util.PECustomMod + +abstract class GenMSIL extends SubComponent { import global._ import loaders.clrTypes import clrTypes.{types, constructors, methods, fields} @@ -1815,7 +1815,7 @@ abstract class GenMSIL /*extends SubComponent { types.get(sym).getOrElse { classes.get(sym) match { case Some(iclass) => - msilTypeBuilderFromSym(sym) + msilTypeBuilderFromSym(sym) case None => getType(sym) } @@ -1844,7 +1844,7 @@ abstract class GenMSIL /*extends SubComponent { debuglog("super type: " + parents(0).typeSymbol + ", msil type: " + superType) val interfaces: Array[MsilType] = - parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray + parents.tail.map(p => msilTypeFromSym(p.typeSymbol)).toArray if (parents.length > 1) { if (settings.debug.value) { log("interfaces:") @@ -2355,4 +2355,3 @@ abstract class GenMSIL /*extends SubComponent { } // class BytecodeGenerator } // class GenMSIL -*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/io/MsilFile.scala b/src/compiler/scala/tools/nsc/io/MsilFile.scala index aeaa1b759b..d970d0e9c9 100644 --- a/src/compiler/scala/tools/nsc/io/MsilFile.scala +++ b/src/compiler/scala/tools/nsc/io/MsilFile.scala @@ -6,14 +6,13 @@ package scala.tools.nsc package io -// import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } +import ch.epfl.lamp.compiler.msil.{ Type => MsilType, _ } /** This class wraps an MsilType. It exists only so * ClassPath can treat all of JVM/MSIL/bin/src files * uniformly, as AbstractFiles. */ -class MsilFile /* (val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { +class MsilFile(val msilType: MsilType) extends VirtualFile(msilType.FullName, msilType.Namespace) { } object NoMsilFile extends MsilFile(null) { } -*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala index 2241bb224e..942ec1fa86 100644 --- a/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala +++ b/src/compiler/scala/tools/nsc/symtab/SymbolLoaders.scala @@ -13,7 +13,7 @@ import classfile.ClassfileParser import reflect.internal.Flags._ import reflect.internal.MissingRequirementError import util.Statistics._ -import scala.tools.nsc.io.{ AbstractFile } //, MsilFile } +import scala.tools.nsc.io.{ AbstractFile, MsilFile } /** This class ... * @@ -236,16 +236,16 @@ abstract class SymbolLoaders { } override def sourcefile: Option[AbstractFile] = classfileParser.srcfile } - // - // class MsilFileLoader(msilFile: MsilFile) extends SymbolLoader { - // private def typ = msilFile.msilType - // private object typeParser extends clr.TypeParser { - // val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global - // } - // - // protected def description = "MsilFile "+ typ.FullName + ", assembly "+ typ.Assembly.FullName - // protected def doComplete(root: Symbol) { typeParser.parse(typ, root) } - // } + + class MsilFileLoader(msilFile: MsilFile) extends SymbolLoader { + private def typ = msilFile.msilType + private object typeParser extends clr.TypeParser { + val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global + } + + protected def description = "MsilFile "+ typ.FullName + ", assembly "+ typ.Assembly.FullName + protected def doComplete(root: Symbol) { typeParser.parse(typ, root) } + } class SourcefileLoader(val srcfile: AbstractFile) extends SymbolLoader { protected def description = "source file "+ srcfile.toString @@ -258,11 +258,11 @@ abstract class SymbolLoaders { protected def description = "module class loader" protected def doComplete(root: Symbol) { root.sourceModule.initialize } } - // - // object clrTypes extends clr.CLRTypes { - // val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global - // if (global.forMSIL) init() - // } + + object clrTypes extends clr.CLRTypes { + val global: SymbolLoaders.this.global.type = SymbolLoaders.this.global + if (global.forMSIL) init() + } /** used from classfile parser to avoid cyclies */ var parentsLevel = 0 diff --git a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala index 469f7ce3ab..7be0fcb146 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/CLRTypes.scala @@ -7,17 +7,17 @@ package scala.tools.nsc package symtab package clr -// import java.io.File -// import java.util.{Comparator, StringTokenizer} -// import scala.util.Sorting -// import ch.epfl.lamp.compiler.msil._ -// import scala.collection.{ mutable, immutable } -// import scala.tools.nsc.util.{Position, NoPosition} +import java.io.File +import java.util.{Comparator, StringTokenizer} +import scala.util.Sorting +import ch.epfl.lamp.compiler.msil._ +import scala.collection.{ mutable, immutable } +import scala.tools.nsc.util.{Position, NoPosition} /** * Collects all types from all reference assemblies. */ -abstract class CLRTypes /*{ +abstract class CLRTypes { val global: Global import global.Symbol @@ -135,4 +135,3 @@ abstract class CLRTypes /*{ def isDelegateType(t: Type): Boolean = { t.BaseType() == DELEGATE } } // CLRTypes -*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala index d16c9980d5..e11a5a4ad9 100644 --- a/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/clr/TypeParser.scala @@ -6,17 +6,17 @@ package scala.tools.nsc package symtab package clr -// import java.io.IOException -// import io.MsilFile -// import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _} -// import scala.collection.{ mutable, immutable } -// import scala.reflect.internal.pickling.UnPickler -// import ch.epfl.lamp.compiler.msil.Type.TMVarUsage +import java.io.IOException +import io.MsilFile +import ch.epfl.lamp.compiler.msil.{Type => MSILType, Attribute => MSILAttribute, _} +import scala.collection.{ mutable, immutable } +import scala.reflect.internal.pickling.UnPickler +import ch.epfl.lamp.compiler.msil.Type.TMVarUsage /** * @author Nikolay Mihaylov */ -abstract class TypeParser /*{ +abstract class TypeParser { val global: Global @@ -224,14 +224,14 @@ abstract class TypeParser /*{ if (canBeTakenAddressOf) { clazzBoxed.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) + else polyType(ownTypeParams, classInfoAsInMetadata) ) clazzBoxed.setFlag(flags) val rawValueInfoType = ClassInfoType(definitions.anyvalparam, instanceDefs, clazz) clazz.setInfo( if (ownTypeParams.isEmpty) rawValueInfoType - else GenPolyType(ownTypeParams, rawValueInfoType) ) + else polyType(ownTypeParams, rawValueInfoType) ) } else { clazz.setInfo( if (ownTypeParams.isEmpty) classInfoAsInMetadata - else GenPolyType(ownTypeParams, classInfoAsInMetadata) ) + else polyType(ownTypeParams, classInfoAsInMetadata) ) } // TODO I don't remember if statics.setInfo and staticModule.setInfo should also know about type params @@ -256,18 +256,18 @@ abstract class TypeParser /*{ // import nested types for (ntype <- typ.getNestedTypes() if !(ntype.IsNestedPrivate || ntype.IsNestedAssembly || ntype.IsNestedFamANDAssem) - || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) + || ntype.IsInterface /* TODO why shouldn't nested ifaces be type-parsed too? */ ) { val loader = new loaders.MsilFileLoader(new MsilFile(ntype)) - val nclazz = statics.newClass(ntype.Name.toTypeName) - val nmodule = statics.newModule(ntype.Name) - nclazz.setInfo(loader) - nmodule.setInfo(loader) - staticDefs.enter(nclazz) - staticDefs.enter(nmodule) - - assert(nclazz.companionModule == nmodule, nmodule) - assert(nmodule.companionClass == nclazz, nclazz) + val nclazz = statics.newClass(ntype.Name.toTypeName) + val nmodule = statics.newModule(ntype.Name) + nclazz.setInfo(loader) + nmodule.setInfo(loader) + staticDefs.enter(nclazz) + staticDefs.enter(nmodule) + + assert(nclazz.companionModule == nmodule, nmodule) + assert(nmodule.companionClass == nclazz, nclazz) } val fields = typ.getFields() @@ -280,9 +280,9 @@ abstract class TypeParser /*{ val name = newTermName(field.Name); val fieldType = if (field.IsLiteral && !field.FieldType.IsEnum && isDefinedAtgetConstant(getCLRType(field.FieldType))) - ConstantType(getConstant(getCLRType(field.FieldType), field.getValue)) - else - getCLRType(field.FieldType) + ConstantType(getConstant(getCLRType(field.FieldType), field.getValue)) + else + getCLRType(field.FieldType) val owner = if (field.IsStatic()) statics else clazz; val sym = owner.newValue(NoPosition, name).setFlag(flags).setInfo(fieldType); // TODO: set private within!!! -> look at typechecker/Namers.scala @@ -301,49 +301,49 @@ abstract class TypeParser /*{ for (prop <- typ.getProperties) { val propType: Type = getCLSType(prop.PropertyType); if (propType != null) { - val getter: MethodInfo = prop.GetGetMethod(true); - val setter: MethodInfo = prop.GetSetMethod(true); - var gparamsLength: Int = -1; - if (!(getter == null || getter.IsPrivate || getter.IsAssembly + val getter: MethodInfo = prop.GetGetMethod(true); + val setter: MethodInfo = prop.GetSetMethod(true); + var gparamsLength: Int = -1; + if (!(getter == null || getter.IsPrivate || getter.IsAssembly || getter.IsFamilyAndAssembly || getter.HasPtrParamOrRetType)) - { - assert(prop.PropertyType == getter.ReturnType); - val gparams: Array[ParameterInfo] = getter.GetParameters(); - gparamsLength = gparams.length; - val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; - val flags = translateAttributes(getter); - val owner: Symbol = if (getter.IsStatic) statics else clazz; - val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) + { + assert(prop.PropertyType == getter.ReturnType); + val gparams: Array[ParameterInfo] = getter.GetParameters(); + gparamsLength = gparams.length; + val name: Name = if (gparamsLength == 0) prop.Name else nme.apply; + val flags = translateAttributes(getter); + val owner: Symbol = if (getter.IsStatic) statics else clazz; + val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) val mtype: Type = if (gparamsLength == 0) NullaryMethodType(propType) // .NET properties can't be polymorphic else methodType(getter, getter.ReturnType)(methodSym) methodSym.setInfo(mtype); - methodSym.setFlag(Flags.ACCESSOR); - (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) - clrTypes.methods(methodSym) = getter; - methodsSet -= getter; - } - if (!(setter == null || setter.IsPrivate || setter.IsAssembly + methodSym.setFlag(Flags.ACCESSOR); + (if (getter.IsStatic) staticDefs else instanceDefs).enter(methodSym) + clrTypes.methods(methodSym) = getter; + methodsSet -= getter; + } + if (!(setter == null || setter.IsPrivate || setter.IsAssembly || setter.IsFamilyAndAssembly || setter.HasPtrParamOrRetType)) - { - val sparams: Array[ParameterInfo] = setter.GetParameters() - if(getter != null) - assert(getter.IsStatic == setter.IsStatic); - assert(setter.ReturnType == clrTypes.VOID); - if(getter != null) - assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter); - - val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) - else nme.update; - val flags = translateAttributes(setter); - val mtype = methodType(setter, definitions.UnitClass.tpe); - val owner: Symbol = if (setter.IsStatic) statics else clazz; - val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) + { + val sparams: Array[ParameterInfo] = setter.GetParameters() + if(getter != null) + assert(getter.IsStatic == setter.IsStatic); + assert(setter.ReturnType == clrTypes.VOID); + if(getter != null) + assert(sparams.length == gparamsLength + 1, "" + getter + "; " + setter); + + val name: Name = if (gparamsLength == 0) nme.getterToSetter(prop.Name) + else nme.update; + val flags = translateAttributes(setter); + val mtype = methodType(setter, definitions.UnitClass.tpe); + val owner: Symbol = if (setter.IsStatic) statics else clazz; + val methodSym = owner.newMethod(NoPosition, name).setFlag(flags) methodSym.setInfo(mtype(methodSym)) - methodSym.setFlag(Flags.ACCESSOR); - (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); - clrTypes.methods(methodSym) = setter; - methodsSet -= setter; - } + methodSym.setFlag(Flags.ACCESSOR); + (if (setter.IsStatic) staticDefs else instanceDefs).enter(methodSym); + clrTypes.methods(methodSym) = setter; + methodsSet -= setter; + } } } @@ -354,27 +354,27 @@ abstract class TypeParser /*{ val adder: MethodInfo = event.GetAddMethod(); val remover: MethodInfo = event.GetRemoveMethod(); if (!(adder == null || adder.IsPrivate || adder.IsAssembly - || adder.IsFamilyAndAssembly)) - { - assert(adder.ReturnType == clrTypes.VOID); - assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); - val name = encode("+="); - val flags = translateAttributes(adder); - val mtype: Type = methodType(adder, adder.ReturnType); - createMethod(name, flags, mtype, adder, adder.IsStatic) - methodsSet -= adder; - } + || adder.IsFamilyAndAssembly)) + { + assert(adder.ReturnType == clrTypes.VOID); + assert(adder.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); + val name = encode("+="); + val flags = translateAttributes(adder); + val mtype: Type = methodType(adder, adder.ReturnType); + createMethod(name, flags, mtype, adder, adder.IsStatic) + methodsSet -= adder; + } if (!(remover == null || remover.IsPrivate || remover.IsAssembly - || remover.IsFamilyAndAssembly)) - { - assert(remover.ReturnType == clrTypes.VOID); - assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); - val name = encode("-="); - val flags = translateAttributes(remover); - val mtype: Type = methodType(remover, remover.ReturnType); - createMethod(name, flags, mtype, remover, remover.IsStatic) - methodsSet -= remover; - } + || remover.IsFamilyAndAssembly)) + { + assert(remover.ReturnType == clrTypes.VOID); + assert(remover.GetParameters().map(_.ParameterType).toList == List(event.EventHandlerType)); + val name = encode("-="); + val flags = translateAttributes(remover); + val mtype: Type = methodType(remover, remover.ReturnType); + createMethod(name, flags, mtype, remover, remover.IsStatic) + methodsSet -= remover; + } } */ /* Adds view amounting to syntax sugar for a CLR implicit overload. @@ -480,7 +480,7 @@ abstract class TypeParser /*{ val mtype = methodType(method, rettype); if (mtype == null) return; /* START CLR generics (snippet 4) */ - val mInfo = if (method.IsGeneric) GenPolyType(newMethodTParams, mtype(methodSym)) + val mInfo = if (method.IsGeneric) polyType(newMethodTParams, mtype(methodSym)) else mtype(methodSym) /* END CLR generics (snippet 4) */ /* START CLR non-generics (snippet 4) @@ -805,7 +805,7 @@ abstract class TypeParser /*{ private def translateAttributes(typ: MSILType): Long = { var flags: Long = Flags.JAVA; if (typ.IsNotPublic() || typ.IsNestedPrivate() - || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()) + || typ.IsNestedAssembly() || typ.IsNestedFamANDAssem()) flags = flags | Flags.PRIVATE; else if (typ.IsNestedFamily() || typ.IsNestedFamORAssem()) flags = flags | Flags.PROTECTED; @@ -849,4 +849,3 @@ abstract class TypeParser /*{ flags } } -*/ \ No newline at end of file diff --git a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala index e46f3cbc77..6215506141 100644 --- a/src/compiler/scala/tools/nsc/util/MsilClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/MsilClassPath.scala @@ -8,20 +8,20 @@ package scala.tools.nsc package util -// import java.io.File -// import java.net.URL -// import java.util.StringTokenizer -// import scala.util.Sorting -// import scala.collection.mutable -// import scala.tools.nsc.io.{ AbstractFile, MsilFile } -// import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly } -// import ClassPath.{ ClassPathContext, isTraitImplementation } +import java.io.File +import java.net.URL +import java.util.StringTokenizer +import scala.util.Sorting +import scala.collection.mutable +import scala.tools.nsc.io.{ AbstractFile, MsilFile } +import ch.epfl.lamp.compiler.msil.{ Type => MSILType, Assembly } +import ClassPath.{ ClassPathContext, isTraitImplementation } /** Keeping the MSIL classpath code in its own file is important to make sure * we don't accidentally introduce a dependency on msil.jar in the jvm. */ -object MsilClassPath /*{ +object MsilClassPath { def collectTypes(assemFile: AbstractFile) = { var res: Array[MSILType] = MSILType.EmptyTypes val assem = Assembly.LoadFrom(assemFile.path) @@ -166,5 +166,4 @@ class AssemblyClassPath(types: Array[MSILType], namespace: String, val context: * MSILType values. */ class MsilClassPath(ext: String, user: String, source: String, context: MsilContext) -extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } -*/ \ No newline at end of file +extends MergedClassPath[MsilFile](MsilClassPath.assembleEntries(ext, user, source, context), context) { } \ No newline at end of file -- cgit v1.2.3 From 84bf74e3346a5b42199572930d303900a3675b22 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 21:18:19 -0800 Subject: Fixed all but one of the scalap tests. --- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 12 +++++------- test/files/scalap/abstractClass/result.test | 2 +- test/files/scalap/abstractMethod/result.test | 2 +- test/files/scalap/caseClass/result.test | 2 +- test/files/scalap/caseObject/result.test | 2 +- test/files/scalap/cbnParam/result.test | 2 +- test/files/scalap/classPrivate/result.test | 4 ++-- test/files/scalap/classWithExistential/result.test | 2 +- test/files/scalap/classWithSelfAnnotation/result.test | 2 +- test/files/scalap/covariantParam/result.test | 2 +- test/files/scalap/implicitParam/result.test | 2 +- test/files/scalap/packageObject/result.test | 2 +- test/files/scalap/paramClauses/result.test | 2 +- test/files/scalap/paramNames/result.test | 2 +- test/files/scalap/sequenceParam/result.test | 2 +- test/files/scalap/simpleClass/result.test | 2 +- test/files/scalap/traitObject/result.test | 4 ++-- test/files/scalap/typeAnnotations/result.test | 2 +- test/files/scalap/valAndVar/result.test | 2 +- test/files/scalap/wildcardType/result.test | 2 +- 20 files changed, 26 insertions(+), 28 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index f7401c813a..97c264fa4b 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2764,13 +2764,11 @@ self => Template(parents0, self, body) } else { - val parents = ( - if (parents0.isEmpty) List(scalaAnyRefConstr) - /*if (!isInterface(mods, body) && !isScalaArray(name)) - parents0 /* :+ scalaScalaObjectConstr*/ - else*/ - else parents0 - ) ++ caseParents() + val casePs = caseParents() + val parents = parents0 match { + case Nil if casePs.isEmpty => List(scalaAnyRefConstr) + case _ => parents0 ++ casePs + } Template(parents, self, constrMods, vparamss, argss, body, o2p(tstart)) } } diff --git a/test/files/scalap/abstractClass/result.test b/test/files/scalap/abstractClass/result.test index 9b8fc4dd95..98c5047cbc 100644 --- a/test/files/scalap/abstractClass/result.test +++ b/test/files/scalap/abstractClass/result.test @@ -1,4 +1,4 @@ -abstract class AbstractClass extends java.lang.Object with scala.ScalaObject { +abstract class AbstractClass extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo : scala.Predef.String } diff --git a/test/files/scalap/abstractMethod/result.test b/test/files/scalap/abstractMethod/result.test index a1bd378c87..062a458c13 100644 --- a/test/files/scalap/abstractMethod/result.test +++ b/test/files/scalap/abstractMethod/result.test @@ -1,4 +1,4 @@ -trait AbstractMethod extends java.lang.Object with scala.ScalaObject { +trait AbstractMethod extends java.lang.Object with scala.AnyRef { def $init$() : scala.Unit = { /* compiled code */ } def arity : scala.Int def isCool : scala.Boolean = { /* compiled code */ } diff --git a/test/files/scalap/caseClass/result.test b/test/files/scalap/caseClass/result.test index a0dbc497fe..8e3255859f 100644 --- a/test/files/scalap/caseClass/result.test +++ b/test/files/scalap/caseClass/result.test @@ -1,4 +1,4 @@ -case class CaseClass[A <: scala.Seq[scala.Int]](i : A, s : scala.Predef.String) extends java.lang.Object with scala.ScalaObject with scala.Product with scala.Serializable { +case class CaseClass[A <: scala.Seq[scala.Int]](i : A, s : scala.Predef.String) extends java.lang.Object with scala.Product with scala.Serializable { val i : A = { /* compiled code */ } val s : scala.Predef.String = { /* compiled code */ } def foo : scala.Int = { /* compiled code */ } diff --git a/test/files/scalap/caseObject/result.test b/test/files/scalap/caseObject/result.test index 55e46eccd7..9c66c6ebb1 100644 --- a/test/files/scalap/caseObject/result.test +++ b/test/files/scalap/caseObject/result.test @@ -1,4 +1,4 @@ -case object CaseObject extends java.lang.Object with scala.ScalaObject with scala.Product with scala.Serializable { +case object CaseObject extends java.lang.Object with scala.Product with scala.Serializable { def bar : scala.Int = { /* compiled code */ } override def productPrefix : java.lang.String = { /* compiled code */ } def productArity : scala.Int = { /* compiled code */ } diff --git a/test/files/scalap/cbnParam/result.test b/test/files/scalap/cbnParam/result.test index c6b2f4caa8..d00a13d2d7 100644 --- a/test/files/scalap/cbnParam/result.test +++ b/test/files/scalap/cbnParam/result.test @@ -1,3 +1,3 @@ -class CbnParam extends java.lang.Object with scala.ScalaObject { +class CbnParam extends java.lang.Object with scala.AnyRef { def this(s : => scala.Predef.String) = { /* compiled code */ } } diff --git a/test/files/scalap/classPrivate/result.test b/test/files/scalap/classPrivate/result.test index 0d12b779c3..1846b7f0ea 100644 --- a/test/files/scalap/classPrivate/result.test +++ b/test/files/scalap/classPrivate/result.test @@ -1,7 +1,7 @@ -class ClassPrivate extends java.lang.Object with scala.ScalaObject { +class ClassPrivate extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def baz : scala.Int = { /* compiled code */ } - class Outer extends java.lang.Object with scala.ScalaObject { + class Outer extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } private[ClassPrivate] def qux : scala.Int = { /* compiled code */ } } diff --git a/test/files/scalap/classWithExistential/result.test b/test/files/scalap/classWithExistential/result.test index 91afddaf0e..078b93ad89 100644 --- a/test/files/scalap/classWithExistential/result.test +++ b/test/files/scalap/classWithExistential/result.test @@ -1,4 +1,4 @@ -class ClassWithExistential extends java.lang.Object with scala.ScalaObject { +class ClassWithExistential extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo[A, B] : scala.Function1[A, B forSome {type A <: scala.Seq[scala.Int]; type B >: scala.Predef.String}] = { /* compiled code */ } } \ No newline at end of file diff --git a/test/files/scalap/classWithSelfAnnotation/result.test b/test/files/scalap/classWithSelfAnnotation/result.test index 326437c7be..37b2bae5e0 100644 --- a/test/files/scalap/classWithSelfAnnotation/result.test +++ b/test/files/scalap/classWithSelfAnnotation/result.test @@ -1,4 +1,4 @@ -class ClassWithSelfAnnotation extends java.lang.Object with scala.ScalaObject { +class ClassWithSelfAnnotation extends java.lang.Object with scala.AnyRef { this : ClassWithSelfAnnotation with java.lang.CharSequence => def this() = { /* compiled code */ } def foo : scala.Int = { /* compiled code */ } diff --git a/test/files/scalap/covariantParam/result.test b/test/files/scalap/covariantParam/result.test index 8acd9b497a..9e4dbb802d 100644 --- a/test/files/scalap/covariantParam/result.test +++ b/test/files/scalap/covariantParam/result.test @@ -1,4 +1,4 @@ -class CovariantParam[+A] extends java.lang.Object with scala.ScalaObject { +class CovariantParam[+A] extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo[A](a : A) : scala.Int = { /* compiled code */ } } diff --git a/test/files/scalap/implicitParam/result.test b/test/files/scalap/implicitParam/result.test index 11d678df06..05be2f9ae1 100644 --- a/test/files/scalap/implicitParam/result.test +++ b/test/files/scalap/implicitParam/result.test @@ -1,4 +1,4 @@ -class ImplicitParam extends java.lang.Object with scala.ScalaObject { +class ImplicitParam extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo(i : scala.Int)(implicit f : scala.Float, d : scala.Double) : scala.Int = { /* compiled code */ } } diff --git a/test/files/scalap/packageObject/result.test b/test/files/scalap/packageObject/result.test index 6a8d6ae1d5..94c6a01b08 100644 --- a/test/files/scalap/packageObject/result.test +++ b/test/files/scalap/packageObject/result.test @@ -1,4 +1,4 @@ -package object PackageObject extends java.lang.Object with scala.ScalaObject { +package object PackageObject extends java.lang.Object { def this() = { /* compiled code */ } type A = scala.Predef.String def foo(i : scala.Int) : scala.Int = { /* compiled code */ } diff --git a/test/files/scalap/paramClauses/result.test b/test/files/scalap/paramClauses/result.test index 9ef93d2e76..ff7c879933 100644 --- a/test/files/scalap/paramClauses/result.test +++ b/test/files/scalap/paramClauses/result.test @@ -1,4 +1,4 @@ -class ParamClauses extends java.lang.Object with scala.ScalaObject { +class ParamClauses extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo(i : scala.Int)(s : scala.Predef.String)(t : scala.Double) : scala.Int = { /* compiled code */ } } diff --git a/test/files/scalap/paramNames/result.test b/test/files/scalap/paramNames/result.test index f9d98d9647..a18c6350e3 100644 --- a/test/files/scalap/paramNames/result.test +++ b/test/files/scalap/paramNames/result.test @@ -1,4 +1,4 @@ -class ParamNames extends java.lang.Object with scala.ScalaObject { +class ParamNames extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo(s : => scala.Seq[scala.Int], s2 : => scala.Seq[scala.Any]) : scala.Unit = { /* compiled code */ } } diff --git a/test/files/scalap/sequenceParam/result.test b/test/files/scalap/sequenceParam/result.test index 4b9d7844ab..ca004ab0bf 100644 --- a/test/files/scalap/sequenceParam/result.test +++ b/test/files/scalap/sequenceParam/result.test @@ -1,3 +1,3 @@ -class SequenceParam extends java.lang.Object with scala.ScalaObject { +class SequenceParam extends java.lang.Object with scala.AnyRef { def this(s : scala.Predef.String, i : scala.Int*) = { /* compiled code */ } } diff --git a/test/files/scalap/simpleClass/result.test b/test/files/scalap/simpleClass/result.test index d10b633bce..f350720895 100644 --- a/test/files/scalap/simpleClass/result.test +++ b/test/files/scalap/simpleClass/result.test @@ -1,4 +1,4 @@ -class SimpleClass extends java.lang.Object with scala.ScalaObject { +class SimpleClass extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } def foo : scala.Int = { /* compiled code */ } } diff --git a/test/files/scalap/traitObject/result.test b/test/files/scalap/traitObject/result.test index 0d7de1535d..e9a72316e9 100644 --- a/test/files/scalap/traitObject/result.test +++ b/test/files/scalap/traitObject/result.test @@ -1,8 +1,8 @@ -trait TraitObject extends java.lang.Object with scala.ScalaObject { +trait TraitObject extends java.lang.Object with scala.AnyRef { def $init$() : scala.Unit = { /* compiled code */ } def foo : scala.Int = { /* compiled code */ } } -object TraitObject extends java.lang.Object with scala.ScalaObject { +object TraitObject extends java.lang.Object { def this() = { /* compiled code */ } def bar : scala.Int = { /* compiled code */ } } diff --git a/test/files/scalap/typeAnnotations/result.test b/test/files/scalap/typeAnnotations/result.test index b565d6185b..fe48e081d3 100644 --- a/test/files/scalap/typeAnnotations/result.test +++ b/test/files/scalap/typeAnnotations/result.test @@ -1,4 +1,4 @@ -abstract class TypeAnnotations[@scala.specialized R] extends java.lang.Object with scala.ScalaObject { +abstract class TypeAnnotations[@scala.specialized R] extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } @scala.specialized val x : scala.Int = { /* compiled code */ } diff --git a/test/files/scalap/valAndVar/result.test b/test/files/scalap/valAndVar/result.test index 934ad0a086..287dfa6163 100644 --- a/test/files/scalap/valAndVar/result.test +++ b/test/files/scalap/valAndVar/result.test @@ -1,4 +1,4 @@ -class ValAndVar extends java.lang.Object with scala.ScalaObject { +class ValAndVar extends java.lang.Object with scala.AnyRef { def this() = { /* compiled code */ } val foo : java.lang.String = { /* compiled code */ } var bar : scala.Int = { /* compiled code */ } diff --git a/test/files/scalap/wildcardType/result.test b/test/files/scalap/wildcardType/result.test index aa3d5d53bc..ceb7c9ba7f 100644 --- a/test/files/scalap/wildcardType/result.test +++ b/test/files/scalap/wildcardType/result.test @@ -1,3 +1,3 @@ -class WildcardType extends java.lang.Object with scala.ScalaObject { +class WildcardType extends java.lang.Object with scala.AnyRef { def this(f : scala.Function1[scala.Int, _]) = { /* compiled code */ } } -- cgit v1.2.3 From 90039fcf18c28a0f89271e6b1fbb6dfd36e1d4ba Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 21:47:05 -0800 Subject: Fixing AnyVal verify error and reflection. Have to give AnyVal a constructor and simultaneously pacify both the typer (which knows Any has no constructor) and the jvm (which mandates a constructor must call its superconstructor.) It's the usual angle of adding a not-quite-right tree during parsing and then finishing it later (in this case, in AddInterfaces.) --- src/compiler/scala/tools/nsc/transform/AddInterfaces.scala | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 8fe82258e2..971a0c9aab 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -308,8 +308,13 @@ abstract class AddInterfaces extends InfoTransform { case (presuper, supercall :: rest) => stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) - case (Nil, Nil) => // AnyVal constructor - Literal(Constant()) + case (Nil, Nil) => + // AnyVal constructor - have to provide a real body so the + // jvm doesn't throw a VerifyError. But we can't add the + // body until now, because the typer knows that Any has no + // constructor and won't accept a call to super.init. + val superCall = Apply(Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR), Nil) + Block(List(superCall), Literal(Constant())) } } } -- cgit v1.2.3 From b265d014416f1c4c6b22d47b4be16b22499dc05f Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 22:06:01 -0800 Subject: Tweaking parent printing a little further. Not too many Object/AnyRef parents, not too few. --- src/compiler/scala/reflect/internal/Definitions.scala | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala index a06f2d07bf..2ca9c8bfd0 100644 --- a/src/compiler/scala/reflect/internal/Definitions.scala +++ b/src/compiler/scala/reflect/internal/Definitions.scala @@ -716,7 +716,16 @@ trait Definitions extends reflect.api.StandardDefinitions { /** Remove references to class Object (other than the head) in a list of parents */ def removeLaterObjects(tps: List[Type]): List[Type] = tps match { case Nil => Nil - case x :: xs => x :: xs.filter(_.typeSymbol != ObjectClass) + case x :: xs => x :: xs.filterNot(_.typeSymbol == ObjectClass) + } + /** Remove all but one reference to class Object from a list of parents. */ + def removeRedundantObjects(tps: List[Type]): List[Type] = tps match { + case Nil => Nil + case x :: xs => + if (x.typeSymbol == ObjectClass) + x :: xs.filterNot(_.typeSymbol == ObjectClass) + else + x :: removeRedundantObjects(xs) } /** Order a list of types with non-trait classes before others. */ def classesFirst(tps: List[Type]): List[Type] = { @@ -725,15 +734,15 @@ trait Definitions extends reflect.api.StandardDefinitions { else classes ::: others } /** The following transformations applied to a list of parents. - * If any parent is a class/trait, all parents which are Object - * or an alias of it are discarded. Otherwise, all Objects other - * the head of the list are discarded. + * If any parent is a class/trait, all parents which normalize to + * Object are discarded. Otherwise, all parents which normalize + * to Object except the first one found are discarded. */ def normalizedParents(parents: List[Type]): List[Type] = { if (parents exists (t => (t.typeSymbol ne ObjectClass) && t.typeSymbol.isClass)) parents filterNot (_.typeSymbol eq ObjectClass) else - removeLaterObjects(parents) + removeRedundantObjects(parents) } def parentsString(parents: List[Type]) = normalizedParents(parents) mkString " with " -- cgit v1.2.3 From 1af71c9191d6b8d73a21e5a4bd86a7e8c2511810 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 22:15:04 -0800 Subject: Hardened/documented AnyVal constructor switcheroo. --- src/compiler/scala/tools/nsc/ast/parser/Parsers.scala | 2 ++ src/compiler/scala/tools/nsc/transform/AddInterfaces.scala | 1 + 2 files changed, 3 insertions(+) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 97c264fa4b..c2b4dc32b6 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -2754,6 +2754,8 @@ self => val tstart0 = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart atPos(tstart0) { if (inScalaPackage && name == tpnme.AnyVal) { + // Not a well-formed constructor, has to be finished later - see note + // regarding AnyVal constructor in AddInterfaces. val constructor = DefDef(NoMods, nme.CONSTRUCTOR, Nil, List(Nil), TypeTree(), Block(Nil, Literal(Constant()))) Template(parents0, self, constructor :: body) } diff --git a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala index 971a0c9aab..e7759f1d7e 100644 --- a/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala +++ b/src/compiler/scala/tools/nsc/transform/AddInterfaces.scala @@ -309,6 +309,7 @@ abstract class AddInterfaces extends InfoTransform { stats span (t => t.hasSymbolWhich(_ hasFlag PRESUPER)) treeCopy.Block(tree, presuper ::: (supercall :: mixinConstructorCalls ::: rest), expr) case (Nil, Nil) => + assert(clazz eq AnyValClass, clazz) // AnyVal constructor - have to provide a real body so the // jvm doesn't throw a VerifyError. But we can't add the // body until now, because the typer knows that Any has no -- cgit v1.2.3 From fe901382384ded9b75ab5dbd981dde9255856715 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 22:18:17 -0800 Subject: A little msil I missed un-reverting. --- src/compiler/scala/tools/nsc/Global.scala | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 31269829bf..8e5ca2156a 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -27,8 +27,7 @@ import typechecker._ import transform._ import backend.icode.{ ICodes, GenICode, ICodeCheckers } -// import backend.{ ScalaPrimitives, Platform, MSILPlatform, JavaPlatform } -import backend.{ ScalaPrimitives, Platform, JavaPlatform } +import backend.{ ScalaPrimitives, Platform, MSILPlatform, JavaPlatform } import backend.jvm.GenJVM import backend.opt.{ Inliners, InlineExceptionHandlers, ClosureElimination, DeadCodeElimination } import backend.icode.analysis._ @@ -66,9 +65,9 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb type ThisPlatform = Platform { val global: Global.this.type } - lazy val platform: ThisPlatform = new { val global: Global.this.type = Global.this } with JavaPlatform - // if (forMSIL) new { val global: Global.this.type = Global.this } with MSILPlatform - // else new { val global: Global.this.type = Global.this } with JavaPlatform + lazy val platform: ThisPlatform = + if (forMSIL) new { val global: Global.this.type = Global.this } with MSILPlatform + else new { val global: Global.this.type = Global.this } with JavaPlatform def classPath: ClassPath[platform.BinaryRepr] = platform.classPath def rootLoader: LazyType = platform.rootLoader -- cgit v1.2.3 From 65ae85738cb2d14bb5e586417ccef352c3a268ac Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 22:19:53 -0800 Subject: Hardening in Constructors. --- src/compiler/scala/tools/nsc/transform/Constructors.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/transform/Constructors.scala b/src/compiler/scala/tools/nsc/transform/Constructors.scala index a672059211..b60b411f47 100644 --- a/src/compiler/scala/tools/nsc/transform/Constructors.scala +++ b/src/compiler/scala/tools/nsc/transform/Constructors.scala @@ -48,8 +48,8 @@ abstract class Constructors extends Transform with ast.TreeDSL { case Some(ddef @ DefDef(_, _, _, List(vparams), _, rhs @ Block(_, _))) => ConstrInfo(ddef, vparams map (_.symbol), rhs) case x => - // assert(false, "no constructor in template: impl = " + impl) - // AnyVal constructor + // AnyVal constructor is OK + assert(clazz eq AnyValClass, "no constructor in template: impl = " + impl) return impl } } -- cgit v1.2.3 From b5eab2f3640f458d40f3e3cb87055e871af70947 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Sat, 4 Feb 2012 22:36:14 -0800 Subject: Made a typer hack less hacky. --- src/compiler/scala/tools/nsc/typechecker/Typers.scala | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index ba3172dd06..66330d4321 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -1610,8 +1610,6 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { * @param rhs ... */ def computeParamAliases(clazz: Symbol, vparamss: List[List[ValDef]], rhs: Tree) { - if (clazz eq AnyValClass) - return debuglog("computing param aliases for "+clazz+":"+clazz.primaryConstructor.tpe+":"+rhs)//debug def decompose(call: Tree): (Tree, List[Tree]) = call match { case Apply(fn, args) => @@ -1791,8 +1789,12 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { transformedOrTyped(ddef.rhs, EXPRmode, tpt1.tpe) } - if (meth.isPrimaryConstructor && meth.isClassConstructor && !isPastTyper && !reporter.hasErrors) - computeParamAliases(meth.owner, vparamss1, rhs1) + if (meth.isPrimaryConstructor && meth.isClassConstructor && !isPastTyper && !reporter.hasErrors) { + // At this point in AnyVal there is no supercall, which will blow up + // in computeParamAliases; there's nothing to be computed for Anyval anyway. + if (meth.owner ne AnyValClass) + computeParamAliases(meth.owner, vparamss1, rhs1) + } if (tpt1.tpe.typeSymbol != NothingClass && !context.returnsSeen && rhs1.tpe.typeSymbol != NothingClass) rhs1 = checkDead(rhs1) -- cgit v1.2.3 From 55990c9ec619cf212a31db4f818dedb5d3150157 Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 14 Mar 2012 10:25:59 -0700 Subject: New starr to support new fundamental laws of reality. And grueling recovery from branch drift. Merges a portion (and only a portion) of topic/inline into master. The major changes which come with this merge are: AnyVal is unsealed, can be extended directly. ScalaObject is no longer with us. --- lib/scala-compiler.jar.desired.sha1 | 2 +- lib/scala-library-src.jar.desired.sha1 | 2 +- lib/scala-library.jar.desired.sha1 | 2 +- .../scala/tools/nsc/transform/LiftCode.scala | 571 --------------------- .../scala/tools/nsc/typechecker/RefChecks.scala | 2 +- test/files/codelib/code.jar.desired.sha1 | 2 +- test/files/neg/anyval-children-2.check | 2 +- test/files/neg/t5529.check | 4 +- test/files/presentation/callcc-interpreter.check | 4 +- test/files/run/existentials3.check | 44 +- test/files/run/programmatic-main.check | 37 +- test/files/run/reify_ann1a.check | 4 +- test/files/run/reify_ann1b.check | 4 +- test/files/run/reify_classfileann_a.check | 4 +- test/files/run/t1195.check | 12 +- test/files/run/t5224.check | 2 +- test/files/run/t5271_1.check | 2 +- test/files/run/t5271_2.check | 2 +- test/files/run/t5271_3.check | 4 +- test/files/run/t5527.check | 14 +- test/files/specialized/SI-5005.check | 4 +- 21 files changed, 75 insertions(+), 649 deletions(-) delete mode 100644 src/compiler/scala/tools/nsc/transform/LiftCode.scala (limited to 'src/compiler') diff --git a/lib/scala-compiler.jar.desired.sha1 b/lib/scala-compiler.jar.desired.sha1 index 79f6de5e27..d8c99fd8a7 100644 --- a/lib/scala-compiler.jar.desired.sha1 +++ b/lib/scala-compiler.jar.desired.sha1 @@ -1 +1 @@ -40f87533e0d03ad04ca632119286d347ee54d8ae ?scala-compiler.jar +c6fc8984eeabb722aca2d99e7afebdb96e834995 ?scala-compiler.jar diff --git a/lib/scala-library-src.jar.desired.sha1 b/lib/scala-library-src.jar.desired.sha1 index cfb865f1e8..1acb36ecd9 100644 --- a/lib/scala-library-src.jar.desired.sha1 +++ b/lib/scala-library-src.jar.desired.sha1 @@ -1 +1 @@ -4a34794dd9a45cd2e8603de559f565535e7aa74b ?scala-library-src.jar +8aca5d1d5890965ea4c8ece61a6018484566a95b ?scala-library-src.jar diff --git a/lib/scala-library.jar.desired.sha1 b/lib/scala-library.jar.desired.sha1 index 28a2c586a0..00fc8b0018 100644 --- a/lib/scala-library.jar.desired.sha1 +++ b/lib/scala-library.jar.desired.sha1 @@ -1 +1 @@ -3516dc2e17bf72b1e4bc665e59f6b7ec51cba48d ?scala-library.jar +3348de294ffc98750730e835e06a84dd4e1133fc ?scala-library.jar diff --git a/src/compiler/scala/tools/nsc/transform/LiftCode.scala b/src/compiler/scala/tools/nsc/transform/LiftCode.scala deleted file mode 100644 index 8affea56a2..0000000000 --- a/src/compiler/scala/tools/nsc/transform/LiftCode.scala +++ /dev/null @@ -1,571 +0,0 @@ -/* NSC -- new Scala compiler - * Copyright 2005-2011 LAMP/EPFL - * @author Gilles Dubochet - * @author Martin Odersky - */ - -package scala.tools.nsc -package transform - -import symtab._ -import Flags._ -import scala.collection.{ mutable, immutable } -import scala.collection.mutable.ListBuffer -import scala.tools.nsc.util.FreshNameCreator -import scala.runtime.ScalaRunTime.{ isAnyVal, isTuple } - -/** - * Translate expressions of the form reflect.Code.lift(exp) - * to the reified "reflect trees" representation of exp. - * Also: mutable variables that are accessed from a local function are wrapped in refs. - * - * @author Martin Odersky - * @version 2.10 - */ -abstract class LiftCode extends Transform with TypingTransformers { - - import global._ // the global environment - import definitions._ // standard classes and methods - import typer.{ typed, atOwner } // methods to type trees - - val symbols: global.type = global - - /** the following two members override abstract members in Transform */ - val phaseName: String = "liftcode" - - def newTransformer(unit: CompilationUnit): Transformer = - new Codifier(unit) - - private lazy val MirrorMemberNames = - ReflectRuntimeMirror.info.nonPrivateMembers filter (_.isTerm) map (_.toString) toSet - - // Would be nice if we could use something like this to check the names, - // but it seems that info is unavailable when I need it. - private def mirrorFactoryName(value: Any): Option[String] = value match { - // Modest (inadequate) sanity check that there's a member by this name. - case x: Product if MirrorMemberNames(x.productPrefix) => - Some(x.productPrefix) - case _ => - Some(value.getClass.getName split """[$.]""" last) filter MirrorMemberNames - } - private def isMirrorMemberObject(value: Product) = value match { - case NoType | NoPrefix | NoPosition | EmptyTree => true - case _ => false - } - - class Codifier(unit: CompilationUnit) extends TypingTransformer(unit) { - - val reifyDebug = settings.Yreifydebug.value - val reifyTyperDebug = settings.Yreifytyperdebug.value - val debugTrace = util.trace when reifyDebug - - val reifyCopypaste = settings.Yreifycopypaste.value - def printCopypaste(tree: Tree) { - if (reifyDebug) println("=======================") - printCopypaste1(tree) - if (reifyDebug) println("=======================") - } - def printCopypaste1(tree: Tree) { - import scala.reflect.api.Modifier - import scala.reflect.api.Modifier._ - - def copypasteModifier(mod: Modifier.Value): String = mod match { - case mod @ ( - `protected` | `private` | `override` | - `abstract` | `final` | `sealed` | - `implicit` | `lazy` | `macro` | - `case` | `trait`) => "`" + mod.toString + "`" - case mod => mod.toString - } - - // I fervently hope this is a test case or something, not anything being - // depended upon. Of more fragile code I cannot conceive. - for (line <- (tree.toString.split(Properties.lineSeparator) drop 2 dropRight 1)) { - var s = line.trim - s = s.replace("$mr.", "") - s = s.replace(".apply", "") - s = s.replace("scala.collection.immutable.", "") - s = "List\\[List\\[.*?\\].*?\\]".r.replaceAllIn(s, "List") - s = "List\\[.*?\\]".r.replaceAllIn(s, "List") - s = s.replace("immutable.this.Nil", "List()") - s = s.replace("modifiersFromInternalFlags", "Modifiers") - s = s.replace("Modifiers(0L, newTypeName(\"\"), List())", "Modifiers()") - s = """Modifiers\((\d+)[lL], newTypeName\("(.*?)"\), List\((.*?)\)\)""".r.replaceAllIn(s, m => { - val buf = new StringBuilder - - val flags = m.group(1).toLong - val s_flags = Flags.modifiersOfFlags(flags) map copypasteModifier mkString ", " - if (s_flags != "") - buf.append("Set(" + s_flags + ")") - - val privateWithin = "" + m.group(2) - if (privateWithin != "") - buf.append(", newTypeName(\"" + privateWithin + "\")") - - val annotations = m.group(3) - if (annotations.nonEmpty) - buf.append(", List(" + annotations + ")") - - "Modifiers(" + buf.toString + ")" - }) - s = """setInternalFlags\((\d+)L\)""".r.replaceAllIn(s, m => { - val flags = m.group(1).toLong - val mods = Flags.modifiersOfFlags(flags) map copypasteModifier - "setInternalFlags(flagsOfModifiers(List(" + mods.mkString(", ") + ")))" - }) - - println(s) - } - } - - override def transformUnit(unit: CompilationUnit) { - atPhase(phase.next) { - super.transformUnit(unit) - } - } - - override def transform(tree: Tree): Tree = { - val sym = tree.symbol - tree match { - case Apply(_, List(tree)) if sym == Code_lift => // reify Code.lift[T](expr) instances - val saved = printTypings - try { - debugTrace("transforming = ")(if (settings.Xshowtrees.value) "\n" + nodePrinters.nodeToString(tree).trim else tree.toString) - debugTrace("transformed = ") { - val untyped = codify(super.transform(tree)) - if (reifyCopypaste) printCopypaste(untyped) - - printTypings = reifyTyperDebug - val typed = localTyper.typedPos(tree.pos)(untyped) - typed - } - } catch { - case ex: ReifierError => - unit.error(ex.pos, ex.msg) - tree - } finally { - printTypings = saved - } - case _ => - super.transform(tree) - } - } - - def codify(tree: Tree): Tree = debugTrace("codified " + tree + " -> ") { - val targetType = definitions.CodeClass.primaryConstructor.info.paramTypes.head - val reifier = new Reifier() - val arg = gen.mkAsInstanceOf(reifier.reifyTopLevel(tree), targetType, wrapInApply = false) - val treetpe = // this really should use packedType(tree.tpe, context.owner) - // where packedType is defined in Typers. But we can do that only if liftCode is moved to Typers. - if (tree.tpe.typeSymbol.isAnonymousClass) tree.tpe.typeSymbol.classBound - else tree.tpe - New(TypeTree(appliedType(definitions.CodeClass.typeConstructor, List(treetpe.widen))), - List(List(arg))) - } - } - - /** - * Given a tree or type, generate a tree that when executed at runtime produces the original tree or type. - * For instance: Given - * - * var x = 1; Code(x + 1) - * - * The `x + 1` expression is reified to - * - * $mr.Apply($mr.Select($mr.Ident($mr.freeVar("x". , x), "+"), List($mr.Literal($mr.Constant(1)))))) - * - * Or, the term name 'abc' is reified to: - * - * $mr.Apply($mr.Select($mr.Ident("newTermName")), List(Literal(Constant("abc"))))) - * - * todo: Treat embedded Code blocks by merging them into containing block - * - */ - class Reifier() { - - final val scalaPrefix = "scala." - final val localPrefix = "$local" - final val memoizerName = "$memo" - - val reifyDebug = settings.Yreifydebug.value - - private val reifiableSyms = mutable.ArrayBuffer[Symbol]() // the symbols that are reified with the tree - private val symIndex = mutable.HashMap[Symbol, Int]() // the index of a reifiable symbol in `reifiableSyms` - private var boundSyms = Set[Symbol]() // set of all symbols that are bound in tree to be reified - - /** - * Generate tree of the form - * - * { val $mr = scala.reflect.runtime.Mirror - * $local1 = new TypeSymbol(owner1, NoPosition, name1) - * ... - * $localN = new TermSymbol(ownerN, NoPositiion, nameN) - * $local1.setInfo(tpe1) - * ... - * $localN.setInfo(tpeN) - * $localN.setAnnotations(annotsN) - * rtree - * } - * - * where - * - * - `$localI` are free type symbols in the environment, as well as local symbols - * of refinement types. - * - `tpeI` are the info's of `symI` - * - `rtree` is code that generates `data` at runtime, maintaining all attributes. - * - `data` is typically a tree or a type. - */ - def reifyTopLevel(data: Any): Tree = { - val rtree = reify(data) - Block(mirrorAlias :: reifySymbolTableSetup, rtree) - } - - private def isLocatable(sym: Symbol) = - sym.isPackageClass || sym.owner.isClass || sym.isTypeParameter && sym.paramPos >= 0 - - private def registerReifiableSymbol(sym: Symbol): Unit = - if (!(symIndex contains sym)) { - sym.owner.ownersIterator find (x => !isLocatable(x)) foreach registerReifiableSymbol - symIndex(sym) = reifiableSyms.length - reifiableSyms += sym - } - - // helper methods - - private def localName(sym: Symbol): TermName = - newTermName(localPrefix + symIndex(sym)) - - private def call(fname: String, args: Tree*): Tree = - Apply(termPath(fname), args.toList) - - private def mirrorSelect(name: String): Tree = - termPath(nme.MIRROR_PREFIX + name) - - private def mirrorCall(name: TermName, args: Tree*): Tree = - call("" + (nme.MIRROR_PREFIX append name), args: _*) - - private def mirrorCall(name: String, args: Tree*): Tree = - call(nme.MIRROR_PREFIX + name, args: _*) - - private def mirrorFactoryCall(value: Product, args: Tree*): Tree = - mirrorCall(value.productPrefix, args: _*) - - private def scalaFactoryCall(name: String, args: Tree*): Tree = - call(scalaPrefix + name + ".apply", args: _*) - - private def mkList(args: List[Tree]): Tree = - scalaFactoryCall("collection.immutable.List", args: _*) - - private def reifyModifiers(m: Modifiers) = - mirrorCall("modifiersFromInternalFlags", reify(m.flags), reify(m.privateWithin), reify(m.annotations)) - - private def reifyAggregate(name: String, args: Any*) = - scalaFactoryCall(name, (args map reify).toList: _*) - - /** - * Reify a list - */ - private def reifyList(xs: List[Any]): Tree = - mkList(xs map reify) - - /** Reify a name */ - private def reifyName(name: Name) = - mirrorCall(if (name.isTypeName) "newTypeName" else "newTermName", Literal(Constant(name.toString))) - - private def isFree(sym: Symbol) = - !(symIndex contains sym) - - /** - * Reify a reference to a symbol - */ - private def reifySymRef(sym: Symbol): Tree = { - symIndex get sym match { - case Some(idx) => - Ident(localName(sym)) - case None => - if (sym == NoSymbol) - mirrorSelect("NoSymbol") - else if (sym == RootPackage) - mirrorSelect("definitions.RootPackage") - else if (sym == RootClass) - mirrorSelect("definitions.RootClass") - else if (sym == EmptyPackage) - mirrorSelect("definitions.EmptyPackage") - else if (sym == EmptyPackageClass) - mirrorSelect("definitions.EmptyPackageClass") - else if (sym.isModuleClass) - Select(reifySymRef(sym.sourceModule), "moduleClass") - else if (sym.isStatic && sym.isClass) - mirrorCall("staticClass", reify(sym.fullName)) - else if (sym.isStatic && sym.isModule) - mirrorCall("staticModule", reify(sym.fullName)) - else if (isLocatable(sym)) - if (sym.isTypeParameter) - mirrorCall("selectParam", reify(sym.owner), reify(sym.paramPos)) - else { - if (reifyDebug) println("locatable: " + sym + " " + sym.isPackageClass + " " + sym.owner + " " + sym.isTypeParameter) - val rowner = reify(sym.owner) - val rname = reify(sym.name.toString) - if (sym.isType) - mirrorCall("selectType", rowner, rname) - else if (sym.isMethod && sym.owner.isClass && sym.owner.info.decl(sym.name).isOverloaded) { - val index = sym.owner.info.decl(sym.name).alternatives indexOf sym - assert(index >= 0, sym) - mirrorCall("selectOverloadedMethod", rowner, rname, reify(index)) - } else - mirrorCall("selectTerm", rowner, rname) - } - else { - if (sym.isTerm) { - if (reifyDebug) println("Free: " + sym) - val symtpe = lambdaLift.boxIfCaptured(sym, sym.tpe, erasedTypes = false) - def markIfCaptured(arg: Ident): Tree = - if (sym.isCapturedVariable) referenceCapturedVariable(arg) else arg - mirrorCall("freeVar", reify(sym.name.toString), reify(symtpe), markIfCaptured(Ident(sym))) - } else { - if (reifyDebug) println("Late local: " + sym) - registerReifiableSymbol(sym) - reifySymRef(sym) - } - } - } - } - - /** - * reify the creation of a symbol - */ - private def reifySymbolDef(sym: Symbol): Tree = { - if (reifyDebug) println("reify sym def " + sym) - - ValDef(NoMods, localName(sym), TypeTree(), - Apply( - Select(reify(sym.owner), "newNestedSymbol"), - List(reify(sym.name), reify(sym.pos), Literal(Constant(sym.flags))) - ) - ) - } - - /** - * Generate code to add type and annotation info to a reified symbol - */ - private def fillInSymbol(sym: Symbol): Tree = { - val rset = Apply(Select(reifySymRef(sym), nme.setTypeSig), List(reifyType(sym.info))) - if (sym.annotations.isEmpty) rset - else Apply(Select(rset, nme.setAnnotations), List(reify(sym.annotations))) - } - - /** Reify a scope */ - private def reifyScope(scope: Scope): Tree = { - scope foreach registerReifiableSymbol - mirrorCall(nme.newScopeWith, scope.toList map reifySymRef: _*) - } - - /** Reify a list of symbols that need to be created */ - private def reifySymbols(syms: List[Symbol]): Tree = { - syms foreach registerReifiableSymbol - mkList(syms map reifySymRef) - } - - /** Reify a type that defines some symbols */ - private def reifyTypeBinder(value: Product, bound: List[Symbol], underlying: Type): Tree = - mirrorFactoryCall(value, reifySymbols(bound), reify(underlying)) - - /** Reify a type */ - private def reifyType(tpe0: Type): Tree = { - val tpe = tpe0.normalize - val tsym = tpe.typeSymbol - if (tsym.isClass && tpe == tsym.typeConstructor && tsym.isStatic) - Select(reifySymRef(tpe.typeSymbol), nme.asTypeConstructor) - else tpe match { - case t @ NoType => - reifyMirrorObject(t) - case t @ NoPrefix => - reifyMirrorObject(t) - case tpe @ ThisType(clazz) if clazz.isModuleClass && clazz.isStatic => - mirrorCall(nme.thisModuleType, reify(clazz.fullName)) - case t @ RefinedType(parents, decls) => - registerReifiableSymbol(tpe.typeSymbol) - mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) - case t @ ClassInfoType(parents, decls, clazz) => - registerReifiableSymbol(clazz) - mirrorFactoryCall(t, reify(parents), reify(decls), reify(t.typeSymbol)) - case t @ ExistentialType(tparams, underlying) => - reifyTypeBinder(t, tparams, underlying) - case t @ PolyType(tparams, underlying) => - reifyTypeBinder(t, tparams, underlying) - case t @ MethodType(params, restpe) => - reifyTypeBinder(t, params, restpe) - case _ => - reifyProductUnsafe(tpe) - } - } - - private def definedInLiftedCode(tpe: Type) = - tpe exists (tp => boundSyms contains tp.typeSymbol) - - private def isErased(tree: Tree) = tree match { - case tt: TypeTree => definedInLiftedCode(tt.tpe) && tt.original == null - case _ => false - } - - /** Reify a tree */ - private def reifyTree(tree: Tree): Tree = tree match { - case EmptyTree => - reifyMirrorObject(EmptyTree) - case This(_) if !(boundSyms contains tree.symbol) => - reifyFree(tree) - case Ident(_) if !(boundSyms contains tree.symbol) => - if (tree.symbol.isVariable && tree.symbol.owner.isTerm) { - captureVariable(tree.symbol) // Note order dependency: captureVariable needs to come before reifyTree here. - mirrorCall("Select", reifyFree(tree), reifyName(nme.elem)) - } else reifyFree(tree) - case tt: TypeTree if (tt.tpe != null) => - if (definedInLiftedCode(tt.tpe)) { - // erase non-essential (i.e. inferred) types - // reify symless counterparts of essential types - if (tt.original != null) reify(tt.original) else mirrorCall("TypeTree") - } else { - var rtt = mirrorCall(nme.TypeTree, reifyType(tt.tpe)) - if (tt.original != null) { - val setOriginal = Select(rtt, newTermName("setOriginal")) - val reifiedOriginal = reify(tt.original) - rtt = Apply(setOriginal, List(reifiedOriginal)) - } - rtt - } - case ta @ TypeApply(hk, ts) => - if (ts exists isErased) reifyTree(hk) else reifyProduct(ta) - case global.emptyValDef => - mirrorSelect(nme.emptyValDef) - case Literal(constant @ Constant(tpe: Type)) if boundSyms exists (tpe contains _) => - CannotReifyClassOfBoundType(tree, tpe) - case Literal(constant @ Constant(sym: Symbol)) if boundSyms contains sym => - CannotReifyClassOfBoundEnum(tree, constant.tpe) - case _ => - if (tree.isDef) { - if (reifyDebug) println("boundSym: " + tree.symbol) - boundSyms += tree.symbol - } - - reifyProduct(tree) - /* - if (tree.isDef || tree.isInstanceOf[Function]) - registerReifiableSymbol(tree.symbol) - if (tree.hasSymbol) - rtree = Apply(Select(rtree, nme.setSymbol), List(reifySymRef(tree.symbol))) - Apply(Select(rtree, nme.setType), List(reifyType(tree.tpe))) -*/ - } - - /** - * Reify a free reference. The result will be either a mirror reference - * to a global value, or else a mirror Literal. - */ - private def reifyFree(tree: Tree): Tree = tree match { - case This(_) if tree.symbol.isClass && !tree.symbol.isModuleClass => - val sym = tree.symbol - if (reifyDebug) println("This for %s, reified as freeVar".format(sym)) - if (reifyDebug) println("Free: " + sym) - val freeVar = mirrorCall("freeVar", reify(sym.name.toString), reify(sym.tpe), This(sym)) - mirrorCall(nme.Ident, freeVar) - case This(_) => - if (reifyDebug) println("This for %s, reified as This".format(tree.symbol)) - mirrorCall(nme.This, reifySymRef(tree.symbol)) - case _ => - mirrorCall(nme.Ident, reifySymRef(tree.symbol)) - } - - // todo: consider whether we should also reify positions - private def reifyPosition(pos: Position): Tree = - reifyMirrorObject(NoPosition) - - // !!! we must eliminate these casts. - private def reifyProductUnsafe(x: Any): Tree = - reifyProduct(x.asInstanceOf[Product]) - private def reifyProduct(x: Product): Tree = - mirrorCall(x.productPrefix, (x.productIterator map reify).toList: _*) - - /** - * Reify a case object defined in Mirror - */ - private def reifyMirrorObject(name: String): Tree = mirrorSelect(name) - private def reifyMirrorObject(x: Product): Tree = reifyMirrorObject(x.productPrefix) - - private def isReifiableConstant(value: Any) = value match { - case null => true // seems pretty reifable to me? - case _: String => true - case _ => isAnyVal(value) - } - - /** Reify an arbitary value */ - private def reify(value: Any): Tree = value match { - case tree: Tree => reifyTree(tree) - case sym: Symbol => reifySymRef(sym) - case tpe: Type => reifyType(tpe) - case xs: List[_] => reifyList(xs) - case xs: Array[_] => scalaFactoryCall(nme.Array, xs map reify: _*) - case scope: Scope => reifyScope(scope) - case x: Name => reifyName(x) - case x: Position => reifyPosition(x) - case x: Modifiers => reifyModifiers(x) - case _ => - if (isReifiableConstant(value)) Literal(Constant(value)) - else reifyProductUnsafe(value) - } - - /** - * An (unreified) path that refers to definition with given fully qualified name - * @param mkName Creator for last portion of name (either TermName or TypeName) - */ - private def path(fullname: String, mkName: String => Name): Tree = { - val parts = fullname split "\\." - val prefixParts = parts.init - val lastName = mkName(parts.last) - if (prefixParts.isEmpty) Ident(lastName) - else { - val prefixTree = ((Ident(prefixParts.head): Tree) /: prefixParts.tail)(Select(_, _)) - Select(prefixTree, lastName) - } - } - - /** An (unreified) path that refers to term definition with given fully qualified name */ - private def termPath(fullname: String): Tree = path(fullname, newTermName) - - /** An (unreified) path that refers to type definition with given fully qualified name */ - private def typePath(fullname: String): Tree = path(fullname, newTypeName) - - private def mirrorAlias = - ValDef(NoMods, nme.MIRROR_SHORT, TypeTree(), termPath(fullnme.MirrorPackage)) - - /** - * Generate code that generates a symbol table of all symbols registered in `reifiableSyms` - */ - private def reifySymbolTableSetup: List[Tree] = { - val symDefs, fillIns = new mutable.ArrayBuffer[Tree] - var i = 0 - while (i < reifiableSyms.length) { - // fillInSymbol might create new reifiableSyms, that's why this is done iteratively - symDefs += reifySymbolDef(reifiableSyms(i)) - fillIns += fillInSymbol(reifiableSyms(i)) - i += 1 - } - - symDefs.toList ++ fillIns.toList - } - } - - /** A throwable signalling a reification error */ - class ReifierError(var pos: Position, val msg: String) extends Throwable(msg) { - def this(msg: String) = this(NoPosition, msg) - } - - def CannotReifyClassOfBoundType(tree: Tree, tpe: Type) = { - val msg = "cannot reify classOf[%s] which refers to a type declared inside the block being reified".format(tpe) - throw new ReifierError(tree.pos, msg) - } - - def CannotReifyClassOfBoundEnum(tree: Tree, tpe: Type) = { - val msg = "cannot reify classOf[%s] which refers to an enum declared inside the block being reified".format(tpe) - throw new ReifierError(tree.pos, msg) - } -} diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 1e17cb2e3f..a9278a2616 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -526,7 +526,7 @@ abstract class RefChecks extends InfoTransform with reflect.internal.transform.R // #3622: erasure operates on uncurried types -- // note on passing sym in both cases: only sym.isType is relevant for uncurry.transformInfo // !!! erasure.erasure(sym, uncurry.transformInfo(sym, tp)) gives erreneous of inaccessible type - check whether that's still the case! - def uncurryAndErase(tp: Type) = erasure.erasure(sym)(uncurry.transformInfo(sym, tp)) + def uncurryAndErase(tp: Type) = erasure.erasure(sym, uncurry.transformInfo(sym, tp)) val tp1 = uncurryAndErase(clazz.thisType.memberType(sym)) val tp2 = uncurryAndErase(clazz.thisType.memberType(other)) afterErasure(tp1 matches tp2) diff --git a/test/files/codelib/code.jar.desired.sha1 b/test/files/codelib/code.jar.desired.sha1 index dbf19cafd7..8dabf404b9 100644 --- a/test/files/codelib/code.jar.desired.sha1 +++ b/test/files/codelib/code.jar.desired.sha1 @@ -1 +1 @@ -e25f1daf9010b9dc6038ae7069fc9d0f7d48a53b ?code.jar +e76a8883d275ca4870f745b505fb0a1cb9cbe446 ?code.jar diff --git a/test/files/neg/anyval-children-2.check b/test/files/neg/anyval-children-2.check index cb327faeeb..a88682ea93 100644 --- a/test/files/neg/anyval-children-2.check +++ b/test/files/neg/anyval-children-2.check @@ -1,4 +1,4 @@ -anyval-children-2.scala:1: error: Only @inline classes (not traits) are allowed to extend AnyVal +anyval-children-2.scala:1: error: Only classes (not traits) are allowed to extend AnyVal @inline trait NotOkDingus1 extends AnyVal // fail ^ one error found diff --git a/test/files/neg/t5529.check b/test/files/neg/t5529.check index 78a26aeb50..5d2175fa79 100644 --- a/test/files/neg/t5529.check +++ b/test/files/neg/t5529.check @@ -4,9 +4,7 @@ t5529.scala:12: error: File is already defined as class File t5529.scala:10: error: class type required but test.Test.File found sealed class Dir extends File { } ^ -t5529.scala:10: error: illegal inheritance; super - is not a subclass of the superclass Object - of the mixin trait ScalaObject +t5529.scala:10: error: test.Test.File does not have a constructor sealed class Dir extends File { } ^ three errors found diff --git a/test/files/presentation/callcc-interpreter.check b/test/files/presentation/callcc-interpreter.check index 41b07b07dc..3385ef12b7 100644 --- a/test/files/presentation/callcc-interpreter.check +++ b/test/files/presentation/callcc-interpreter.check @@ -20,7 +20,7 @@ retrieved 64 members `method ->[B](y: B)(callccInterpreter.type, B)` `method ==(x$1: Any)Boolean` `method ==(x$1: AnyRef)Boolean` -`method add(a: callccInterpreter.Value, b: callccInterpreter.Value)callccInterpreter.M[_ >: callccInterpreter.Num with callccInterpreter.Wrong.type <: Serializable with Product with callccInterpreter.Value]` +`method add(a: callccInterpreter.Value, b: callccInterpreter.Value)callccInterpreter.M[_ >: callccInterpreter.Num with callccInterpreter.Wrong.type <: Product with Serializable with callccInterpreter.Value]` `method apply(a: callccInterpreter.Value, b: callccInterpreter.Value)callccInterpreter.M[callccInterpreter.Value]` `method asInstanceOf[T0]=> T0` `method callCC[A](h: (A => callccInterpreter.M[A]) => callccInterpreter.M[A])callccInterpreter.M[A]` @@ -87,7 +87,7 @@ def showM(m: callccInterpreter.M[callccInterpreter.Value]): String = m.in.apply( askType at CallccInterpreter.scala(50,30) ================================================================================ [response] askTypeAt at (50,30) -def add(a: callccInterpreter.Value, b: callccInterpreter.Value): callccInterpreter.M[_ >: callccInterpreter.Num with callccInterpreter.Wrong.type <: Serializable with Product with callccInterpreter.Value] = scala.this.Predef.Pair.apply[callccInterpreter.Value, callccInterpreter.Value](a, b) match { +def add(a: callccInterpreter.Value, b: callccInterpreter.Value): callccInterpreter.M[_ >: callccInterpreter.Num with callccInterpreter.Wrong.type <: Product with Serializable with callccInterpreter.Value] = scala.this.Predef.Pair.apply[callccInterpreter.Value, callccInterpreter.Value](a, b) match { case scala.this.Predef.Pair.unapply[callccInterpreter.Value, callccInterpreter.Value]() ((n: Int)callccInterpreter.Num((m @ _)), (n: Int)callccInterpreter.Num((n @ _))) => this.unitM[callccInterpreter.Num](callccInterpreter.this.Num.apply(m.+(n))) case _ => callccInterpreter.this.unitM[callccInterpreter.Wrong.type](callccInterpreter.this.Wrong) } diff --git a/test/files/run/existentials3.check b/test/files/run/existentials3.check index 41dc1f767c..8559540f80 100644 --- a/test/files/run/existentials3.check +++ b/test/files/run/existentials3.check @@ -1,22 +1,22 @@ -_ <: scala.runtime.AbstractFunction0[_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object -_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable -Object with Test$ToS with scala.ScalaObject -Object with Test$ToS with scala.ScalaObject -Object with Test$ToS with scala.ScalaObject -scala.Function0[Object with Test$ToS with scala.ScalaObject] -scala.Function0[Object with Test$ToS with scala.ScalaObject] -_ <: Object with _ <: Object with Object with Test$ToS with scala.ScalaObject -_ <: Object with _ <: Object with _ <: Object with Test$ToS with scala.ScalaObject -scala.collection.immutable.List[Object with scala.collection.Seq[Int] with scala.ScalaObject] -scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int] with scala.ScalaObject] -_ <: scala.runtime.AbstractFunction0[_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object -_ <: Object with Test$ToS with scala.ScalaObject with scala.Product with scala.Serializable -Object with Test$ToS with scala.ScalaObject -Object with Test$ToS with scala.ScalaObject -Object with Test$ToS with scala.ScalaObject -scala.Function0[Object with Test$ToS with scala.ScalaObject] -scala.Function0[Object with Test$ToS with scala.ScalaObject] -_ <: Object with _ <: Object with Object with Test$ToS with scala.ScalaObject -_ <: Object with _ <: Object with _ <: Object with Test$ToS with scala.ScalaObject -scala.collection.immutable.List[Object with scala.collection.Seq[Int] with scala.ScalaObject] -scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int] with scala.ScalaObject] +_ <: scala.runtime.AbstractFunction0[_ <: Object with Test$ToS with scala.Product with scala.Serializable with Object] with scala.Serializable with java.lang.Object +_ <: Object with Test$ToS with scala.Product with scala.Serializable with Object +Object with Test$ToS +Object with Test$ToS with Object +Object with Test$ToS +scala.Function0[Object with Test$ToS] +scala.Function0[Object with Test$ToS] +_ <: Object with _ <: Object with Object with Test$ToS with Object with Object +_ <: Object with _ <: Object with _ <: Object with Test$ToS with Object with Object +scala.collection.immutable.List[Object with scala.collection.Seq[Int] with Object] +scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int] with Object] +_ <: scala.runtime.AbstractFunction0[_ <: Object with Test$ToS with scala.Product with scala.Serializable with Object] with scala.Serializable with java.lang.Object +_ <: Object with Test$ToS with scala.Product with scala.Serializable with Object +Object with Test$ToS +Object with Test$ToS with Object +Object with Test$ToS +scala.Function0[Object with Test$ToS] +scala.Function0[Object with Test$ToS] +_ <: Object with _ <: Object with Object with Test$ToS with Object with Object +_ <: Object with _ <: Object with _ <: Object with Test$ToS with Object with Object +scala.collection.immutable.List[Object with scala.collection.Seq[Int] with Object] +scala.collection.immutable.List[Object with scala.collection.Seq[_ <: Int] with Object] diff --git a/test/files/run/programmatic-main.check b/test/files/run/programmatic-main.check index a24de79b8a..b5a54f5ea7 100644 --- a/test/files/run/programmatic-main.check +++ b/test/files/run/programmatic-main.check @@ -8,23 +8,22 @@ superaccessors 6 add super accessors in traits and nested classes pickler 7 serialize symbol tables refchecks 8 reference/override checking, translate nested objects - liftcode 9 reify trees - uncurry 10 uncurry, translate function values to anonymous classes - tailcalls 11 replace tail calls by jumps - specialize 12 @specialized-driven class and method specialization - explicitouter 13 this refs to outer pointers, translate patterns - erasure 14 erase types, add interfaces for traits - lazyvals 15 allocate bitmaps, translate lazy vals into lazified defs - lambdalift 16 move nested functions to top level - constructors 17 move field definitions into constructors - flatten 18 eliminate inner classes - mixin 19 mixin composition - cleanup 20 platform-specific cleanups, generate reflective calls - icode 21 generate portable intermediate code - inliner 22 optimization: do inlining -inlineExceptionHandlers 23 optimization: inline exception handlers - closelim 24 optimization: eliminate uncalled closures - dce 25 optimization: eliminate dead code - jvm 26 generate JVM bytecode - terminal 27 The last phase in the compiler chain + uncurry 9 uncurry, translate function values to anonymous classes + tailcalls 10 replace tail calls by jumps + specialize 11 @specialized-driven class and method specialization + explicitouter 12 this refs to outer pointers, translate patterns + erasure 13 erase types, add interfaces for traits + lazyvals 14 allocate bitmaps, translate lazy vals into lazified defs + lambdalift 15 move nested functions to top level + constructors 16 move field definitions into constructors + flatten 17 eliminate inner classes + mixin 18 mixin composition + cleanup 19 platform-specific cleanups, generate reflective calls + icode 20 generate portable intermediate code + inliner 21 optimization: do inlining +inlineExceptionHandlers 22 optimization: inline exception handlers + closelim 23 optimization: eliminate uncalled closures + dce 24 optimization: eliminate dead code + jvm 25 generate JVM bytecode + terminal 26 The last phase in the compiler chain diff --git a/test/files/run/reify_ann1a.check b/test/files/run/reify_ann1a.check index 2822238706..97d4848a49 100644 --- a/test/files/run/reify_ann1a.check +++ b/test/files/run/reify_ann1a.check @@ -1,5 +1,5 @@ { - @new ann(immutable.this.List.apply[String]("1a")) @new ann(immutable.this.List.apply[String]("1b")) class C[@new ann(immutable.this.List.apply[String]("2a")) @new ann(immutable.this.List.apply[String]("2b")) T>: Nothing <: Any] extends Object with ScalaObject { + @new ann(immutable.this.List.apply[String]("1a")) @new ann(immutable.this.List.apply[String]("1b")) class C[@new ann(immutable.this.List.apply[String]("2a")) @new ann(immutable.this.List.apply[String]("2b")) T>: Nothing <: Any] extends scala.AnyRef { @new ann(immutable.this.List.apply[String]("3a")) @new ann(immutable.this.List.apply[String]("3b")) private[this] val x: T @ann(immutable.this.List.apply[String]("4a")) @ann(immutable.this.List.apply[String]("4b")) = _; def (@new ann(immutable.this.List.apply[String]("3a")) @new ann(immutable.this.List.apply[String]("3b")) x: T @ann(immutable.this.List.apply[String]("4a")) @ann(immutable.this.List.apply[String]("4b"))) = { super.(); @@ -14,7 +14,7 @@ () } { - @ann(immutable.this.List.apply[String]("1a")) @ann(immutable.this.List.apply[String]("1b")) class C[@ann(immutable.this.List.apply[String]("2a")) @ann(immutable.this.List.apply[String]("2b")) T>: Nothing <: Any] extends Object with ScalaObject { + @ann(immutable.this.List.apply[String]("1a")) @ann(immutable.this.List.apply[String]("1b")) class C[@ann(immutable.this.List.apply[String]("2a")) @ann(immutable.this.List.apply[String]("2b")) T>: Nothing <: Any] extends scala.AnyRef { @ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) private[this] val x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a")) = _; def (@ann(immutable.this.List.apply[String]("3a")) @ann(immutable.this.List.apply[String]("3b")) x: T @ann(immutable.this.List.apply[String]("4b")) @ann(immutable.this.List.apply[String]("4a"))): C[T] = { C.super.(); diff --git a/test/files/run/reify_ann1b.check b/test/files/run/reify_ann1b.check index e240e1e0ce..ceebc0e2ed 100644 --- a/test/files/run/reify_ann1b.check +++ b/test/files/run/reify_ann1b.check @@ -1,5 +1,5 @@ { - @new ann(bar = "1a") @new ann(bar = "1b") class C[@new ann(bar = "2a") @new ann(bar = "2b") T>: Nothing <: Any] extends Object with ScalaObject { + @new ann(bar = "1a") @new ann(bar = "1b") class C[@new ann(bar = "2a") @new ann(bar = "2b") T>: Nothing <: Any] extends scala.AnyRef { @new ann(bar = "3a") @new ann(bar = "3b") private[this] val x: T @ann(bar = "4a") @ann(bar = "4b") = _; def (@new ann(bar = "3a") @new ann(bar = "3b") x: T @ann(bar = "4a") @ann(bar = "4b")) = { super.(); @@ -14,7 +14,7 @@ () } { - @ann(bar = "1a") @ann(bar = "1b") class C[@ann(bar = "2a") @ann(bar = "2b") T>: Nothing <: Any] extends Object with ScalaObject { + @ann(bar = "1a") @ann(bar = "1b") class C[@ann(bar = "2a") @ann(bar = "2b") T>: Nothing <: Any] extends scala.AnyRef { @ann(bar = "3a") @ann(bar = "3b") private[this] val x: T @ann(bar = "4b") @ann(bar = "4a") = _; def (@ann(bar = "3a") @ann(bar = "3b") x: T @ann(bar = "4b") @ann(bar = "4a")): C[T] = { C.super.(); diff --git a/test/files/run/reify_classfileann_a.check b/test/files/run/reify_classfileann_a.check index 1773263a94..419d916907 100644 --- a/test/files/run/reify_classfileann_a.check +++ b/test/files/run/reify_classfileann_a.check @@ -1,5 +1,5 @@ { - @new ann(bar = "1", quux = Array("2", "3"), baz = new ann(bar = "4")) class C extends Object with ScalaObject { + @new ann(bar = "1", quux = Array("2", "3"), baz = new ann(bar = "4")) class C extends scala.AnyRef { def () = { super.(); () @@ -8,7 +8,7 @@ () } { - @ann(bar = "1", quux = ["2", "3"], baz = ann(bar = "4")) class C extends Object with ScalaObject { + @ann(bar = "1", quux = ["2", "3"], baz = ann(bar = "4")) class C extends scala.AnyRef { def (): C = { C.super.(); () diff --git a/test/files/run/t1195.check b/test/files/run/t1195.check index dc521fb8ca..1214d0c4b5 100644 --- a/test/files/run/t1195.check +++ b/test/files/run/t1195.check @@ -1,6 +1,6 @@ -_ <: scala.runtime.AbstractFunction1[Int, _ <: Object with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object -_ <: Object with scala.ScalaObject with scala.Product with scala.Serializable -Object with scala.ScalaObject with scala.Product with scala.Serializable -_ <: scala.runtime.AbstractFunction1[Int, _ <: Object with scala.ScalaObject with scala.Product with scala.Serializable] with scala.ScalaObject with scala.Serializable with java.lang.Object -_ <: Object with scala.ScalaObject with scala.Product with scala.Serializable -Object with scala.ScalaObject with scala.Product with scala.Serializable +_ <: scala.runtime.AbstractFunction1[Int, _ <: Object with scala.Product with scala.Serializable with Object] with scala.Serializable with java.lang.Object +_ <: Object with scala.Product with scala.Serializable with Object +Object with scala.Product with scala.Serializable +_ <: scala.runtime.AbstractFunction1[Int, _ <: Object with scala.Product with scala.Serializable with Object] with scala.Serializable with java.lang.Object +_ <: Object with scala.Product with scala.Serializable with Object +Object with scala.Product with scala.Serializable diff --git a/test/files/run/t5224.check b/test/files/run/t5224.check index 5bead91b36..28bc75d4fd 100644 --- a/test/files/run/t5224.check +++ b/test/files/run/t5224.check @@ -1,5 +1,5 @@ { - @new Foo(bar = "qwe") class C extends Object with ScalaObject { + @new Foo(bar = "qwe") class C extends scala.AnyRef { def () = { super.(); () diff --git a/test/files/run/t5271_1.check b/test/files/run/t5271_1.check index d4fd544e88..9b956da17a 100644 --- a/test/files/run/t5271_1.check +++ b/test/files/run/t5271_1.check @@ -1,5 +1,5 @@ { - case class C extends Object with ScalaObject with Product with Serializable { + case class C extends Object with Product with Serializable { val foo : Int = _; val bar : Int = _; def (foo: Int, bar: Int) = { diff --git a/test/files/run/t5271_2.check b/test/files/run/t5271_2.check index 5a519f265f..27297febb6 100644 --- a/test/files/run/t5271_2.check +++ b/test/files/run/t5271_2.check @@ -1,5 +1,5 @@ { - case class C extends Object with ScalaObject with Product with Serializable { + case class C extends Object with Product with Serializable { val foo : Int = _; val bar : Int = _; def (foo: Int, bar: Int) = { diff --git a/test/files/run/t5271_3.check b/test/files/run/t5271_3.check index be87696f02..9331c78959 100644 --- a/test/files/run/t5271_3.check +++ b/test/files/run/t5271_3.check @@ -1,12 +1,12 @@ { - object C extends Object with ScalaObject with Serializable { + object C extends scala.AnyRef with Serializable { def () = { super.(); () }; def qwe: Int = 4 }; - case class C extends Object with ScalaObject with Product with Serializable { + case class C extends Object with Product with Serializable { val foo : Int = _; val bar : Int = _; def (foo: Int, bar: Int) = { diff --git a/test/files/run/t5527.check b/test/files/run/t5527.check index 4a8a9ce602..bb13928fd8 100644 --- a/test/files/run/t5527.check +++ b/test/files/run/t5527.check @@ -1,13 +1,13 @@ [[syntax trees at end of parser]]// Scala source: newSource1 package { - object UselessComments extends scala.ScalaObject { + object UselessComments extends scala.AnyRef { def () = { super.(); () }; var z = 0; def test1 = { - object Maybe extends scala.ScalaObject { + object Maybe extends scala.AnyRef { def () = { super.(); () @@ -42,13 +42,13 @@ package { } }; /** comments that we should keep */ - object UsefulComments extends scala.ScalaObject { + object UsefulComments extends scala.AnyRef { def () = { super.(); () }; /** class A */ - class A extends scala.ScalaObject { + class A extends scala.AnyRef { def () = { super.(); () @@ -61,7 +61,7 @@ package { var u = 2 }; /** trait B */ - abstract trait B extends scala.ScalaObject { + abstract trait B extends scala.AnyRef { def $init$() = { () }; @@ -75,7 +75,7 @@ package { var u = 2 }; /** object C */ - object C extends scala.ScalaObject { + object C extends scala.AnyRef { def () = { super.(); () @@ -88,7 +88,7 @@ package { var u = 2 }; /** class D */ - @new deprecated("use ... instead", "2.10.0") class D extends scala.ScalaObject { + @new deprecated("use ... instead", "2.10.0") class D extends scala.AnyRef { def () = { super.(); () diff --git a/test/files/specialized/SI-5005.check b/test/files/specialized/SI-5005.check index d2a97512ae..9fc63a2b1d 100644 --- a/test/files/specialized/SI-5005.check +++ b/test/files/specialized/SI-5005.check @@ -1,6 +1,6 @@ [[syntax trees at end of specialize]]// Scala source: newSource1 package { - class C2[@specialized(scala.Boolean) U >: Nothing <: Any] extends Object with ScalaObject { + class C2[@specialized(scala.Boolean) U >: Nothing <: Any] extends Object { def (): C2[U] = { C2.super.(); () @@ -8,7 +8,7 @@ package { def apply(x: U): U = x; def apply$mcZ$sp(x: Boolean): Boolean = C2.this.apply(x.asInstanceOf[U]()).asInstanceOf[Boolean]() }; - class B extends Object with ScalaObject { + class B extends Object { def (): B = { B.super.(); () -- cgit v1.2.3 From 5b562d4e7e451156236b48b3591db980a5691f8d Mon Sep 17 00:00:00 2001 From: Paul Phillips Date: Wed, 14 Mar 2012 12:26:38 -0700 Subject: Cleaning up stray ScalaObject references. --- src/compiler/scala/reflect/internal/Types.scala | 8 -------- src/detach/plugin/scala/tools/detach/Detach.scala | 3 +-- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala index 94559aeacd..ac4f404521 100644 --- a/src/compiler/scala/reflect/internal/Types.scala +++ b/src/compiler/scala/reflect/internal/Types.scala @@ -5879,14 +5879,6 @@ trait Types extends api.Types { self: SymbolTable => loop(initialBTSes) } - // @AM the following problem is solved by elimHOTparams in lublist - // @PP lubLists gone bad: lubList(List( - // List(scala.collection.generic.GenericCompanion[scala.collection.immutable.Seq], ScalaObject, java.lang.Object, Any) - // List(scala.collection.generic.GenericCompanion[scala.collection.mutable.Seq], ScalaObject, java.lang.Object, Any) - // )) == ( - // List(scala.collection.generic.GenericCompanion[Seq**[Any]**], ScalaObject, java.lang.Object, Any) - // ) - /** The minimal symbol (wrt Symbol.isLess) of a list of types */ private def minSym(tps: List[Type]): Symbol = (tps.head.typeSymbol /: tps.tail) { diff --git a/src/detach/plugin/scala/tools/detach/Detach.scala b/src/detach/plugin/scala/tools/detach/Detach.scala index 546041844e..41a3795a49 100644 --- a/src/detach/plugin/scala/tools/detach/Detach.scala +++ b/src/detach/plugin/scala/tools/detach/Detach.scala @@ -746,8 +746,7 @@ abstract class Detach extends PluginComponent // Variant 1: rebind/unbind val cparents = List(UnicastRemoteObjectClass.tpe, iface.tpe, UnreferencedClass.tpe) // Variant 2: un-/exportObject - //val cparents = List(ObjectClass.tpe, iface.tpe, - // UnreferencedClass.tpe, ScalaObjectClass.tpe) + //val cparents = List(ObjectClass.tpe, iface.tpe, UnreferencedClass.tpe) iclaz setInfo ClassInfoType(cparents, newScope, iclaz) val proxy = (iface, iclaz, new mutable.HashMap[Symbol, Symbol]) proxies(clazz) = proxy -- cgit v1.2.3