Skip to content

Commit 08918c2

Browse files
authored
Merge pull request #10205 from dotty-staging/fix-#10123
2 parents 3899b6a + ee631c2 commit 08918c2

File tree

5 files changed

+67
-0
lines changed

5 files changed

+67
-0
lines changed

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,28 @@ object Inferencing {
8181
if (depVars.nonEmpty) instantiateSelected(tp, depVars.toList)
8282
}
8383

84+
/** If `tp` is top-level type variable with a lower bound in the current constraint,
85+
* instantiate it from below. We also look for TypeVars whereever their instantiation
86+
* could uncover new type members.
87+
*/
88+
def couldInstantiateTypeVar(tp: Type)(using Context): Boolean = tp.dealias match
89+
case tvar: TypeVar
90+
if !tvar.isInstantiated
91+
&& ctx.typerState.constraint.contains(tvar)
92+
&& tvar.hasLowerBound =>
93+
tvar.instantiate(fromBelow = true)
94+
true
95+
case AppliedType(tycon, _) =>
96+
couldInstantiateTypeVar(tycon)
97+
case RefinedType(parent, _, _) =>
98+
couldInstantiateTypeVar(parent)
99+
case tp: AndOrType =>
100+
couldInstantiateTypeVar(tp.tp1) || couldInstantiateTypeVar(tp.tp2)
101+
case AnnotatedType(tp, _) =>
102+
couldInstantiateTypeVar(tp)
103+
case _ =>
104+
false
105+
84106
/** The accumulator which forces type variables using the policy encoded in `force`
85107
* and returns whether the type is fully defined. The direction in which
86108
* a type variable is instantiated is determined as follows:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import config.Printers.typr
1212
import ast.Trees._
1313
import NameOps._
1414
import ProtoTypes._
15+
import Inferencing.couldInstantiateTypeVar
1516
import collection.mutable
1617
import reporting._
1718
import Checking.{checkNoPrivateLeaks, checkNoWildcard}
@@ -159,6 +160,9 @@ trait TypeAssigner {
159160
TryDynamicCallType
160161
else if (qualType.isErroneous || name.toTermName == nme.ERROR)
161162
UnspecifiedErrorType
163+
else if couldInstantiateTypeVar(qualType) then
164+
// try again with more defined qualifier type
165+
selectionType(tree, qual1)
162166
else if (name == nme.CONSTRUCTOR)
163167
errorType(ex"$qualType does not have a constructor", tree.srcPos)
164168
else {
File renamed without changes.

tests/pos/i10123.scala

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
class D
2+
class C[+T](x: T)
3+
4+
class Foo() {
5+
val status: Int = 0
6+
}
7+
8+
object Main {
9+
implicit class RichC[T](c: C[T]) {
10+
def await(implicit d: D = ???): T = ???
11+
}
12+
13+
def test1: Int = {
14+
val foo = new C(new Foo()).await
15+
foo.status
16+
}
17+
18+
val test2 = new C(new Foo()).await.status
19+
}

tests/pos/i9567.scala

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// object Test {
2+
// val x: Int => Int = identity
3+
// }
4+
5+
trait Foo[F[_]] {
6+
def foo[G[x] >: F[x]]: G[Unit]
7+
}
8+
9+
trait M[A] {
10+
def bla: Int = 1
11+
def baz(f: Int => Int): Int = f(1)
12+
}
13+
14+
object Test {
15+
def bar(x: Foo[M]): Unit = {
16+
// error: value bla is not a member of G[Unit], where: G is a type variable with constraint >: M and <: [x] =>> Any
17+
x.foo.bla
18+
19+
// error: value bla is not a member of G[Unit], where: G is a type variable with constraint >: M and <: [x] =>> Any
20+
x.foo.baz(x => x)
21+
}
22+
}

0 commit comments

Comments
 (0)