diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 8a0b0f12c167..739aff14d4b2 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -429,6 +429,10 @@ object Types { /** Is this a higher-kinded type lambda with given parameter variances? */ def isDeclaredVarianceLambda: Boolean = false + /** Does this type contain wildcard types? */ + final def containsWildcardTypes(using Context) = + existsPart(_.isInstanceOf[WildcardType], stopAtStatic = true) + // ----- Higher-order combinators ----------------------------------- /** Returns true if there is a part of this type that satisfies predicate `p`. @@ -4461,13 +4465,30 @@ object Types { def instantiate(fromBelow: Boolean)(using Context): Type = instantiateWith(avoidCaptures(TypeComparer.instanceType(origin, fromBelow))) + /** For uninstantiated type variables: the entry in the constraint (either bounds or + * provisional instance value) + */ + private def currentEntry(using Context): Type = ctx.typerState.constraint.entry(origin) + /** For uninstantiated type variables: Is the lower bound different from Nothing? */ - def hasLowerBound(using Context): Boolean = - !ctx.typerState.constraint.entry(origin).loBound.isExactlyNothing + def hasLowerBound(using Context): Boolean = !currentEntry.loBound.isExactlyNothing /** For uninstantiated type variables: Is the upper bound different from Any? */ - def hasUpperBound(using Context): Boolean = - !ctx.typerState.constraint.entry(origin).hiBound.isRef(defn.AnyClass) + def hasUpperBound(using Context): Boolean = !currentEntry.hiBound.isRef(defn.AnyClass) + + /** For uninstantiated type variables: Is the lower bound different from Nothing and + * does it not contain wildcard types? + */ + def hasNonWildcardLowerBound(using Context): Boolean = + val lo = currentEntry.loBound + !lo.isExactlyNothing && !lo.containsWildcardTypes + + /** For uninstantiated type variables: Is the upper bound different from Any and + * does it not contain wildcard types? + */ + def hasNonWildcardUpperBound(using Context): Boolean = + val hi = currentEntry.hiBound + !hi.isRef(defn.AnyClass) && !hi.containsWildcardTypes /** Unwrap to instance (if instantiated) or origin (if not), until result * is no longer a TypeVar diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 59ee126f382d..04a3d3e7493e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -173,12 +173,14 @@ object Inferencing { && ctx.typerState.constraint.contains(tvar) && { val direction = instDirection(tvar.origin) - if direction != 0 then + if minimizeSelected then + if direction <= 0 && tvar.hasNonWildcardLowerBound then + instantiate(tvar, fromBelow = true) + else if direction >= 0 && tvar.hasNonWildcardUpperBound then + instantiate(tvar, fromBelow = false) + // else hold off instantiating unbounded unconstrained variable + else if direction != 0 then instantiate(tvar, fromBelow = direction < 0) - else if minimizeSelected then - if tvar.hasLowerBound then instantiate(tvar, fromBelow = true) - else if tvar.hasUpperBound then instantiate(tvar, fromBelow = false) - else () // hold off instantiating unbounded unconstrained variables else if variance >= 0 && (force.ifBottom == IfBottom.ok || tvar.hasLowerBound) then instantiate(tvar, fromBelow = true) else if variance >= 0 && force.ifBottom == IfBottom.fail then diff --git a/tests/pos/i12247.scala b/tests/pos/i12247.scala new file mode 100644 index 000000000000..b2b522f36044 --- /dev/null +++ b/tests/pos/i12247.scala @@ -0,0 +1,27 @@ +sealed abstract class CtorType +object CtorType { + final class Props extends CtorType + sealed trait Summoner { type CT <: CtorType } + implicit def summonP: Summoner {type CT = Props} = ??? +} + +final case class Builder() { + def build(using ctorType: CtorType.Summoner): Component[ctorType.CT] = ??? +} + +final class Component[CT <: CtorType] + +object Test { + + def assertTypeOf[A](a: => A) = new TestDsl[A] + class TestDsl[A] { + def is[B](implicit ev: A =:= B): Unit = () + } + + type Expect = Component[CtorType.Props] + + assertTypeOf( Builder().build ).is[Expect] // error + + val x = Builder().build + assertTypeOf(x).is[Expect] // ok +}