From a45a3e5f573fc5b768fcd0d6be507a0af8fd53cc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 13 Oct 2016 16:51:05 +0200 Subject: [PATCH 1/2] Fix #1590: Eliminate wildcards when approximating a type Fixes #1590. Type variables should never be instantiated to types containing wildcards. --- src/dotty/tools/dotc/core/ConstraintHandling.scala | 6 +++++- tests/pos/i1590.scala | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i1590.scala diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index 3835d553c088..95fa407047c0 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -162,7 +162,8 @@ trait ConstraintHandling { /** Solve constraint set for given type parameter `param`. * If `fromBelow` is true the parameter is approximated by its lower bound, * otherwise it is approximated by its upper bound. However, any occurrences - * of the parameter in a refinement somewhere in the bound are removed. + * of the parameter in a refinement somewhere in the bound are removed. Also + * wildcard types in bounds are approximated by their upper or lower bounds. * (Such occurrences can arise for F-bounded types). * The constraint is left unchanged. * @return the instantiating type @@ -174,6 +175,9 @@ trait ConstraintHandling { def apply(tp: Type) = mapOver { tp match { case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent + case tp: WildcardType => + val bounds = tp.optBounds.orElse(TypeBounds.empty).bounds + if (fromBelow == (variance >= 0)) bounds.lo else bounds.hi case _ => tp } } diff --git a/tests/pos/i1590.scala b/tests/pos/i1590.scala new file mode 100644 index 000000000000..a8f36de459fc --- /dev/null +++ b/tests/pos/i1590.scala @@ -0,0 +1 @@ +case class W[T](seq: Option[Option[T]] = Option.empty) From 5d531ec78173b9524acd3b58485f89099dbe6991 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 13 Oct 2016 18:39:42 +0200 Subject: [PATCH 2/2] Refinement of interpolation direction --- .../tools/dotc/core/ConstraintHandling.scala | 20 ++++++++++++++++++- tests/pos/i1590.scala | 9 +++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/dotty/tools/dotc/core/ConstraintHandling.scala b/src/dotty/tools/dotc/core/ConstraintHandling.scala index 95fa407047c0..0e155b9e1f2a 100644 --- a/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -177,7 +177,25 @@ trait ConstraintHandling { case tp: RefinedType if param occursIn tp.refinedInfo => tp.parent case tp: WildcardType => val bounds = tp.optBounds.orElse(TypeBounds.empty).bounds - if (fromBelow == (variance >= 0)) bounds.lo else bounds.hi + // Try to instantiate the wildcard to a type that is known to conform to it. + // This means: + // If fromBelow is true, we minimize the type overall + // Hence, if variance < 0, pick the maximal safe type: bounds.lo + // (i.e. the whole bounds range is over the type) + // if variance > 0, pick the minimal safe type: bounds.hi + // (i.e. the whole bounds range is under the type) + // if variance == 0, pick bounds.lo anyway (this is arbitrary but in line with + // the principle that we pick the smaller type when in doubt). + // If fromBelow is false, we maximize the type overall and reverse the bounds + // if variance != 0. For variance == 0, we still minimize. + // In summary we pick the bound given by this table: + // + // variance | -1 0 1 + // ------------------------ + // from below | lo lo hi + // from above | hi lo lo + // + if (variance == 0 || fromBelow == (variance < 0)) bounds.lo else bounds.hi case _ => tp } } diff --git a/tests/pos/i1590.scala b/tests/pos/i1590.scala index a8f36de459fc..ab922c21845a 100644 --- a/tests/pos/i1590.scala +++ b/tests/pos/i1590.scala @@ -1 +1,10 @@ case class W[T](seq: Option[Option[T]] = Option.empty) +object W { + def apply[T] = new W[T]() +} + +case class V[T](vv: W[W[T]] = W.apply) +object Test { + W[Int]() + // V[Int]() fails in scalac and dotty: both instantiate the vv-default to W[Nothing] +}