1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
package dotty.tools
package dotc
package core
import Types._
import Flags._
import Contexts._
import util.SimpleMap
import reporting._
import printing.{Showable, Printer}
import printing.Texts._
import annotation.elidable
class TyperState(val reporter: Reporter) extends DotClass with Showable {
/** The current constraint set */
def constraint: Constraint = new Constraint(SimpleMap.Empty)
/** The currently uninstantiated TypeVars */
def undetVars: Set[TypeVar] = collection.immutable.ListSet()
/** A map that records for instantiated type vars their instance type.
* Used only in a temporary way for contexts that may be retracted
* without also retracting the type var as a whole.
*/
def instType: SimpleMap[TypeVar, Type] = SimpleMap.Empty
def constraint_=(c: Constraint): Unit = {}
def undetVars_=(vs: Set[TypeVar]): Unit = unsupported("undetVars_=")
def instType_=(m: SimpleMap[TypeVar, Type]): Unit = unsupported("instType_=")
def fresh(isCommittable: Boolean): TyperState = this
def commit()(implicit ctx: Context): Unit = unsupported("commit")
def isCommittable: Boolean = false
@elidable(elidable.FINER)
def checkConsistent(implicit ctx: Context) = ()
@elidable(elidable.FINER)
def enableChecking(b: Boolean): Boolean = true
def withCheckingDisabled[T](op: => T)(implicit ctx: Context): T = op
override def toText(printer: Printer): Text = "ImmutableTyperState"
}
class MutableTyperState(previous: TyperState, reporter: Reporter, override val isCommittable: Boolean)
extends TyperState(reporter) {
private var myConstraint: Constraint = previous.constraint
private var myUndetVars: Set[TypeVar] = previous.undetVars
private var myInstType: SimpleMap[TypeVar, Type] = previous.instType
private var checkingEnabled: Boolean = true
override def constraint = myConstraint
override def undetVars = myUndetVars
override def instType = myInstType
override def constraint_=(c: Constraint) = {
myConstraint = c
checkConsistent()
}
override def undetVars_=(vs: Set[TypeVar]) = {
myUndetVars = vs
checkConsistent()
}
override def instType_=(m: SimpleMap[TypeVar, Type]): Unit = myInstType = m
override def fresh(isCommittable: Boolean): TyperState =
new MutableTyperState(this, new StoreReporter, isCommittable)
/** Commit typer state so that its information is copied into current typer state
* In addition (1) the owning state of undetermined or temporarily instantiated
* type variables changes from this typer state to the current one. (2) Variables
* that were temporarily instantiated in the current typer state are permanently
* instantiated instead.
*/
override def commit()(implicit ctx: Context) = {
checkConsistent
val targetState = ctx.typerState
val prev = targetState.enableChecking(false)
targetState.constraint = constraint
targetState.undetVars = undetVars
targetState.instType = instType
targetState.enableChecking(prev)
def adjustOwningState(tvar: TypeVar) =
if (tvar.owningState eq this) tvar.owningState = targetState
undetVars foreach adjustOwningState
instType foreachKey { tvar =>
adjustOwningState(tvar)
if (tvar.owningState == targetState) {
tvar.inst = instType(tvar)
targetState.instType = targetState.instType remove tvar
}
}
targetState.checkConsistent // !!! DEBUG
reporter.flush()
}
@elidable(elidable.FINER)
def checkConsistent(show: Showable => String = MutableTyperState.toStr): Unit = if (checkingEnabled) {
def err(msg: String, what: Showable) = s"$msg: ${show(what)}\n${show(this)}"
for (tvar <- undetVars)
assert(constraint contains tvar.origin, err("unconstrained type var", tvar.origin))
if (isCommittable) {
val undetParams = undetVars map (_.origin)
for (param <- constraint.domainParams)
assert(undetParams contains param, err("junk constraint on", param))
instType.foreachKey { tvar =>
assert(!(undetVars contains tvar), err("duplicate undetVar and instType", tvar))
}
}
}
@elidable(elidable.FINER)
override def checkConsistent(implicit ctx: Context): Unit = checkConsistent(_.show)
@elidable(elidable.FINER)
override def enableChecking(b: Boolean) = {
val prev = checkingEnabled
checkingEnabled = b
prev
}
override def withCheckingDisabled[T](op: => T)(implicit ctx: Context): T = {
val prev = enableChecking(false)
var thrown = false
try op
catch {
case ex: Throwable =>
thrown = true
throw ex
}
finally {
enableChecking(prev)
if (!thrown) checkConsistent
}
}
override def toText(printer: Printer): Text = {
val header: Text = "Typer state:"
val undetVarsText =
" undetVars: " ~
Text(undetVars map (_.toText(printer)), ", ") ~ "."
val constrainedText =
" constrained types: " ~ constraint.constrainedTypesText(printer) ~ "."
val constraintText =
" constraint: " ~ constraint.constraintText(3, printer)
val instTypeText =
" instType: " ~
Text(instType.map2((k, v) => s"${k.toText(printer)} -> ${v.toText(printer)}"), ", ") ~ "."
Text.lines(List(header, undetVarsText, constrainedText, constraintText, instTypeText))
}
}
object MutableTyperState {
private def toStr(x: Any) = x.toString
}
|