Skip to content

Commit 0fdd4e3

Browse files
authored
Merge pull request #1592 from dotty-staging/fix-#1590
Fix #1590: Eliminate wildcards when approximating a type
2 parents 009398b + 5d531ec commit 0fdd4e3

File tree

2 files changed

+33
-1
lines changed

2 files changed

+33
-1
lines changed

src/dotty/tools/dotc/core/ConstraintHandling.scala

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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
}

tests/pos/i1590.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
case class W[T](seq: Option[Option[T]] = Option.empty)
2+
object W {
3+
def apply[T] = new W[T]()
4+
}
5+
6+
case class V[T](vv: W[W[T]] = W.apply)
7+
object Test {
8+
W[Int]()
9+
// V[Int]() fails in scalac and dotty: both instantiate the vv-default to W[Nothing]
10+
}

0 commit comments

Comments
 (0)