Skip to content

Commit bfd085d

Browse files
committed
Fix scala#8425: Avoid race between erasure and explicit outer
1 parent c6b681c commit bfd085d

File tree

2 files changed

+24
-11
lines changed

2 files changed

+24
-11
lines changed

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -612,7 +612,7 @@ object Erasure {
612612
val restpe =
613613
if (sym.isConstructor) defn.UnitType
614614
else sym.info.resultType
615-
var vparamss1 = (outer.paramDefs(sym) ::: ddef.vparamss.flatten) :: Nil
615+
var vparamss1 = (outerParamDefs(sym) ::: ddef.vparamss.flatten) :: Nil
616616
var rhs1 = ddef.rhs
617617
if (sym.isAnonymousFunction && vparamss1.head.length > MaxImplementedFunctionArity) {
618618
val bunchedParam = ctx.newSymbol(sym, nme.ALLARGS, Flags.TermParam, JavaArrayType(defn.ObjectType))
@@ -635,6 +635,28 @@ object Erasure {
635635
super.typedDefDef(ddef1, sym)
636636
}
637637

638+
/** The outer parameter definition of a constructor if it needs one */
639+
private def outerParamDefs(constr: Symbol)(using ctx: Context): List[ValDef] =
640+
if constr.isConstructor && hasOuterParam(constr.owner.asClass) then
641+
constr.info match
642+
case MethodTpe(outerName :: _, outerType :: _, _) =>
643+
val outerSym = ctx.newSymbol(constr, outerName, Flags.Param, outerType)
644+
ValDef(outerSym) :: Nil
645+
case _ =>
646+
// There's a possible race condition that a constructor was looked at
647+
// after erasure before we had a chance to run ExplicitOuter on its class
648+
// If furthermore the enclosing class does not always have constructors,
649+
// but needs constructors in this particular case, we miss the constructor
650+
// accessor that's produced with an `enteredAfter` in ExplicitOuter, so
651+
// `tranformInfo` of the constructor in erasure yields a method type without
652+
// an outer parameter. We fix this problem by adding the missing outer
653+
// parameter here.
654+
constr.copySymDenotation(
655+
info = outer.addParam(constr.owner.asClass, constr.info)
656+
).installAfter(erasurePhase)
657+
outerParamDefs(constr)
658+
else Nil
659+
638660
override def typedClosure(tree: untpd.Closure, pt: Type)(implicit ctx: Context): Tree = {
639661
val xxl = defn.isXXLFunctionClass(tree.typeOpt.typeSymbol)
640662
var implClosure @ Closure(_, meth, _) = super.typedClosure(tree, pt)

compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ object ExplicitOuter {
240240
needsOuterIfReferenced(cls) && outerAccessor(cls).exists
241241

242242
/** Class constructor takes an outer argument. Can be called only after phase ExplicitOuter. */
243-
private def hasOuterParam(cls: ClassSymbol)(implicit ctx: Context): Boolean =
243+
def hasOuterParam(cls: ClassSymbol)(implicit ctx: Context): Boolean =
244244
!cls.is(Trait) && needsOuterIfReferenced(cls) && outerAccessor(cls).exists
245245

246246
/** Tree references an outer class of `cls` which is not a static owner.
@@ -412,14 +412,5 @@ object ExplicitOuter {
412412
loop(start, count)
413413
catch case ex: ClassCastException =>
414414
throw new ClassCastException(i"no path exists from ${ctx.owner.enclosingClass} to $toCls")
415-
416-
/** The outer parameter definition of a constructor if it needs one */
417-
def paramDefs(constr: Symbol): List[ValDef] =
418-
if (constr.isConstructor && hasOuterParam(constr.owner.asClass)) {
419-
val MethodTpe(outerName :: _, outerType :: _, _) = constr.info
420-
val outerSym = ctx.newSymbol(constr, outerName, Param, outerType)
421-
ValDef(outerSym) :: Nil
422-
}
423-
else Nil
424415
}
425416
}

0 commit comments

Comments
 (0)