@@ -162,7 +162,8 @@ trait ConstraintHandling {
162
162
/** Solve constraint set for given type parameter `param`.
163
163
* If `fromBelow` is true the parameter is approximated by its lower bound,
164
164
* otherwise it is approximated by its upper bound. However, any occurrences
165
- * of the parameter in a refinement somewhere in the bound are removed.
165
+ * of the parameter in a refinement somewhere in the bound are removed. Also
166
+ * wildcard types in bounds are approximated by their upper or lower bounds.
166
167
* (Such occurrences can arise for F-bounded types).
167
168
* The constraint is left unchanged.
168
169
* @return the instantiating type
@@ -174,6 +175,27 @@ trait ConstraintHandling {
174
175
def apply (tp : Type ) = mapOver {
175
176
tp match {
176
177
case tp : RefinedType if param occursIn tp.refinedInfo => tp.parent
178
+ case tp : WildcardType =>
179
+ val bounds = tp.optBounds.orElse(TypeBounds .empty).bounds
180
+ // Try to instantiate the wildcard to a type that is known to conform to it.
181
+ // This means:
182
+ // If fromBelow is true, we minimize the type overall
183
+ // Hence, if variance < 0, pick the maximal safe type: bounds.lo
184
+ // (i.e. the whole bounds range is over the type)
185
+ // if variance > 0, pick the minimal safe type: bounds.hi
186
+ // (i.e. the whole bounds range is under the type)
187
+ // if variance == 0, pick bounds.lo anyway (this is arbitrary but in line with
188
+ // the principle that we pick the smaller type when in doubt).
189
+ // If fromBelow is false, we maximize the type overall and reverse the bounds
190
+ // if variance != 0. For variance == 0, we still minimize.
191
+ // In summary we pick the bound given by this table:
192
+ //
193
+ // variance | -1 0 1
194
+ // ------------------------
195
+ // from below | lo lo hi
196
+ // from above | hi lo lo
197
+ //
198
+ if (variance == 0 || fromBelow == (variance < 0 )) bounds.lo else bounds.hi
177
199
case _ => tp
178
200
}
179
201
}
0 commit comments