summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-12-19 22:37:58 -0800
committerPaul Phillips <paulp@improving.org>2011-12-19 23:22:35 -0800
commitbba3b00cf737528de9dcb4823806d6928a00474e (patch)
treecc1c6db76a3c72d22bb0dd5b10ac4921bdeb08b0
parent6226468fdf81d46f005b97fb49c4ec08c856ea3f (diff)
downloadscala-bba3b00cf737528de9dcb4823806d6928a00474e.tar.gz
scala-bba3b00cf737528de9dcb4823806d6928a00474e.tar.bz2
scala-bba3b00cf737528de9dcb4823806d6928a00474e.zip
Fix for classOf NPE.
Let type parameter be inferred. Closes SI-4871.
-rw-r--r--src/compiler/scala/reflect/internal/Definitions.scala10
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala34
-rw-r--r--test/files/run/t4871.check2
-rw-r--r--test/files/run/t4871.scala12
5 files changed, 49 insertions, 20 deletions
diff --git a/src/compiler/scala/reflect/internal/Definitions.scala b/src/compiler/scala/reflect/internal/Definitions.scala
index 4d71d2a769..6ee9347aab 100644
--- a/src/compiler/scala/reflect/internal/Definitions.scala
+++ b/src/compiler/scala/reflect/internal/Definitions.scala
@@ -232,6 +232,16 @@ 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
+ * during resident compilations).
+ */
+ def isPredefMemberNamed(sym: Symbol, name: Name) = (
+ (sym.name == name) && (sym.owner == PredefModule.moduleClass)
+ )
+
lazy val ConsoleModule: Symbol = getModule("scala.Console")
lazy val ScalaRunTimeModule: Symbol = getModule("scala.runtime.ScalaRunTime")
lazy val SymbolModule: Symbol = getModule("scala.Symbol")
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 92be241951..d54cb248cf 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -740,7 +740,7 @@ trait Implicits {
)
private def isIneligible(info: ImplicitInfo) = (
info.isCyclicOrErroneous
- || isView && isConforms(info.sym)
+ || isView && isPredefMemberNamed(info.sym, nme.conforms)
|| isShadowed(info.name)
)
@@ -760,15 +760,6 @@ trait Implicits {
*/
private def checkValid(sym: Symbol) = isValid(sym) || { invalidImplicits += sym ; false }
- /** Is `sym` the standard conforms method in Predef?
- * Note: DON't replace this by sym == Predef_conforms, as Predef_conforms is a `def`
- * which does a member lookup (it can't be a lazy val because we might reload Predef
- * during resident compilations).
- */
- private def isConforms(sym: Symbol) = (
- (sym.name == nme.conforms) && (sym.owner == PredefModule.moduleClass)
- )
-
/** Preventing a divergent implicit from terminating implicit search,
* so that if there is a best candidate it can still be selected.
*/
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 9b03d59216..341e1bc5ea 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2950,6 +2950,11 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
new DeSkolemizeMap mapOver tp
}
+ def typedClassOf(tree: Tree, tpt: Tree) = {
+ checkClassType(tpt, true, false)
+ atPos(tree.pos)(gen.mkClassOf(tpt.tpe))
+ }
+
protected def typedExistentialTypeTree(tree: ExistentialTypeTree, mode: Int): Tree = {
for (wc <- tree.whereClauses)
if (wc.symbol == NoSymbol) { namer.enterSym(wc); wc.symbol setFlag EXISTENTIAL }
@@ -2989,10 +2994,9 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
if (sameLength(tparams, args)) {
val targs = args map (_.tpe)
checkBounds(tree.pos, NoPrefix, NoSymbol, tparams, targs, "")
- if (fun.symbol == Predef_classOf) {
- checkClassType(args.head, true, false)
- atPos(tree.pos) { gen.mkClassOf(targs.head) }
- } else {
+ if (fun.symbol == Predef_classOf)
+ typedClassOf(tree, args.head)
+ else {
if (!isPastTyper && fun.symbol == Any_isInstanceOf && !targs.isEmpty)
checkCheckable(tree.pos, targs.head, "")
val resultpe = restpe.instantiateTypeParams(tparams, targs)
@@ -3769,7 +3773,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
@@ -3900,13 +3904,23 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
}
}
}
- if (defSym.owner.isPackageClass) pre = defSym.owner.thisType
+ if (defSym.owner.isPackageClass)
+ pre = defSym.owner.thisType
+
+ // Inferring classOf type parameter from expected type.
if (defSym.isThisSym) {
typed1(This(defSym.owner) setPos tree.pos, mode, pt)
- } else {
- val tree1 = if (qual == EmptyTree) tree
- else atPos(tree.pos)(Select(qual, name))
- // atPos necessary because qualifier might come from startContext
+ }
+ // Inferring classOf type parameter from expected type. Otherwise an
+ // actual call to the stubbed classOf method is generated, returning null.
+ else if (isPredefMemberNamed(defSym, nme.classOf) && pt.typeSymbol == ClassClass && pt.typeArgs.nonEmpty)
+ typedClassOf(tree, TypeTree(pt.typeArgs.head))
+ else {
+ val tree1 = (
+ if (qual == EmptyTree) tree
+ // atPos necessary because qualifier might come from startContext
+ else atPos(tree.pos)(Select(qual, name))
+ )
val (tree2, pre2) = makeAccessible(tree1, defSym, pre, qual)
// assert(pre.typeArgs isEmpty) // no need to add #2416-style check here, right?
stabilize(tree2, pre2, mode, pt) match {
diff --git a/test/files/run/t4871.check b/test/files/run/t4871.check
new file mode 100644
index 0000000000..a60526a0f3
--- /dev/null
+++ b/test/files/run/t4871.check
@@ -0,0 +1,2 @@
+class Test$C
+class Test$D
diff --git a/test/files/run/t4871.scala b/test/files/run/t4871.scala
new file mode 100644
index 0000000000..70d8b7145c
--- /dev/null
+++ b/test/files/run/t4871.scala
@@ -0,0 +1,12 @@
+object Test {
+ class C
+ class D
+
+ def main(args: Array[String]): Unit = {
+ val z: Class[C] = classOf
+ val z2: Class[D] = classOf[D]
+
+ println(z)
+ println(z2)
+ }
+}