summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2010-06-13 15:12:54 +0000
committerMartin Odersky <odersky@gmail.com>2010-06-13 15:12:54 +0000
commitcb988a4af07c2b3b4427fbf047beb5c74fe90958 (patch)
tree139937ff046ba14000113ea44d4def35b9508ee6
parent5791355fe2e5b3f4cdb166f1550d504ac710f953 (diff)
downloadscala-cb988a4af07c2b3b4427fbf047beb5c74fe90958.tar.gz
scala-cb988a4af07c2b3b4427fbf047beb5c74fe90958.tar.bz2
scala-cb988a4af07c2b3b4427fbf047beb5c74fe90958.zip
Applied patch that closes #3560 and still fixes...
Applied patch that closes #3560 and still fixes #3174.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala117
1 files changed, 71 insertions, 46 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index a892ae1582..284d359ce0 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -69,6 +69,10 @@ trait Typers { self: Analyzer =>
private class NormalTyper(context : Context) extends Typer(context)
// hooks for auto completion
+ // A transient flag to mark members of anonymous classes
+ // that are turned private by typedBlock
+ private final val SYNTHETIC_PRIVATE = TRANS_FLAG
+
// Mode constants
/** The three mode <code>NOmode</code>, <code>EXPRmode</code>
@@ -433,7 +437,7 @@ trait Typers { self: Analyzer =>
override def apply(t: Type): Type = {
def checkNoEscape(sym: Symbol) {
- if (sym.hasFlag(PRIVATE)) {
+ if (sym.hasFlag(PRIVATE) && !sym.hasFlag(SYNTHETIC_PRIVATE)) {
var o = owner
while (o != NoSymbol && o != sym.owner &&
!o.isLocal && !o.hasFlag(PRIVATE) &&
@@ -1821,54 +1825,75 @@ trait Typers { self: Analyzer =>
* @return ...
*/
def typedBlock(block: Block, mode: Int, pt: Type): Block = {
- namer.enterSyms(block.stats)
- for (stat <- block.stats) {
- if (onlyPresentation && stat.isDef) {
- var e = context.scope.lookupEntry(stat.symbol.name)
- while ((e ne null) && (e.sym ne stat.symbol)) e = e.tail
- if (e eq null) context.scope.enter(stat.symbol)
+ val syntheticPrivates = new ListBuffer[Symbol]
+ try {
+ namer.enterSyms(block.stats)
+ for (stat <- block.stats) {
+ if (onlyPresentation && stat.isDef) {
+ var e = context.scope.lookupEntry(stat.symbol.name)
+ while ((e ne null) && (e.sym ne stat.symbol)) e = e.tail
+ if (e eq null) context.scope.enter(stat.symbol)
+ }
+ enterLabelDef(stat)
}
- enterLabelDef(stat)
- }
- if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
- // One reason for this code is that structural refinements
- // come with strings attached; for instance the inferred type
- // may not refer to enclosing type parameters.
- // So abstracting out an anonymous class might lead to type errors.
- // The setPrivateWithin below is is a quick hack to avoid escaping privates checks
- // we need to go back and address the problem of escaping
- // idents form ths ground up.
- block match {
- case block @ Block(List(classDef @ ClassDef(_, _, _, _)), newInst @ Apply(Select(New(_), _), _)) =>
- // The block is an anonymous class definitions/instantiation pair
- // -> members that are hidden by the type of the block are made private
- val visibleMembers = pt match {
- case WildcardType => classDef.symbol.info.decls.toList
- case BoundedWildcardType(TypeBounds(lo, hi)) => lo.members
- case _ => pt.members
- }
- for (member <- classDef.symbol.info.decls.toList
- if member.isTerm && !member.isConstructor &&
- member.allOverriddenSymbols.isEmpty &&
- (!member.hasFlag(PRIVATE) && member.privateWithin == NoSymbol) &&
- !(visibleMembers exists { visible =>
- visible.name == member.name &&
- member.tpe <:< visible.tpe.substThis(visible.owner, ThisType(classDef.symbol))
- })
- ) {
- member.resetFlag(PROTECTED)
- member.resetFlag(LOCAL)
- member.privateWithin = classDef.symbol
- }
- case _ =>
+
+ if (phaseId(currentPeriod) <= currentRun.typerPhase.id) {
+ // This is very tricky stuff, because we are navigating
+ // the Skylla and Charybdis of anonymous classes and what to return
+ // from them here. On the one hand, we cannot admit
+ // every non-private member of an anonymous class as a part of
+ // the structural type of the enclosing block. This runs afoul of
+ // the restriction that a structural type may not refer to an enclosing
+ // type parameter or abstract types (which in turn is necessitated
+ // by what can be done in Java reflection. On the other hand,
+ // making every term member private conflicts with private escape checking
+ // see ticket #3174 for an example.
+ // The cleanest way forward is if we would find a way to suppress
+ // structural type checking for these members and maybe defer
+ // type errors to the places where members are called. But that would
+ // be a bug refactoring and also a big departure from existing code.
+ // The probably safest fix for 2.8 is to keep members of an anonymous
+ // class that are not mentioned in a parent type private (as before)
+ // but to disable escape checking for code that's in the same anonymous class.
+ // That's what's done here.
+ // We really should go back and think hard whether we find a better
+ // way to address the problem of escaping idents on the one hand and well-formed
+ // structural types on the other.
+ block match {
+ case block @ Block(List(classDef @ ClassDef(_, _, _, _)), newInst @ Apply(Select(New(_), _), _)) =>
+ // The block is an anonymous class definitions/instantiation pair
+ // -> members that are hidden by the type of the block are made private
+ val visibleMembers = pt match {
+ case WildcardType => classDef.symbol.info.decls.toList
+ case BoundedWildcardType(TypeBounds(lo, hi)) => lo.members
+ case _ => pt.members
+ }
+ for (member <- classDef.symbol.info.decls.toList
+ if member.isTerm && !member.isConstructor &&
+ member.allOverriddenSymbols.isEmpty &&
+ (!member.hasFlag(PRIVATE) && member.privateWithin == NoSymbol) &&
+ !(visibleMembers exists { visible =>
+ visible.name == member.name &&
+ member.tpe <:< visible.tpe.substThis(visible.owner, ThisType(classDef.symbol))
+ })
+ ) {
+ member.resetFlag(PROTECTED)
+ member.resetFlag(LOCAL)
+ member.setFlag(PRIVATE | SYNTHETIC_PRIVATE)
+ member.privateWithin = NoSymbol
+ }
+ case _ =>
+ }
}
+ val stats1 = typedStats(block.stats, context.owner)
+ val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt)
+ treeCopy.Block(block, stats1, expr1)
+ .setType(if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst)
+ } finally {
+ // enable escaping privates checking from the outside and recycle
+ // transient flag
+ for (sym <- syntheticPrivates) sym resetFlag SYNTHETIC_PRIVATE
}
- val stats1 = typedStats(block.stats, context.owner)
- val expr1 = typed(block.expr, mode & ~(FUNmode | QUALmode), pt)
- val block1 = treeCopy.Block(block, stats1, expr1)
- .setType(if (treeInfo.isPureExpr(block)) expr1.tpe else expr1.tpe.deconst)
- //checkNoEscaping.locals(context.scope, pt, block1)
- block1
}
/**