@@ -25,10 +25,10 @@ object ForwardDepChecks:
25
25
}
26
26
27
27
/** A class to help in forward reference checking */
28
- class LevelInfo (outerLevelAndIndex : LevelAndIndex , stats : List [Tree ])(using Context )
28
+ class LevelInfo (val outer : OptLevelInfo , val owner : Symbol , stats : List [Tree ])(using Context )
29
29
extends OptLevelInfo {
30
30
override val levelAndIndex : LevelAndIndex =
31
- stats.foldLeft(outerLevelAndIndex , 0 ) {(mi, stat) =>
31
+ stats.foldLeft(outer.levelAndIndex , 0 ) {(mi, stat) =>
32
32
val (m, idx) = mi
33
33
val m1 = stat match {
34
34
case stat : MemberDef => m.updated(stat.symbol, (this , idx))
@@ -71,7 +71,7 @@ class ForwardDepChecks extends MiniPhase:
71
71
72
72
override def prepareForStats (trees : List [Tree ])(using Context ): Context =
73
73
if (ctx.owner.isTerm)
74
- ctx.fresh.updateStore(LevelInfo , new LevelInfo (currentLevel.levelAndIndex , trees))
74
+ ctx.fresh.updateStore(LevelInfo , new LevelInfo (currentLevel, ctx.owner , trees))
75
75
else ctx
76
76
77
77
override def transformValDef (tree : ValDef )(using Context ): ValDef =
@@ -89,19 +89,39 @@ class ForwardDepChecks extends MiniPhase:
89
89
tree
90
90
}
91
91
92
- override def transformApply (tree : Apply )(using Context ): Apply = {
93
- if (isSelfConstrCall(tree)) {
94
- assert(currentLevel.isInstanceOf [LevelInfo ], s " ${ctx.owner}/ " + i " $tree" )
95
- val level = currentLevel.asInstanceOf [LevelInfo ]
96
- if (level.maxIndex > 0 ) {
97
- // An implementation restriction to avoid VerifyErrors and lazyvals mishaps; see SI-4717
98
- report.debuglog(" refsym = " + level.refSym)
99
- report.error(" forward reference not allowed from self constructor invocation" ,
100
- ctx.source.atSpan(level.refSpan))
101
- }
102
- }
92
+ /** Check that self constructor call does not contain references to vals or defs
93
+ * defined later in the secondary constructor's right hand side. This is tricky
94
+ * since the complete self constructor might itself be a block that originated from
95
+ * expanding named and default parameters. In that case we have to go outwards
96
+ * and find the enclosing expression that consists of that block. Test cases in
97
+ * {pos,neg}/complex-self-call.scala.
98
+ */
99
+ private def checkSelfConstructorCall ()(using Context ): Unit =
100
+ // Find level info corresponding to constructor's RHS. This is the info of the
101
+ // outermost LevelInfo that has the constructor as owner.
102
+ def rhsLevelInfo (l : OptLevelInfo ): OptLevelInfo = l match
103
+ case l : LevelInfo if l.owner == ctx.owner =>
104
+ rhsLevelInfo(l.outer) match
105
+ case l1 : LevelInfo => l1
106
+ case _ => l
107
+ case _ =>
108
+ NoLevelInfo
109
+
110
+ rhsLevelInfo(currentLevel) match
111
+ case level : LevelInfo =>
112
+ if level.maxIndex > 0 then
113
+ report.debuglog(" refsym = " + level.refSym.showLocated)
114
+ report.error(" forward reference not allowed from self constructor invocation" ,
115
+ ctx.source.atSpan(level.refSpan))
116
+ case _ =>
117
+ assert(false , s " ${ctx.owner.showLocated}" )
118
+ end checkSelfConstructorCall
119
+
120
+ override def transformApply (tree : Apply )(using Context ): Apply =
121
+ if (isSelfConstrCall(tree))
122
+ assert(ctx.owner.isConstructor)
123
+ checkSelfConstructorCall()
103
124
tree
104
- }
105
125
106
126
override def transformNew (tree : New )(using Context ): New = {
107
127
currentLevel.enterReference(tree.tpe.typeSymbol, tree.span)
0 commit comments