Skip to content

Commit

Permalink
SI-5604, selections on package objects.
Browse files Browse the repository at this point in the history
[backport]
mkAttributedSelect, which creates a Select tree based on
a symbol, has been a major source of package object bugs,
because it has not been accurately identifying selections
on package objects.  When selecting foo.bar, if foo turns
out to be a package object, the created Select tree must be

  foo.`package`.bar

However mkAttributedSelect was only examining the owner of
the symbol, which means it would work if the package object
defined bar directly, but not if it inherited it.
  • Loading branch information
paulp committed Jan 30, 2013
1 parent e156cd1 commit d4437aa
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 3 deletions.
25 changes: 22 additions & 3 deletions src/reflect/scala/reflect/internal/TreeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,29 @@ abstract class TreeGen extends macros.TreeBuilder {
if (qual.symbol != null && (qual.symbol.isEffectiveRoot || qual.symbol.isEmptyPackage))
mkAttributedIdent(sym)
else {
// Have to recognize anytime a selection is made on a package
// so it can be rewritten to foo.bar.`package`.name rather than
// foo.bar.name if name is in the package object.
// TODO - factor out the common logic between this and
// the Typers method "isInPackageObject", used in typedIdent.
val qualsym = (
if (qual.tpe ne null) qual.tpe.typeSymbol
else if (qual.symbol ne null) qual.symbol
else NoSymbol
)
val needsPackageQualifier = (
(sym ne null)
&& qualsym.isPackage
&& !sym.isDefinedInPackage
)
val pkgQualifier =
if (sym != null && sym.owner.isPackageObjectClass && sym.effectiveOwner == qual.tpe.typeSymbol) {
val obj = sym.owner.sourceModule
Select(qual, nme.PACKAGE) setSymbol obj setType singleType(qual.tpe, obj)
if (needsPackageQualifier) {
// The owner of a symbol which requires package qualification may be the
// package object iself, but it also could be any superclass of the package
// object. In the latter case, we must go through the qualifier's info
// to obtain the right symbol.
val packageObject = if (sym.owner.isModuleClass) sym.owner.sourceModule else qual.tpe member nme.PACKAGE
Select(qual, nme.PACKAGE) setSymbol packageObject setType singleType(qual.tpe, packageObject)
}
else qual

Expand Down
6 changes: 6 additions & 0 deletions test/files/pos/t5604b/T_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// sandbox/t5604/T.scala
package t6504

trait T {
def foo: Boolean = false
}
6 changes: 6 additions & 0 deletions test/files/pos/t5604b/T_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// sandbox/t5604/T.scala
package t6504

trait T {
def foo: Boolean = false
}
7 changes: 7 additions & 0 deletions test/files/pos/t5604b/Test_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// sandbox/t5604/Test.scala
package t6504

object Test {
def blerg1(a: Any): Any = if (foo) blerg1(0)
def blerg2(a: Any): Any = if (t6504.foo) blerg2(0)
}
7 changes: 7 additions & 0 deletions test/files/pos/t5604b/Test_2.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// sandbox/t5604/Test.scala
package t6504

object Test {
def blerg1(a: Any): Any = if (foo) blerg1(0)
def blerg2(a: Any): Any = if (t6504.foo) blerg2(0)
}
5 changes: 5 additions & 0 deletions test/files/pos/t5604b/pack_1.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// sandbox/t5604/pack.scala
package t6504

object `package` extends T {
}
8 changes: 8 additions & 0 deletions test/files/run/t5604.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
long
double
long
double
long
double
long
double
50 changes: 50 additions & 0 deletions test/files/run/t5604.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// a.scala
// Fri Jan 13 11:31:47 PST 2012

package foo {
object regular extends Duh {
def buh(n: Long) = println("long")
def buh(n: Double) = println("double")
}
class regular {
import regular._

duh(33L)
duh(3.0d)
foo.regular.duh(33L)
foo.regular.duh(3.0d)
buh(66L)
buh(6.0d)
foo.regular.buh(66L)
foo.regular.buh(6.0d)
}

trait Duh {
def duh(n: Long) = println("long")
def duh(n: Double) = println("double")
}
package object bar extends Duh {
def buh(n: Long) = println("long")
def buh(n: Double) = println("double")
}
package bar {
object Main {
def main(args:Array[String]) {
duh(33L)
duh(3.0d)
foo.bar.duh(33L)
foo.bar.duh(3.0d)
buh(66L)
buh(6.0d)
foo.bar.buh(66L)
foo.bar.buh(6.0d)
}
}
}
}

object Test {
def main(args: Array[String]): Unit = {
foo.bar.Main.main(null)
}
}

0 comments on commit d4437aa

Please sign in to comment.