Skip to content

Commit 7dfbf07

Browse files
committed
Merge commit 'b43ae58f31'; commit 'b579a42ee3'; commit '81fa831609' into merge-210
* commit 'b43ae58f31': introduces an exhaustive java-to-scala test SI-6989 privateWithin is now populated in reflect * commit 'b579a42ee3': SI-6888 Loosen criteria for $outer search. * commit '81fa831609': Class symbols can't be contravariant. SI-6666 Catch VerifyErrors in the making in early defs. Broader checks for poisonous this references. Add a test case from the comments of SI-6666. SI-6666 Account for nesting in setting INCONSTRUCTOR Move a test from pos to run to highlight bytecode deficiencies. Conflicts: src/compiler/scala/tools/nsc/interpreter/IMain.scala
4 parents 2a48821 + b43ae58 + b579a42 + 81fa831 commit 7dfbf07

30 files changed

+624
-93
lines changed

src/compiler/scala/tools/nsc/interpreter/IMain.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,9 @@ class IMain(initialSettings: Settings, protected val out: JPrintWriter) extends
243243
settings.outputDirs setSingleOutput replOutput.dir
244244
settings.exposeEmptyPackage.value = true
245245
if (settings.Yrangepos.value)
246-
new Global(settings, reporter) with ReplGlobal with interactive.RangePositions
246+
new Global(settings, reporter) with ReplGlobal with interactive.RangePositions { override def toString: String = "<global>" }
247247
else
248-
new Global(settings, reporter) with ReplGlobal
248+
new Global(settings, reporter) with ReplGlobal { override def toString: String = "<global>" }
249249
}
250250

251251
/** Parent classloader. Overridable. */

