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
|
package dotty.tools
package dotc
package core
import Types._, Contexts._
import util.SimpleMap
import collection.mutable.ListBuffer
import printing.{Printer, Showable}
import printing.Texts._
/** Constraint over undetermined type parameters
* @param myMap a map from PolyType to the type bounds that constrain the
* polytype's type parameters. A type parameter that does not
* have a constraint is represented by a `NoType` in the corresponding
* array entry.
*/
class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends AnyVal with Showable {
/** Does the constraint's domain contain the type parameters of `pt`? */
def contains(pt: PolyType): Boolean = myMap(pt) != null
/** Does the constraint's domain contain the type parameter `param`? */
def contains(param: PolyParam): Boolean = {
val entries = myMap(param.binder)
entries != null && entries(param.paramNum).exists
}
/** The constraint for given type parameter `param`, or NoType if `param` is not part of
* the constraint domain.
*/
def at(param: PolyParam): Type = {
val entries = myMap(param.binder)
if (entries == null) NoType else entries(param.paramNum)
}
/** The constraint bounds for given type parameter `param`.
* @pre `param` is not part of the constraint domain.
*/
def bounds(param: PolyParam): TypeBounds = at(param).asInstanceOf[TypeBounds]
/** A new constraint which is derived from this constraint by adding or replacing
* the entries corresponding to `pt` with `entries`.
*/
private def updateEntries(pt: PolyType, entries: Array[Type]): Constraint = {
import Constraint._
val res = new Constraint(myMap.updated(pt, entries))
if (res.myMap.size > maxSize) {
maxSize = res.myMap.size
maxConstraint = res
}
res
}
/** A new constraint which is derived from this constraint by updating
* the the entry for parameter `param` to `tpe`.
* @pre `this contains param`.
*/
def updated(param: PolyParam, tpe: Type): Constraint = {
val newEntries = myMap(param.binder).clone
newEntries(param.paramNum) = tpe
updateEntries(param.binder, newEntries)
}
/** A new constraint which is derived from this constraint by mapping
* `op` over all entries of type `poly`.
* @pre `this contains poly`.
*/
def transformed(poly: PolyType, op: Type => Type): Constraint =
updateEntries(poly, myMap(poly) map op)
/** A new constraint which is derived from this constraint by removing
* the type parameter `param` from the domain.
*/
def - (param: PolyParam)(implicit ctx: Context) = {
val pt = param.binder
val pnum = param.paramNum
val entries = myMap(pt)
var noneLeft = true
var i = 0
while (noneLeft && (i < entries.length)) {
noneLeft = (entries(i) eq NoType) || i == pnum
i += 1
}
if (noneLeft) new Constraint(myMap remove pt)
else updated(param, NoType)
}
/** A new constraint which is derived from this constraint by adding
* entries for all type parameters of `poly`.
*/
def +(poly: PolyType) =
updateEntries(poly, poly.paramBounds.toArray[Type])
/** A new constraint which is derived from this constraint by removing
* the type parameter `param` from the domain and replacing all occurrences
* of the parameter elsewhere in the constraint by type `tp`.
*/
def replace(param: PolyParam, tp: Type)(implicit ctx: Context) = {
def subst(entries: Array[Type]) = {
var result = entries
var i = 0
while (i < entries.length) {
entries(i) match {
case oldBounds: TypeBounds =>
val newBounds = oldBounds.substParam(param, tp)
if (oldBounds ne newBounds) {
if (result eq entries) result = entries.clone
result(i) = newBounds
}
case _ =>
}
i += 1
}
result
}
new Constraint((this - param).myMap mapValues subst)
}
def domainPolys: List[PolyType] = myMap.keys
def domainParams: List[PolyParam] =
for {
(poly, entries) <- myMap.toList
n <- 0 until entries.length
if entries(n).exists
} yield PolyParam(poly, n)
def constrainedTypesText(printer: Printer): Text =
Text(domainPolys map (_.toText(printer)), ", ")
def constraintText(indent: Int, printer: Printer): Text = {
val assocs =
for (param <- domainParams)
yield (" " * indent) ~ param.toText(printer) ~ at(param).toText(printer)
Text(assocs, "\n")
}
override def toText(printer: Printer): Text =
"Constraint(" ~ constrainedTypesText(printer) ~ ") {" ~ constraintText(2, printer) ~ "}"
}
object Constraint {
var maxSize = 0
var maxConstraint: Constraint = _
def printMax()(implicit ctx: Context) =
if (maxSize > 0) println(s"max constraint = ${maxConstraint.show}")
}
|