Skip to content

Commit 0edd835

Browse files
committed
Remove Env
We only use it to pass constructor arguments. As now we store constructor arguments on the underlying object, there no need for it any more.
1 parent f58c158 commit 0edd835

File tree

1 file changed

+25
-82
lines changed

1 file changed

+25
-82
lines changed

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

Lines changed: 25 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -144,56 +144,6 @@ object Semantic:
144144

145145
def hasField(f: Symbol) = fields.contains(f)
146146

147-
/** The environment stores values for constructor parameters
148-
*
149-
* For performance and usability, we restrict parameters to be either `Cold`
150-
* or `Hot`.
151-
*
152-
* Despite that we have environment for evaluating expressions in secondary
153-
* constructors, we don't need to put environment as the cache key. The
154-
* reason is that constructor parameters are determined by the value of
155-
* `this` --- it suffices to make the value of `this` as part of the cache
156-
* key.
157-
*
158-
* This crucially depends on the fact that in the initialization process
159-
* there can be exactly one call to a specific constructor for a given
160-
* receiver. However, once we relax the design to allow non-hot values to
161-
* methods and functions, we have to put the environment as part of the cache
162-
* key. The reason is that given the same receiver, a method or function may
163-
* be called with different arguments -- they are not decided by the receiver
164-
* anymore.
165-
*
166-
* TODO: remove Env as it is only used to pass value from `callConstructor` -> `eval` -> `init`.
167-
* It goes through `eval` for caching (termination) purposes.
168-
*/
169-
object Env:
170-
opaque type Env = Map[Symbol, Value]
171-
172-
val empty: Env = Map.empty
173-
174-
def apply(bindings: Map[Symbol, Value]): Env = bindings
175-
176-
def apply(ddef: DefDef, args: List[Value])(using Context): Env =
177-
val params = ddef.termParamss.flatten.map(_.symbol)
178-
assert(args.size == params.size, "arguments = " + args.size + ", params = " + params.size)
179-
params.zip(args).toMap
180-
181-
extension (env: Env)
182-
def lookup(sym: Symbol)(using Context): Value = env(sym)
183-
184-
def getOrElse(sym: Symbol, default: Value)(using Context): Value = env.getOrElse(sym, default)
185-
186-
def union(other: Env): Env = env ++ other
187-
188-
def isHot: Boolean = env.values.forall(_ == Hot)
189-
end Env
190-
191-
type Env = Env.Env
192-
inline def env(using env: Env) = env
193-
inline def withEnv[T](env: Env)(op: Env ?=> T): T = op(using env)
194-
195-
import Env.*
196-
197147
object Promoted:
198148
class PromotionInfo:
199149
var isCurrentObjectPromoted: Boolean = false
@@ -399,7 +349,7 @@ object Semantic:
399349
// ----- Checker State -----------------------------------
400350

401351
/** The state that threads through the interpreter */
402-
type Contextual[T] = (Env, Context, Trace, Promoted, Cache, Reporter) ?=> T
352+
type Contextual[T] = (Context, Trace, Promoted, Cache, Reporter) ?=> T
403353

404354
// ----- Error Handling -----------------------------------
405355

@@ -692,10 +642,8 @@ object Semantic:
692642
outer.instantiate(klass, klass.primaryConstructor, args)
693643
else
694644
reporter.reportAll(argErrors)
695-
withEnv(if isLocal then env else Env.empty) {
696-
extendTrace(ddef) {
697-
eval(ddef.rhs, ref, cls, cacheResult = true)
698-
}
645+
extendTrace(ddef) {
646+
eval(ddef.rhs, ref, cls, cacheResult = true)
699647
}
700648
else if ref.canIgnoreMethodCall(target) then
701649
Hot
@@ -726,15 +674,14 @@ object Semantic:
726674
}
727675