src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -547,8 +547,8 @@ abstract class ClassfileParser {
547547
skipMembers() // methods
548548
if (!isScala) {
549549
clazz setFlag sflags
550-
setPrivateWithin(clazz, jflags)
551-
setPrivateWithin(staticModule, jflags)
550+
importPrivateWithinFromJavaFlags(clazz, jflags)
551+
importPrivateWithinFromJavaFlags(staticModule, jflags)
552552
clazz.setInfo(classInfo)
553553
moduleClass setInfo staticInfo
554554
staticModule.setInfo(moduleClass.tpe)
@@ -611,7 +611,7 @@ abstract class ClassfileParser {
611611
if (isEnum) ConstantType(Constant(sym))
612612
else info
613613
}
614-
setPrivateWithin(sym, jflags)
614+
importPrivateWithinFromJavaFlags(sym, jflags)
615615
parseAttributes(sym, info)
616616
getScope(jflags).enter(sym)
617617

@@ -662,7 +662,7 @@ abstract class ClassfileParser {
662662
info = MethodType(newParams, clazz.tpe)
663663
}
664664
sym.setInfo(info)
665-
setPrivateWithin(sym, jflags)
665+
importPrivateWithinFromJavaFlags(sym, jflags)
666666
parseAttributes(sym, info)
667667
if ((jflags & JAVA_ACC_VARARGS) != 0) {
668668
sym.setInfo(arrayToRepeated(sym.info))
@@ -1249,19 +1249,6 @@ abstract class ClassfileParser {
12491249
protected def getScope(flags: Int): Scope =
12501250
if (isStatic(flags)) staticScope else instanceScope
12511251

1252-
private def setPrivateWithin(sym: Symbol, jflags: Int) {
1253-
if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)) == 0)
1254-
// See ticket #1687 for an example of when topLevelClass is NoSymbol: it
1255-
// apparently occurs when processing v45.3 bytecode.
1256-
if (sym.enclosingTopLevelClass != NoSymbol)
1257-
sym.privateWithin = sym.enclosingTopLevelClass.owner
1258-
1259-
// protected in java means package protected. #3946
1260-
if ((jflags & JAVA_ACC_PROTECTED) != 0)
1261-
if (sym.enclosingTopLevelClass != NoSymbol)
1262-
sym.privateWithin = sym.enclosingTopLevelClass.owner
1263-
}
1264-
12651252
private def isPrivate(flags: Int) = (flags & JAVA_ACC_PRIVATE) != 0
12661253
private def isStatic(flags: Int) = (flags & JAVA_ACC_STATIC) != 0
12671254
private def hasAnnotation(flags: Int) = (flags & JAVA_ACC_ANNOTATION) != 0

src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package transform
88

99
import symtab._
1010
import Flags.{ CASE => _, _ }
11+
import scala.collection.mutable
1112
import scala.collection.mutable.ListBuffer
1213
import scala.tools.nsc.settings.ScalaVersion
1314

@@ -195,6 +196,8 @@ abstract class ExplicitOuter extends InfoTransform
195196

196197
/** The first outer selection from currently transformed tree.
197198
* The result is typed but not positioned.
199+
*
200+
* Will return `EmptyTree` if there is no outer accessor because of a premature self reference.
198201
*/
199202
protected def outerValue: Tree =
200203
if (outerParam != NoSymbol) ID(outerParam)
@@ -204,25 +207,34 @@ abstract class ExplicitOuter extends InfoTransform
204207
* The result is typed but not positioned.
205208
* If the outer access is from current class and current class is final
206209
* take outer field instead of accessor
210+
*
211+
* Will return `EmptyTree` if there is no outer accessor because of a premature self reference.
207212
*/
208213
private def outerSelect(base: Tree): Tree = {
209-
val outerAcc = outerAccessor(base.tpe.typeSymbol.toInterface)
210-
val currentClass = this.currentClass //todo: !!! if this line is removed, we get a build failure that protected$currentClass need an override modifier
211-
// outerFld is the $outer field of the current class, if the reference can
212-
// use it (i.e. reference is allowed to be of the form this.$outer),
213-
// otherwise it is NoSymbol
214-
val outerFld =
215-
if (outerAcc.owner == currentClass &&
214+
val baseSym = base.tpe.typeSymbol.toInterface
215+
val outerAcc = outerAccessor(baseSym)
216+
if (outerAcc == NoSymbol && baseSym.ownersIterator.exists(isUnderConstruction)) {
217+
// e.g neg/t6666.scala
218+
// The caller will report the error with more information.
219+
EmptyTree
220+
} else {
221+
val currentClass = this.currentClass //todo: !!! if this line is removed, we get a build failure that protected$currentClass need an override modifier
222+
// outerFld is the $outer field of the current class, if the reference can
223+
// use it (i.e. reference is allowed to be of the form this.$outer),
224+
// otherwise it is NoSymbol
225+
val outerFld =
226+
if (outerAcc.owner == currentClass &&
216227
base.tpe =:= currentClass.thisType &&
217228
outerAcc.owner.isEffectivelyFinal)
218-
outerField(currentClass) suchThat (_.owner == currentClass)
219-
else
220-
NoSymbol
221-
val path =
222-
if (outerFld != NoSymbol) Select(base, outerFld)
223-
else Apply(Select(base, outerAcc), Nil)
224-
225-
localTyper typed path
229+
outerField(currentClass) suchThat (_.owner == currentClass)
230+
else
231+
NoSymbol
232+
val path =
233+
if (outerFld != NoSymbol) Select(base, outerFld)
234+
else Apply(Select(base, outerAcc), Nil)
235+
236+
localTyper typed path
237+
}
226238
}
227239

228240
/** The path
@@ -237,6 +249,17 @@ abstract class ExplicitOuter extends InfoTransform
237249
else outerPath(outerSelect(base), from.outerClass, to)
238250
}
239251

252+
253+
/** The stack of class symbols in which a call to this() or to the super
254+
* constructor, or early definition is active
255+
*/
256+
protected def isUnderConstruction(clazz: Symbol) = selfOrSuperCalls contains clazz
257+
protected val selfOrSuperCalls = mutable.Stack[Symbol]()
258+
@inline protected def inSelfOrSuperCall[A](sym: Symbol)(a: => A) = {
259+
selfOrSuperCalls push sym
260+
try a finally selfOrSuperCalls.pop()
261+
}
262+
240263
override def transform(tree: Tree): Tree = {
241264
val savedOuterParam = outerParam
242265
try {
@@ -250,7 +273,10 @@ abstract class ExplicitOuter extends InfoTransform
250273
}
251274
case _ =>
252275
}
253-
super.transform(tree)
276+
if ((treeInfo isSelfOrSuperConstrCall tree) || (treeInfo isEarlyDef tree))
277+
inSelfOrSuperCall(currentOwner.owner)(super.transform(tree))
278+
else
279+
super.transform(tree)
254280
}
255281
finally outerParam = savedOuterParam
256282
}
@@ -316,7 +342,8 @@ abstract class ExplicitOuter extends InfoTransform
316342

