@@ -13,18 +13,31 @@ import config.Config
1313import collection .mutable
1414import java .lang .ref .WeakReference
1515
16- class TyperState (r : Reporter ) extends DotClass with Showable {
16+ class TyperState (previous : TyperState /* | Null */ ) extends DotClass with Showable {
1717
18- /** The current reporter */
19- def reporter = r
18+ private var myReporter =
19+ if (previous == null ) new ConsoleReporter () else previous.reporter
2020
21- /** The current constraint set */
22- def constraint : Constraint =
23- new OrderingConstraint (SimpleMap .Empty , SimpleMap .Empty , SimpleMap .Empty )
24- def constraint_= (c : Constraint )(implicit ctx : Context ): Unit = {}
21+ def reporter : Reporter = myReporter
2522
26- /** The uninstantiated variables */
27- def uninstVars = constraint.uninstVars
23+ /** A fresh type state with the same constraint as this one and the given reporter */
24+ def setReporter (reporter : Reporter ): this .type = { myReporter = reporter; this }
25+
26+ private var myConstraint : Constraint =
27+ if (previous == null ) new OrderingConstraint (SimpleMap .Empty , SimpleMap .Empty , SimpleMap .Empty )
28+ else previous.constraint
29+
30+ def constraint = myConstraint
31+ def constraint_= (c : Constraint )(implicit ctx : Context ) = {
32+ if (Config .debugCheckConstraintsClosed && isGlobalCommittable) c.checkClosed()
33+ myConstraint = c
34+ }
35+
36+ private val previousConstraint =
37+ if (previous == null ) constraint else previous.constraint
38+
39+ private var myEphemeral : Boolean =
40+ if (previous == null ) false else previous.ephemeral
2841
2942 /** The ephemeral flag is set as a side effect if an operation accesses
3043 * the underlying type of a type variable. The reason we need this flag is
@@ -33,8 +46,26 @@ class TyperState(r: Reporter) extends DotClass with Showable {
3346 * check the ephemeral flag; If the flag is set during an operation, the result
3447 * of that operation should not be cached.
3548 */
36- def ephemeral : Boolean = false
37- def ephemeral_= (x : Boolean ): Unit = ()
49+ def ephemeral = myEphemeral
50+ def ephemeral_= (x : Boolean ): Unit = { myEphemeral = x }
51+
52+ private var myIsCommittable = true
53+
54+ def isCommittable = myIsCommittable
55+
56+ def setCommittable (committable : Boolean ): this .type = { this .myIsCommittable = committable; this }
57+
58+ def isGlobalCommittable : Boolean =
59+ isCommittable && (previous == null || previous.isGlobalCommittable)
60+
61+ private var isCommitted = false
62+
63+ /** A fresh typer state with the same constraint as this one. */
64+ def fresh (): TyperState =
65+ new TyperState (this ).setReporter(new StoreReporter (reporter)).setCommittable(isCommittable)
66+
67+ /** The uninstantiated variables */
68+ def uninstVars = constraint.uninstVars
3869
3970 /** Gives for each instantiated type var that does not yet have its `inst` field
4071 * set, the instance value stored in the constraint. Storing instances in constraints
@@ -49,76 +80,36 @@ class TyperState(r: Reporter) extends DotClass with Showable {
4980 case tp => tp
5081 }
5182
52- /** A fresh typer state with the same constraint as this one.
53- * @param isCommittable The constraint can be committed to an enclosing context.
54- */
55- def fresh (isCommittable : Boolean ): TyperState = this
56-
57- /** A fresh type state with the same constraint as this one and the given reporter */
58- def withReporter (reporter : Reporter ) = new TyperState (reporter)
59-
60- /** Commit state so that it gets propagated to enclosing context */
61- def commit ()(implicit ctx : Context ): Unit = unsupported(" commit" )
62-
6383 /** The closest ancestor of this typer state (including possibly this typer state itself)
6484 * which is not yet committed, or which does not have a parent.
6585 */
66- def uncommittedAncestor : TyperState = this
67-
68- /** Make type variable instances permanent by assigning to `inst` field if
69- * type variable instantiation cannot be retracted anymore. Then, remove
70- * no-longer needed constraint entries.
71- */
72- def gc ()(implicit ctx : Context ): Unit = ()
73-
74- /** Is it allowed to commit this state? */
75- def isCommittable : Boolean = false
76-
77- /** Can this state be transitively committed until the top-level? */
78- def isGlobalCommittable : Boolean = false
79-
80- override def toText (printer : Printer ): Text = " ImmutableTyperState"
81-
82- /** A string showing the hashes of all nested mutable typerstates */
83- def hashesStr : String = " "
84- }
85-
86- class MutableTyperState (previous : TyperState , r : Reporter , override val isCommittable : Boolean )
87- extends TyperState (r) {
88-
89- private var myReporter = r
90-
91- override def reporter = myReporter
92-
93- private val previousConstraint = previous.constraint
94- private var myConstraint : Constraint = previousConstraint
86+ def uncommittedAncestor : TyperState =
87+ if (isCommitted) previous.uncommittedAncestor else this
9588
96- override def constraint = myConstraint
97- override def constraint_= (c : Constraint )(implicit ctx : Context ) = {
98- if (Config .debugCheckConstraintsClosed && isGlobalCommittable) c.checkClosed()
99- myConstraint = c
89+ private var testReporter : StoreReporter = null
90+
91+ /** Test using `op`, restoring typerState to previous state afterwards */
92+ def test (op : => Boolean ): Boolean = {
93+ val savedReporter = myReporter
94+ val savedConstraint = myConstraint
95+ val savedCommittable = myIsCommittable
96+ val savedCommitted = isCommitted
97+ myIsCommittable = false
98+ myReporter =
99+ if (testReporter == null ) new StoreReporter (reporter)
100+ else {
101+ testReporter.reset()
102+ testReporter
103+ }
104+ try op
105+ finally {
106+ myReporter = savedReporter
107+ myConstraint = savedConstraint
108+ myIsCommittable = savedCommittable
109+ isCommitted = savedCommitted
110+ }
100111 }
101112
102- private var myEphemeral : Boolean = previous.ephemeral
103-
104- override def ephemeral = myEphemeral
105- override def ephemeral_= (x : Boolean ): Unit = { myEphemeral = x }
106-
107- override def fresh (isCommittable : Boolean ): TyperState =
108- new MutableTyperState (this , new StoreReporter (reporter), isCommittable)
109-
110- override def withReporter (reporter : Reporter ) =
111- new MutableTyperState (this , reporter, isCommittable)
112-
113- override val isGlobalCommittable =
114- isCommittable &&
115- (! previous.isInstanceOf [MutableTyperState ] || previous.isGlobalCommittable)
116-
117- private var isCommitted = false
118-
119- override def uncommittedAncestor : TyperState =
120- if (isCommitted) previous.uncommittedAncestor else this
121-
122113 /** Commit typer state so that its information is copied into current typer state
123114 * In addition (1) the owning state of undetermined or temporarily instantiated
124115 * type variables changes from this typer state to the current one. (2) Variables
@@ -137,7 +128,7 @@ extends TyperState(r) {
137128 * isApplicableSafe but also for (e.g. erased-lubs.scala) as well as
138129 * many parts of dotty itself.
139130 */
140- override def commit ()(implicit ctx : Context ) = {
131+ def commit ()(implicit ctx : Context ) = {
141132 val targetState = ctx.typerState
142133 assert(isCommittable)
143134 targetState.constraint =
@@ -152,7 +143,11 @@ extends TyperState(r) {
152143 isCommitted = true
153144 }
154145
155- override def gc ()(implicit ctx : Context ): Unit = {
146+ /** Make type variable instances permanent by assigning to `inst` field if
147+ * type variable instantiation cannot be retracted anymore. Then, remove
148+ * no-longer needed constraint entries.
149+ */
150+ def gc ()(implicit ctx : Context ): Unit = {
156151 val toCollect = new mutable.ListBuffer [TypeLambda ]
157152 constraint foreachTypeVar { tvar =>
158153 if (! tvar.inst.exists) {
@@ -170,6 +165,5 @@ extends TyperState(r) {
170165
171166 override def toText (printer : Printer ): Text = constraint.toText(printer)
172167
173- override def hashesStr : String = hashCode.toString + " -> " + previous.hashesStr
174-
168+ def hashesStr : String = hashCode.toString + " -> " + previous.hashesStr
175169}
0 commit comments