728676
def callConstructor(ctor: Symbol, args: List[ArgInfo]): Contextual[Value] = log("call " + ctor.show + ", args = " + args.map(_.value.show), printer, (_: Value).show) {
729-
// init "fake" param fields for the secondary constructor
730-
def addParamsAsFields(env: Env, ref: Ref, ctorDef: DefDef) = {
731-
val paramSyms = ctorDef.termParamss.flatten.map(_.symbol)
732-
paramSyms.map { acc =>
733-
val value = env.lookup(acc)
734-
ref.updateField(acc, value)
735-
printer.println(acc.show + " initialized with " + value)
736-
}
737-
}
677+
// init "fake" param fields for parameters of primary and secondary constructors
678+
def addParamsAsFields(args: List[Value], ref: Ref, ctorDef: DefDef) =
679+
val params = ctorDef.termParamss.flatten.map(_.symbol)
680+
assert(args.size == params.size, "arguments = " + args.size + ", params = " + params.size)
681+
for (param, value) <- params.zip(args) do
682+
ref.updateField(param, value)
683+
printer.println(param.show + " initialized with " + value)
684+
738685
value match {
739686
case Hot | Cold | _: RefSet | _: Fun =>
740687
report.error("unexpected constructor call, meth = " + ctor + ", value = " + value, trace.toVector.last)
@@ -744,13 +691,12 @@ object Semantic:
744691
if ctor.hasSource then
745692
val cls = ctor.owner.enclosingClass.asClass
746693
val ddef = ctor.defTree.asInstanceOf[DefDef]
747-
val env2 = Env(ddef, args.map(_.value).widenArgs)
694+
val args2 = args.map(_.value).widenArgs
695+
addParamsAsFields(args2, ref, ddef)
748696
if ctor.isPrimaryConstructor then
749-
given Env = env2
750697
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
751698
extendTrace(cls.defTree) { init(tpl, ref, cls) }
752699
else
753-
addParamsAsFields(env2, ref, ddef)
754700
val initCall = ddef.rhs match
755701
case Block(call :: _, _) => call
756702
case call => call
@@ -763,14 +709,13 @@ object Semantic:
763709
if ctor.hasSource then
764710
val cls = ctor.owner.enclosingClass.asClass
765711
val ddef = ctor.defTree.asInstanceOf[DefDef]
766-
val env2 = Env(ddef, args.map(_.value).widenArgs)
712+
val args2 = args.map(_.value).widenArgs
713+
addParamsAsFields(args2, ref, ddef)
767714
if ctor.isPrimaryConstructor then
768-
given Env = env2
769715
val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
770716
extendTrace(cls.defTree) { eval(tpl, ref, cls, cacheResult = true) }
771717
ref
772718
else
773-
addParamsAsFields(env2, ref, ddef)
774719
extendTrace(ddef) { eval(ddef.rhs, ref, cls, cacheResult = true) }
775720
else if ref.canIgnoreMethodCall(ctor) then
776721
Hot
@@ -1057,16 +1002,18 @@ object Semantic:
10571002
val thisRef = task.value
10581003
val tpl = thisRef.klass.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template]
10591004

1060-
val paramValues = tpl.constr.termParamss.flatten.map(param => param.symbol -> Hot).toMap
1061-
10621005
@tailrec
10631006
def iterate(): Unit = {
10641007
given Promoted = Promoted.empty
10651008
given Trace = Trace.empty.add(thisRef.klass.defTree)
1066-
given Env = Env(paramValues)
10671009
given reporter: Reporter.BufferedReporter = new Reporter.BufferedReporter
10681010

10691011
thisRef.ensureFresh()
1012+
1013+
// set up constructor parameters
1014+
for param <- tpl.constr.termParamss.flatten do
1015+
thisRef.updateField(param.symbol, Hot)
1016+
10701017
log("checking " + task) { eval(tpl, thisRef, thisRef.klass) }
10711018
reporter.errors.foreach(_.issue)
10721019

@@ -1433,7 +1380,7 @@ object Semantic:
14331380
/** Initialize part of an abstract object in `klass` of the inheritance chain */
14341381
def init(tpl: Template, thisV: Ref, klass: ClassSymbol): Contextual[Value] = log("init " + klass.show, printer, (_: Value).show) {
14351382
val paramsMap = tpl.constr.termParamss.flatten.map { vdef =>
1436-
vdef.name -> env.lookup(vdef.symbol)
1383+
vdef.name -> thisV.objekt.field(vdef.symbol)
14371384
}.toMap
14381385

14391386
// init param fields
@@ -1446,7 +1393,7 @@ object Semantic:
14461393
// Tasks is used to schedule super constructor calls.
14471394
// Super constructor calls are delayed until all outers are set.
14481395
type Tasks = mutable.ArrayBuffer[() => Unit]
1449-
def superCall(tref: TypeRef, ctor: Symbol, args: List[ArgInfo], tasks: Tasks)(using Env): Unit =
1396+
def superCall(tref: TypeRef, ctor: Symbol, args: List[ArgInfo], tasks: Tasks): Unit =
14501397
val cls = tref.classSymbol.asClass
14511398
// update outer for super class
14521399
val res = outerValue(tref, thisV, klass)
@@ -1461,7 +1408,7 @@ object Semantic:
14611408
}
14621409

14631410
// parents
1464-
def initParent(parent: Tree, tasks: Tasks)(using Env) =
1411+
def initParent(parent: Tree, tasks: Tasks) =
14651412
parent match
14661413
case tree @ Block(stats, NewExpr(tref, New(tpt), ctor, argss)) => // can happen
14671414
eval(stats, thisV, klass)
@@ -1479,8 +1426,6 @@ object Semantic:
14791426
// see spec 5.1 about "Template Evaluation".
14801427
// https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html
14811428
if !klass.is(Flags.Trait) then
1482-
given Env = Env.empty
1483-
14841429
// outers are set first
14851430
val tasks = new mutable.ArrayBuffer[() => Unit]
14861431

@@ -1526,18 +1471,16 @@ object Semantic:
15261471
// class body
15271472
if thisV.isThisRef || !thisV.asInstanceOf[Warm].isPopulatingParams then tpl.body.foreach {
15281473
case vdef : ValDef if !vdef.symbol.is(Flags.Lazy) && !vdef.rhs.isEmpty =>
1529-
given Env = Env.empty
15301474
val res = eval(vdef.rhs, thisV, klass)
15311475
thisV.updateField(vdef.symbol, res)
15321476
fieldsChanged = true
15331477

15341478
case _: MemberDef =>
15351479

15361480
case tree =>
1537-
if fieldsChanged && thisV.isThisRef then thisV.asInstanceOf[ThisRef].tryPromoteCurrentObject()
1481+
if fieldsChanged && thisV.isThisRef then
1482+
thisV.asInstanceOf[ThisRef].tryPromoteCurrentObject()
15381483
fieldsChanged = false
1539-
1540-
given Env = Env.empty
15411484
eval(tree, thisV, klass)
15421485
}
15431486

0 commit comments

Comments
 (0)