317343
/** The definition tree of the outer accessor of current class
318344
*/
319-
def outerFieldDef: Tree = VAL(outerField(currentClass)) === EmptyTree
345+
def outerFieldDef: Tree =
346+
VAL(outerField(currentClass)) === EmptyTree
320347

321348
/** The definition tree of the outer accessor of current class
322349
*/
@@ -396,6 +423,9 @@ abstract class ExplicitOuter extends InfoTransform
396423
val clazz = sym.owner
397424
val vparamss1 =
398425
if (isInner(clazz)) { // (4)
426+
if (isUnderConstruction(clazz.outerClass)) {
427+
reporter.error(tree.pos, s"Implementation restriction: ${clazz.fullLocationString} requires premature access to ${clazz.outerClass}.")
428+
}
399429
val outerParam =
400430
sym.newValueParameter(nme.OUTER, sym.pos) setInfo clazz.outerClass.thisType
401431
((ValDef(outerParam) setType NoType) :: vparamss.head) :: vparamss.tail

src/compiler/scala/tools/nsc/transform/LambdaLift.scala

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ abstract class LambdaLift extends InfoTransform {
317317
else searchIn(currentOwner)
318318
}
319319

320-
private def memberRef(sym: Symbol) = {
320+
private def memberRef(sym: Symbol): Tree = {
321321
val clazz = sym.owner.enclClass
322322
//Console.println("memberRef from "+currentClass+" to "+sym+" in "+clazz)
323323
def prematureSelfReference() {
@@ -331,12 +331,17 @@ abstract class LambdaLift extends InfoTransform {
331331
if (clazz == currentClass) gen.mkAttributedThis(clazz)
332332
else {
333333
sym resetFlag (LOCAL | PRIVATE)
334-
if (selfOrSuperCalls exists (_.owner == clazz)) {
334+
if (isUnderConstruction(clazz)) {
335335
prematureSelfReference()
336336
EmptyTree
337337
}
338338
else if (clazz.isStaticOwner) gen.mkAttributedQualifier(clazz.thisType)
339-
else outerPath(outerValue, currentClass.outerClass, clazz)
339+
else {
340+
outerValue match {
341+
case EmptyTree => prematureSelfReference(); return EmptyTree
342+
case o => outerPath(o, currentClass.outerClass, clazz)
343+
}
344+
}
340345
}
341346
Select(qual, sym) setType sym.tpe
342347
}
@@ -533,25 +538,13 @@ abstract class LambdaLift extends InfoTransform {
533538

534539
private def preTransform(tree: Tree) = super.transform(tree) setType lifted(tree.tpe)
535540

536-
/** The stack of constructor symbols in which a call to this() or to the super
537-
* constructor is active.
538-
*/
539-
private val selfOrSuperCalls = mutable.Stack[Symbol]()
540-
@inline private def inSelfOrSuperCall[A](sym: Symbol)(a: => A) = try {
541-
selfOrSuperCalls push sym
542-
a
543-
} finally selfOrSuperCalls.pop()
544-
545541
override def transform(tree: Tree): Tree = tree match {
546542
case Select(ReferenceToBoxed(idt), elem) if elem == nme.elem =>
547543
postTransform(preTransform(idt), isBoxedRef = false)
548544
case ReferenceToBoxed(idt) =>
549545
postTransform(preTransform(idt), isBoxedRef = true)
550546
case _ =>
551-
def transformTree = postTransform(preTransform(tree))
552-
if (treeInfo isSelfOrSuperConstrCall tree)
553-
inSelfOrSuperCall(currentOwner)(transformTree)
554-
else transformTree
547+
postTransform(preTransform(tree))
555548
}
556549

557550
/** Transform statements and add lifted definitions to them. */

src/compiler/scala/tools/nsc/typechecker/Namers.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,12 @@ trait Namers extends MethodSynthesis {
132132
def setPrivateWithin(tree: MemberDef, sym: Symbol): Symbol =
133133
setPrivateWithin(tree, sym, tree.mods)
134134

135-
def inConstructorFlag: Long =
136-
if (owner.isConstructor && !context.inConstructorSuffix || owner.isEarlyInitialized) INCONSTRUCTOR
137-
else 0l
135+
def inConstructorFlag: Long = {
136+
val termOwnedContexts: List[Context] = context.enclosingContextChain.takeWhile(_.owner.isTerm)
137+
val constructorNonSuffix = termOwnedContexts exists (c => c.owner.isConstructor && !c.inConstructorSuffix)
138+
val earlyInit = termOwnedContexts exists (_.owner.isEarlyInitialized)
139+
if (constructorNonSuffix || earlyInit) INCONSTRUCTOR else 0L
140+
}
138141

139142
def moduleClassFlags(moduleFlags: Long) =
140143
(moduleFlags & ModuleToClassFlags) | inConstructorFlag
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package scala.reflect
2+
package internal
3+
4+
import ClassfileConstants._
5+
6+
trait PrivateWithin {
7+
self: SymbolTable =>
8+
9+
def importPrivateWithinFromJavaFlags(sym: Symbol, jflags: Int): Symbol = {
10+
if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)) == 0)
11+
// See ticket #1687 for an example of when topLevelClass is NoSymbol: it
12+
// apparently occurs when processing v45.3 bytecode.
13+
if (sym.enclosingTopLevelClass != NoSymbol)
14+
sym.privateWithin = sym.enclosingTopLevelClass.owner
15+
16+
// protected in java means package protected. #3946
17+
if ((jflags & JAVA_ACC_PROTECTED) != 0)
18+
if (sym.enclosingTopLevelClass != NoSymbol)
19+
sym.privateWithin = sym.enclosingTopLevelClass.owner
20+
21+
sym
22+
}
23+
}

src/reflect/scala/reflect/internal/SymbolTable.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ abstract class SymbolTable extends macros.Universe
3939
with StdAttachments
4040
with StdCreators
4141
with BuildUtils
42+
with PrivateWithin
4243
{
4344

4445
val gen = new TreeGen { val global: SymbolTable.this.type = SymbolTable.this }

src/reflect/scala/reflect/internal/Symbols.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2558,7 +2558,9 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
25582558
}
25592559

25602560
override def outerSource: Symbol =
2561-
if (originalName == nme.OUTER) initialize.referenced
2561+
// SI-6888 Approximate the name to workaround the deficiencies in `nme.originalName`
2562+
// in the face of clases named '$'. SI-2806 remains open to address the deeper problem.
2563+
if (originalName endsWith (nme.OUTER)) initialize.referenced
25622564
else NoSymbol
25632565

25642566
def setModuleClass(clazz: Symbol): TermSymbol = {
@@ -2921,6 +2923,7 @@ trait Symbols extends api.Symbols { self: SymbolTable =>
29212923
final override def isNonClassType = false
29222924
final override def isAbstractType = false
29232925
final override def isAliasType = false
2926+
final override def isContravariant = false
29242927

29252928
override def isAbstractClass = this hasFlag ABSTRACT
29262929
override def isCaseClass = this hasFlag CASE

src/reflect/scala/reflect/runtime/JavaMirrors.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
679679
/** used to avoid cycles while initializing classes */
680680
private var parentsLevel = 0
681681
private var pendingLoadActions: List[() => Unit] = Nil
682+
private val relatedSymbols = clazz +: (if (module != NoSymbol) List(module, module.moduleClass) else Nil)
682683

683684
override def load(sym: Symbol): Unit = {
684685
debugInfo("completing from Java " + sym + "/" + clazz.fullName)//debug
@@ -690,6 +691,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
690691
module.moduleClass setFlag (flags & PRIVATE | JAVA)
691692
}
692693

694+
relatedSymbols foreach (importPrivateWithinFromJavaFlags(_, jclazz.getModifiers))
693695
copyAnnotations(clazz, jclazz)
694696
// to do: annotations to set also for module?
695697

@@ -1095,6 +1097,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
10951097
.newValue(newTermName(jfield.getName), NoPosition, toScalaFieldFlags(jfield.getModifiers))
10961098
.setInfo(typeToScala(jfield.getGenericType))
10971099
fieldCache enter (jfield, field)
1100+
importPrivateWithinFromJavaFlags(field, jfield.getModifiers)
10981101
copyAnnotations(field, jfield)
10991102
field
11001103
}
@@ -1120,6 +1123,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
11201123
val paramtpes = jmeth.getGenericParameterTypes.toList map typeToScala
11211124
val resulttpe = typeToScala(jmeth.getGenericReturnType)
11221125
setMethType(meth, tparams, paramtpes, resulttpe)
1126+
importPrivateWithinFromJavaFlags(meth, jmeth.getModifiers)
11231127
copyAnnotations(meth, jmeth)
11241128
if ((jmeth.getModifiers & JAVA_ACC_VARARGS) != 0) meth.setInfo(arrayToRepeated(meth.info))
11251129
meth
@@ -1143,6 +1147,7 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
11431147
val paramtpes = jconstr.getGenericParameterTypes.toList map typeToScala
11441148
setMethType(constr, tparams, paramtpes, clazz.tpe_*)
11451149
constr setInfo GenPolyType(tparams, MethodType(clazz.newSyntheticValueParams(paramtpes), clazz.tpe))
1150+
importPrivateWithinFromJavaFlags(constr, jconstr.getModifiers)
11461151
copyAnnotations(constr, jconstr)
11471152
constr
11481153
}

test/files/neg/t6666.check

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,22 @@ t6666.scala:54: error: Implementation restriction: access of value x$7 in class
1616
t6666.scala:58: error: Implementation restriction: access of method x$8 in class C3 from anonymous class 9, would require illegal premature access to the unconstructed `this` of class C3
1717
F.hof(() => x)
1818
^
19-
t6666.scala:62: error: Implementation restriction: access of method x$9 in class C4 from object Nested$5, would require illegal premature access to the unconstructed `this` of class C4
19+
t6666.scala:62: error: Implementation restriction: access of method x$9 in class C4 from object Nested$4, would require illegal premature access to the unconstructed `this` of class C4
2020
object Nested { def xx = x}
2121
^
22-
t6666.scala:68: error: Implementation restriction: access of method x$10 in class C5 from object Nested$6, would require illegal premature access to the unconstructed `this` of class C5
23-
object Nested { def xx = x}
24-
^
25-
t6666.scala:83: error: Implementation restriction: access of method x$12 in class C11 from anonymous class 12, would require illegal premature access to the unconstructed `this` of class C11
22+
t6666.scala:76: error: Implementation restriction: access of method x$11 in class C11 from anonymous class 12, would require illegal premature access to the unconstructed `this` of class C11
2623
F.byname(x)
2724
^
28-
t6666.scala:102: error: Implementation restriction: access of method x$13 in class C13 from anonymous class 13, would require illegal premature access to the unconstructed `this` of class C13
25+
t6666.scala:95: error: Implementation restriction: access of method x$12 in class C13 from anonymous class 13, would require illegal premature access to the unconstructed `this` of class C13
2926
F.hof(() => x)
3027
^
31-
t6666.scala:111: error: Implementation restriction: access of method x$14 in class C14 from object Nested$7, would require illegal premature access to the unconstructed `this` of class C14
28+
t6666.scala:104: error: Implementation restriction: access of method x$13 in class C14 from object Nested$5, would require illegal premature access to the unconstructed `this` of class C14
3229
object Nested { def xx = x}
3330
^
34-
t6666.scala:122: error: Implementation restriction: access of method x$15 in class C15 from object Nested$8, would require illegal premature access to the unconstructed `this` of class C15
35-
object Nested { def xx = x}
36-
^
37-
t6666.scala:131: error: Implementation restriction: access of method foo$1 in class COuter from class CInner$1, would require illegal premature access to the unconstructed `this` of class COuter
31+
t6666.scala:112: error: Implementation restriction: access of method foo$1 in class COuter from class CInner$1, would require illegal premature access to the unconstructed `this` of class COuter
3832
class CInner extends C({foo})
3933
^
40-
13 errors found
34+
t6666.scala:118: error: Implementation restriction: access of method x$14 in class CEarly from object Nested$6, would require illegal premature access to the unconstructed `this` of class CEarly
35+
object Nested { def xx = x}
36+
^
37+
12 errors found

0 commit comments

Comments
 (0)