Skip to content

Commit 2e3d0fc

Browse files
committed
Temporary fix for the secondary constructor parameters bug
- Insert the parameters of the secondary constructor into the `Objekt` of `thisV`, so that they can be looked up when it is referenced. - Add tests
1 parent 82172ed commit 2e3d0fc

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

compiler/src/dotty/tools/dotc/transform/init/Semantic.scala

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,15 @@ object Semantic {
652652
}
653653

654654
def callConstructor(ctor: Symbol, args: List[ArgInfo], source: Tree): Contextual[Result] = log("call " + ctor.show + ", args = " + args, printer, (_: Result).show) {
655+
// init "fake" param fields for the secondary constructor
656+
def addParamsAsFields(env: Env, ref: Ref, ctorDef: DefDef) = {
657+
val paramSyms = ctorDef.termParamss.flatten.map(_.symbol)
658+
paramSyms.map { acc =>
659+
val value = env.lookup(acc)
660+
ref.updateField(acc, value)
661+
printer.println(acc.show + " initialized with " + value)
662+
}
663+
}
655664
value match {
656665
case Hot | Cold | _: RefSet | _: Fun =>
657666
report.error("unexpected constructor call, meth = " + ctor + ", value = " + value, source)
@@ -668,6 +677,7 @@ object Semantic {
668677
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
669678
init(tpl, ref, cls)
670679
else
680+
addParamsAsFields(env, ref, ddef)
671681
val initCall = ddef.rhs match
672682
case Block(call :: _, _) => call
673683
case call => call
@@ -682,12 +692,13 @@ object Semantic {
682692
given Trace = trace1
683693
val cls = ctor.owner.enclosingClass.asClass
684694
val ddef = ctor.defTree.asInstanceOf[DefDef]
685-
given Env= Env(ddef, args.map(_.value).widenArgs)
695+
given Env = Env(ddef, args.map(_.value).widenArgs)
686696
if ctor.isPrimaryConstructor then
687697
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
688698
val res = withTrace(trace.add(cls.defTree)) { eval(tpl, ref, cls, cacheResult = true) }
689699
Result(ref, res.errors)
690700
else
701+
addParamsAsFields(env, ref, ddef)
691702
eval(ddef.rhs, ref, cls, cacheResult = true)
692703
else if ref.canIgnoreMethodCall(ctor) then
693704
Result(Hot, Nil)
@@ -752,19 +763,26 @@ object Semantic {
752763
Result(value2, errors)
753764
}
754765
}
766+
end extension
767+
768+
extension (ref: Ref)
755769

756770
def accessLocal(tmref: TermRef, klass: ClassSymbol, source: Tree): Contextual[Result] =
757771
val sym = tmref.symbol
758772

759773
def default() = Result(Hot, Nil)
760774

761775
if sym.is(Flags.Param) && sym.owner.isConstructor then
776+
// if we can get the field from the Ref (which can only possibly be
777+
// a secondary constructor parameter), then use it.
778+
if (ref.objekt.hasField(sym))
779+
Result(ref.objekt.field(sym), Errors.empty)
762780
// instances of local classes inside secondary constructors cannot
763781
// reach here, as those values are abstracted by Cold instead of Warm.
764782
// This enables us to simplify the domain without sacrificing
765783
// expressiveness nor soundess, as local classes inside secondary
766784
// constructors are uncommon.
767-
if sym.isContainedIn(klass) then
785+
else if sym.isContainedIn(klass) then
768786
Result(env.lookup(sym), Nil)
769787
else
770788
// We don't know much about secondary constructor parameters in outer scope.
@@ -777,7 +795,7 @@ object Semantic {
777795
case vdef: ValDef =>
778796
// resolve this for local variable
779797
val enclosingClass = sym.owner.enclosingClass.asClass
780-
val thisValue2 = resolveThis(enclosingClass, value, klass, source)
798+
val thisValue2 = resolveThis(enclosingClass, ref, klass, source)
781799
thisValue2 match {
782800
case Hot => Result(Hot, Errors.empty)
783801

@@ -792,10 +810,7 @@ object Semantic {
792810

793811
case _ => default()
794812
}
795-
end extension
796-
797-
// ----- Promotion ----------------------------------------------------
798-
extension (ref: Ref)
813+
// ----- Promotion ----------------------------------------------------
799814
/** Whether the object is fully assigned
800815
*
801816
* It means all fields and outers are set. For performance, we don't check
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
class A(b: B) {
3+
def this(b: B, m: Int) = {
4+
this(b)
5+
def foo = m // resolved to parameter `m`
6+
class C { foo } // resolved to parameter `m`, as hidden field of `A`
7+
new C
8+
}
9+
}
10+
11+
class D(b: B) extends A(b, 10) {
12+
val n = 10
13+
}
14+
15+
class B {
16+
val a = new D(this)
17+
}

0 commit comments

Comments
 (0)