Skip to content

Commit 22a2c79

Browse files
committed
Generalize set of typevars instantiated before implicit search
We now also consider type variables in a selection prefix of the application. The test case was augmented to include a snippet which only succeeds under the generalization.
1 parent 7f98366 commit 22a2c79

File tree

2 files changed

+42
-22
lines changed

2 files changed

+42
-22
lines changed

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

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import Decorators._
1717
import Uniques._
1818
import ErrorReporting.{errorType, DiagnosticString}
1919
import config.Printers._
20+
import annotation.tailrec
2021
import collection.mutable
2122

2223
trait Inferencing { this: Checking =>
@@ -115,32 +116,44 @@ trait Inferencing { this: Checking =>
115116
res
116117
}
117118
}
118-
119-
/** If `tree`'s type is of the form
120-
*
121-
* e [T1, ..., Tn] (ps1)...(psn)
122-
*
123-
* the list of uninstantiated type variables matching one of `T1`, ..., `Tn`
124-
* which also appear in one of the parameter sections `ps1`, ..., `psn`, otherwise Nil.
119+
120+
/** The list of uninstantiated type variables bound by some prefix of type `T` which
121+
* occur in at least one formal parameter type of a prefix application.
122+
* Considered prefixes are:
123+
* - The function `f` of an application node `f(e1, .., en)`
124+
* - The function `f` of a type application node `f[T1, ..., Tn]`
125+
* - The prefix `p` of a selection `p.f`.
126+
* - The result expression `e` of a block `{s1; .. sn; e}`.
125127
*/
126128
def tvarsInParams(tree: Tree)(implicit ctx: Context): List[TypeVar] = {
127-
def occursInParam(mtp: Type, tvar: TypeVar, secCount: Int): Boolean = mtp match {
128-
case mtp: MethodType =>
129-
secCount > 0 && (
130-
mtp.paramTypes.exists(tvar.occursIn) ||
131-
occursInParam(mtp.resultType, tvar, secCount - 1))
132-
case _ => false
133-
}
134-
def collect(tree: Tree, secCount: Int): List[TypeVar] = tree match {
135-
case Apply(fn, _) => collect(fn, secCount + 1)
136-
case TypeApply(_, targs) =>
137-
targs.tpes.collect {
138-
case tvar: TypeVar
139-
if !tvar.isInstantiated && occursInParam(tree.tpe, tvar, secCount) => tvar
129+
@tailrec def boundVars(tree: Tree, acc: List[TypeVar]): List[TypeVar] = tree match {
130+
case Apply(fn, _) => boundVars(fn, acc)
131+
case TypeApply(fn, targs) =>
132+
val tvars = targs.tpes.collect {
133+
case tvar: TypeVar if !tvar.isInstantiated => tvar
140134
}
141-
case _ => Nil
135+
boundVars(fn, acc ::: tvars)
136+
case Select(pre, _) => boundVars(pre, acc)
137+
case Block(_, expr) => boundVars(expr, acc)
138+
case _ => acc
142139
}
143-
collect(tree, 0)
140+
@tailrec def occurring(tree: Tree, toTest: List[TypeVar], acc: List[TypeVar]): List[TypeVar] =
141+
if (toTest.isEmpty) acc
142+
else tree match {
143+
case Apply(fn, _) =>
144+
fn.tpe match {
145+
case mtp: MethodType =>
146+
val (occ, nocc) = toTest.partition(tvar => mtp.paramTypes.exists(tvar.occursIn))
147+
occurring(fn, nocc, occ ::: acc)
148+
case _ =>
149+
occurring(fn, toTest, acc)
150+
}
151+
case TypeApply(fn, targs) => occurring(fn, toTest, acc)
152+
case Select(pre, _) => occurring(pre, toTest, acc)
153+
case Block(_, expr) => occurring(expr, toTest, acc)
154+
case _ => acc
155+
}
156+
occurring(tree, boundVars(tree, Nil), Nil)
144157
}
145158

146159
/** The instantiation direction for given poly param computed

tests/pos/i739.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,15 @@ class Foo
33
object Test {
44
def foo[T](x: T)(implicit ev: T): T = ???
55

6+
class Fn[T] {
7+
def invoke(implicit ev: T): T = ???
8+
}
9+
10+
def bar[T](x: T): Fn[T] = ???
11+
612
def test: Unit = {
713
implicit val evidence: Foo = new Foo
814
foo(new Foo)
15+
bar(new Foo).invoke
916
}
1017
}

0 commit comments

Comments
 (0)