Skip to content

Commit c9d2826

Browse files
authored
Merge pull request #12294 from dotty-staging/fix-12247
Refrain from instantiating type variables to undetermined types
2 parents 33d15a8 + 5fc0861 commit c9d2826

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,10 @@ object Types {
433433
/** Is this a higher-kinded type lambda with given parameter variances? */
434434
def isDeclaredVarianceLambda: Boolean = false
435435

436+
/** Does this type contain wildcard types? */
437+
final def containsWildcardTypes(using Context) =
438+
existsPart(_.isInstanceOf[WildcardType], stopAtStatic = true)
439+
436440
// ----- Higher-order combinators -----------------------------------
437441

438442
/** Returns true if there is a part of this type that satisfies predicate `p`.
@@ -4465,13 +4469,30 @@ object Types {
44654469
def instantiate(fromBelow: Boolean)(using Context): Type =
44664470
instantiateWith(avoidCaptures(TypeComparer.instanceType(origin, fromBelow)))
44674471

4472+
/** For uninstantiated type variables: the entry in the constraint (either bounds or
4473+
* provisional instance value)
4474+
*/
4475+
private def currentEntry(using Context): Type = ctx.typerState.constraint.entry(origin)
4476+
44684477
/** For uninstantiated type variables: Is the lower bound different from Nothing? */
4469-
def hasLowerBound(using Context): Boolean =
4470-
!ctx.typerState.constraint.entry(origin).loBound.isExactlyNothing
4478+
def hasLowerBound(using Context): Boolean = !currentEntry.loBound.isExactlyNothing
44714479

44724480
/** For uninstantiated type variables: Is the upper bound different from Any? */
4473-
def hasUpperBound(using Context): Boolean =
4474-
!ctx.typerState.constraint.entry(origin).hiBound.isRef(defn.AnyClass)
4481+
def hasUpperBound(using Context): Boolean = !currentEntry.hiBound.isRef(defn.AnyClass)
4482+
4483+
/** For uninstantiated type variables: Is the lower bound different from Nothing and
4484+
* does it not contain wildcard types?
4485+
*/
4486+
def hasNonWildcardLowerBound(using Context): Boolean =
4487+
val lo = currentEntry.loBound
4488+
!lo.isExactlyNothing && !lo.containsWildcardTypes
4489+
4490+
/** For uninstantiated type variables: Is the upper bound different from Any and
4491+
* does it not contain wildcard types?
4492+
*/
4493+
def hasNonWildcardUpperBound(using Context): Boolean =
4494+
val hi = currentEntry.hiBound
4495+
!hi.isRef(defn.AnyClass) && !hi.containsWildcardTypes
44754496

44764497
/** Unwrap to instance (if instantiated) or origin (if not), until result
44774498
* is no longer a TypeVar

compiler/src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,14 @@ object Inferencing {
173173
&& ctx.typerState.constraint.contains(tvar)
174174
&& {
175175
val direction = instDirection(tvar.origin)
176-
if direction != 0 then
176+
if minimizeSelected then
177+
if direction <= 0 && tvar.hasNonWildcardLowerBound then
178+
instantiate(tvar, fromBelow = true)
179+
else if direction >= 0 && tvar.hasNonWildcardUpperBound then
180+
instantiate(tvar, fromBelow = false)
181+
// else hold off instantiating unbounded unconstrained variable
182+
else if direction != 0 then
177183
instantiate(tvar, fromBelow = direction < 0)
178-
else if minimizeSelected then
179-
if tvar.hasLowerBound then instantiate(tvar, fromBelow = true)
180-
else if tvar.hasUpperBound then instantiate(tvar, fromBelow = false)
181-
else () // hold off instantiating unbounded unconstrained variables
182184
else if variance >= 0 && (force.ifBottom == IfBottom.ok || tvar.hasLowerBound) then
183185
instantiate(tvar, fromBelow = true)
184186
else if variance >= 0 && force.ifBottom == IfBottom.fail then

tests/pos/i12247.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
sealed abstract class CtorType
2+
object CtorType {
3+
final class Props extends CtorType
4+
sealed trait Summoner { type CT <: CtorType }
5+
implicit def summonP: Summoner {type CT = Props} = ???
6+
}
7+
8+
final case class Builder() {
9+
def build(using ctorType: CtorType.Summoner): Component[ctorType.CT] = ???
10+
}
11+
12+
final class Component[CT <: CtorType]
13+
14+
object Test {
15+
16+
def assertTypeOf[A](a: => A) = new TestDsl[A]
17+
class TestDsl[A] {
18+
def is[B](implicit ev: A =:= B): Unit = ()
19+
}
20+
21+
type Expect = Component[CtorType.Props]
22+
23+
assertTypeOf( Builder().build ).is[Expect] // error
24+
25+
val x = Builder().build
26+
assertTypeOf(x).is[Expect] // ok
27+
}

0 commit comments

Comments
 (0)