diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2014-11-03 11:05:48 +1000 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2014-11-07 11:40:03 +1000 |
commit | 51745c06f318f859b313c8257a41221837671ac1 (patch) | |
tree | 3e36f237343fabcd6416701e0f304ae8ed0b4b26 /src/compiler/scala/tools | |
parent | 2d8f919389fa33a554c5fb828bfa040f1b2531e4 (diff) | |
download | scala-51745c06f318f859b313c8257a41221837671ac1.tar.gz scala-51745c06f318f859b313c8257a41221837671ac1.tar.bz2 scala-51745c06f318f859b313c8257a41221837671ac1.zip |
More uniform treatment of package objects
- Introduce `Symbol#packageObject` and `Type#packageObject`
to lookup the member package object of a package class/module,
and use this far and wide.
- Replace the overly complicated (and still buggy) implementation
of `Context#isInPackageObject` with a one liner. The simplifying
insight is that if we select a symbol from a package prefix
that does not own that symbol, it *must* have really been
selected from the package object.
- Change implicit search to use the cache in
`ModuleSymbol#implicitMembers` via `Type#implicitMembers`,
which lets the client code read more naturally.
Fixes a bug with `adapt::insertApply` that Adriaan spotted in a feat
of lateral thinking. This is tested in t8862b.scala. alladin763.scala
adds the test case from the bug originally remedied by `insertApply`
to check we haven't regressed.
Diffstat (limited to 'src/compiler/scala/tools')
5 files changed, 22 insertions, 69 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index d9f56b47fa..a1cec2ee0b 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -1138,7 +1138,7 @@ abstract class GenICode extends SubComponent { // a package here, check if there's a package object. val sym = ( if (!tree.symbol.isPackageClass) tree.symbol - else tree.symbol.info.member(nme.PACKAGE) match { + else tree.symbol.info.packageObject match { case NoSymbol => abort("Cannot use package as value: " + tree) case s => devWarning(s"Found ${tree.symbol} where a package object is required. Converting to ${s.moduleClass}") diff --git a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala index daf36ce374..89d7acaa11 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/BCodeBodyBuilder.scala @@ -915,7 +915,7 @@ abstract class BCodeBodyBuilder extends BCodeSkelBuilder { def genLoadModule(tree: Tree): BType = { val module = ( if (!tree.symbol.isPackageClass) tree.symbol - else tree.symbol.info.member(nme.PACKAGE) match { + else tree.symbol.info.packageObject match { case NoSymbol => abort(s"SI-5604: Cannot use package as value: $tree") case s => abort(s"SI-5604: found package class where package object expected: $tree") } diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 6b3b605f1f..c86eaffccf 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -806,10 +806,11 @@ trait Contexts { self: Analyzer => private def collectImplicitImports(imp: ImportInfo): List[ImplicitInfo] = { val qual = imp.qual + val qualSym = qual.tpe.typeSymbol val pre = - if (qual.tpe.typeSymbol.isPackageClass) + if (qualSym.isPackageClass) // SI-6225 important if the imported symbol is inherited by the the package object. - singleType(qual.tpe, qual.tpe member nme.PACKAGE) + qualSym.packageObject.typeOfThis else qual.tpe def collect(sels: List[ImportSelector]): List[ImplicitInfo] = sels match { @@ -882,13 +883,8 @@ trait Contexts { self: Analyzer => Some(collectImplicitImports(imports.head)) } else if (owner.isPackageClass) { // the corresponding package object may contain implicit members. - owner.tpe.member(nme.PACKAGE) match { - case NoSymbol => - None - case packageObject => - val pre = packageObject.typeOfThis - Some(collectImplicits(pre.implicitMembers, pre)) - } + val pre = owner.packageObject.typeOfThis + Some(collectImplicits(pre.implicitMembers, pre)) } else Some(Nil) } @@ -958,52 +954,11 @@ trait Contexts { self: Analyzer => private def importedAccessibleSymbol(imp: ImportInfo, name: Name, requireExplicit: Boolean): Symbol = imp.importedSymbol(name, requireExplicit) filter (s => isAccessible(s, imp.qual.tpe, superAccess = false)) - /** Is `sym` defined in package object of package `pkg`? - * Since sym may be defined in some parent of the package object, - * we cannot inspect its owner only; we have to go through the - * info of the package object. However to avoid cycles we'll check - * what other ways we can before pushing that way. + /** Must `sym` defined in package object of package `pkg`, if + * it selected from a prefix with `pkg` as its type symbol? */ - def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = { - def uninitialized(what: String) = { - log(s"Cannot look for $sym in package object of $pkg; $what is not initialized.") - false - } - def pkgClass = if (pkg.isTerm) pkg.moduleClass else pkg - def matchesInfo = ( - // need to be careful here to not get a cyclic reference during bootstrap - if (pkg.isInitialized) { - val module = pkg.info member nme.PACKAGEkw - if (module.isInitialized) - module.info.member(sym.name).alternatives contains sym - else - uninitialized("" + module) - } - else uninitialized("" + pkg) - ) - def inPackageObject(sym: Symbol) = ( - // To be in the package object, one of these must be true: - // 1) sym.owner is a package object class, and sym.owner.owner is the package class for `pkg` - // 2) sym.owner is inherited by the correct package object class - // We try to establish 1) by inspecting the owners directly, and then we try - // to rule out 2), and only if both those fail do we resort to looking in the info. - !sym.hasPackageFlag && sym.owner.exists && ( - if (sym.owner.isPackageObjectClass) - sym.owner.owner == pkgClass - else - !sym.owner.isPackageClass && matchesInfo - ) - ) - - // An overloaded symbol might not have the expected owner! - // The alternatives must be inspected directly. - pkgClass.isPackageClass && ( - if (sym.isOverloaded) - sym.alternatives forall (isInPackageObject(_, pkg)) - else - inPackageObject(sym) - ) - } + def isInPackageObject(sym: Symbol, pkg: Symbol): Boolean = + pkg.isPackage && sym.owner != pkg def isNameInScope(name: Name) = lookupSymbol(name, _ => true).isSuccess diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala index 2fab4557bd..e2ad578252 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala @@ -1012,18 +1012,12 @@ trait Implicits { } case None => if (pre.isStable && !pre.typeSymbol.isExistentiallyBound) { - val companion = - if (sym.isPackageClass) sym.info.member(nme.PACKAGE) //companionSymbolOf(sym.member, context) - else companionSymbolOf(sym, context) - companion.moduleClass match { - case mc: ModuleClassSymbol => - val pre1 = if (mc.isPackageObjectClass) mc.typeOfThis else singleType(pre, companion) - val infos = - for (im <- mc.implicitMembers.toList) yield new ImplicitInfo(im.name, pre1, im) - if (infos.nonEmpty) - infoMap += (sym -> infos) - case _ => - } + val pre1 = + if (sym.isPackageClass) sym.packageObject.typeOfThis + else singleType(pre, companionSymbolOf(sym, context)) + val infos = pre1.implicitMembers.iterator.map(mem => new ImplicitInfo(mem.name, pre1, mem)).toList + if (infos.nonEmpty) + infoMap += (sym -> infos) } val bts = tp.baseTypeSeq var i = 1 diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 422b940cd3..fe6038bc00 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -538,7 +538,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper } val qual = typedQualifier { atPos(tree.pos.makeTransparent) { tree match { - case Ident(_) => Ident(rootMirror.getPackageObjectWithMember(pre, sym)) + case Ident(_) => + val packageObject = + if (sym.owner.isModuleClass) sym.owner.sourceModule // historical optimization, perhaps no longer needed + else pre.typeSymbol.packageObject + Ident(packageObject) case Select(qual, _) => Select(qual, nme.PACKAGEkw) case SelectFromTypeTree(qual, _) => Select(qual, nme.PACKAGEkw) } |