@@ -162,7 +162,8 @@ trait ConstraintHandling {
162162 /** Solve constraint set for given type parameter `param`.
163163 * If `fromBelow` is true the parameter is approximated by its lower bound,
164164 * 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.
166167 * (Such occurrences can arise for F-bounded types).
167168 * The constraint is left unchanged.
168169 * @return the instantiating type
@@ -174,6 +175,27 @@ trait ConstraintHandling {
174175 def apply (tp : Type ) = mapOver {
175176 tp match {
176177 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
177199 case _ => tp
178200 }
179201 }
0 commit comments