-
Notifications
You must be signed in to change notification settings - Fork 21
Visibilty change (protected -> public) not possible with refinement #1352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Imported From: https://issues.scala-lang.org/browse/SI-1352?orig=1 |
@odersky said: |
@Atry said: object buffer extends collection.mutable.ArrayBuffer[Int]
{
// chagne from public to protected
override def ensureSize(n : Int) = super.ensureSize(n)
def foo = println("new method")
} |
@paulp said: scala> abstract class FooClass { protected def bar: Int }
defined class FooClass
scala> val x = new FooClass { def bar = 1 }
x: FooClass = $anon$1@7da72267
scala> x.bar
<console>:10: error: method bar in class FooClass cannot be accessed in FooClass
Access to protected method bar not permitted because
enclosing object $iw is not a subclass of
class FooClass where target is defined
x.bar
^
scala> val x = new FooClass { val bar = 1 }
x: FooClass{val bar: Int} = $anon$1@393ddf54
scala> x.bar
res0: Int = 1 But... scala> abstract class FooClass { protected val bar: Int }
defined class FooClass
scala> val x = new FooClass { val bar = 1 }
x: FooClass = $anon$1@72f9a516
scala> x.bar
<console>:10: error: value bar in class FooClass cannot be accessed in FooClass
Access to protected value bar not permitted because
enclosing object $iw is not a subclass of
class FooClass where target is defined
x.bar
^ scala insists I bring SOMETHING new to the table if I want to widen the access: def becomes val, more specific return type... but with no "public" keyword, it is impossible to just say it. But there's no reason we should make you say it anyway, because the absence of access modifiers means public! Why would it infer a more restrictive type than the one we declared? Here's the kind of desperation one ends up with. scala> abstract class FooClass { protected val bar: Int }
defined class FooClass
scala> val x = new FooClass { override val bar = 1.asInstanceOf[Int with Nothing] }
x: FooClass{val bar: Int with Nothing} = $anon$1@6e963c02
scala> x.bar
res0: Int with Nothing = 1
scala> x.bar: Int
res1: Int = 1 |
@gkossakowski said: |
@Atry said: Welcome to Scala version 2.10.3 (Java HotSpot(TM) Client VM, Java 1.7.0_25).
Type in expressions to have them evaluated.
Type :help for more information.
scala> trait A { protected val foo: Int }
defined trait A
scala> trait B { protected val foo: Int }
defined trait B
scala> new A with B { val foo = 1; val bar = 2 }
res0: A with B{val bar: Int} = $anon$1@1e3c5fd
scala> res0.bar
warning: there were 1 feature warning(s); re-run with -feature for details
res1: Int = 2
scala> res0.foo
<console>:11: error: value foo in trait B cannot be accessed in A with B{val bar: Int}
Access to protected value foo not permitted because
enclosing object $iw is not a subclass of
trait B where target is defined
res0.foo
^
scala> (new A with B { val foo = 1; val bar = 2 }).foo // It works, why?
res3: Int = 1 |
@retronym said: def typedBlock(block0: Block, mode: Mode, pt: Type): Block = {
val syntheticPrivates = new ListBuffer[Symbol]
try {
namer.enterSyms(block0.stats)
val block = treeCopy.Block(block0, pluginsEnterStats(this, block0.stats), block0.expr)
for (stat <- block.stats) enterLabelDef(stat)
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 big 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(List(classDef @ ClassDef(_, _, _, _)), Apply(Select(New(_), _), _)) =>
val classDecls = classDef.symbol.info.decls
val visibleMembers = pt match {
case WildcardType => classDecls.toList
case BoundedWildcardType(TypeBounds(lo, _)) => lo.members
case _ => pt.members
}
def matchesVisibleMember(member: Symbol) = visibleMembers exists { vis =>
(member.name == vis.name) &&
(member.tpe <:< vis.tpe.substThis(vis.owner, classDef.symbol))
}
// The block is an anonymous class definitions/instantiation pair
// -> members that are hidden by the type of the block are made private
val toHide = (
classDecls filter (member =>
member.isTerm
&& member.isPossibleInRefinement
&& member.isPublic
&& !matchesVisibleMember(member)
) map (member => member
resetFlag (PROTECTED | LOCAL)
setFlag (PRIVATE | SYNTHETIC_PRIVATE)
setPrivateWithin NoSymbol
)
)
syntheticPrivates ++= toHide
case _ =>
}
}
val stats1 = if (isPastTyper) block.stats else
block.stats.flatMap(stat => stat match {
case vd@ValDef(_, _, _, _) if vd.symbol.isLazy =>
namer.addDerivedTrees(Typer.this, vd)
case _ => stat::Nil
})
val stats2 = typedStats(stats1, context.owner)
val expr1 = typed(block.expr, mode &~ (FUNmode | QUALmode), pt)
treeCopy.Block(block, stats2, expr1)
.setType(if (treeInfo.isExprSafeToInline(block)) expr1.tpe else expr1.tpe.deconst)
} finally {
// enable escaping privates checking from the outside and recycle
// transient flag
syntheticPrivates foreach (_ resetFlag SYNTHETIC_PRIVATE)
}
} |
error: method ensureSize cannot be accessed in scala.collection.mutable.ArrayBuffer[Int]{def foo: Unit}
The text was updated successfully, but these errors were encountered: