aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-09-18 17:51:45 +0200
committerMartin Odersky <odersky@gmail.com>2015-09-18 17:51:45 +0200
commit22a2c79adf3acb8b5dd341b552e499bced58c537 (patch)
treef5fc61bf452b2d1b7ef79a2846e8c3fb55325e06
parent7f983665985d93c735d519f7d24d9ba072b26cd4 (diff)
downloaddotty-22a2c79adf3acb8b5dd341b552e499bced58c537.tar.gz
dotty-22a2c79adf3acb8b5dd341b552e499bced58c537.tar.bz2
dotty-22a2c79adf3acb8b5dd341b552e499bced58c537.zip
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.
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala57
-rw-r--r--tests/pos/i739.scala7
2 files changed, 42 insertions, 22 deletions
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index a5cf8c4eb..0a76f45c5 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -17,6 +17,7 @@ import Decorators._
import Uniques._
import ErrorReporting.{errorType, DiagnosticString}
import config.Printers._
+import annotation.tailrec
import collection.mutable
trait Inferencing { this: Checking =>
@@ -115,32 +116,44 @@ trait Inferencing { this: Checking =>
res
}
}
-
- /** If `tree`'s type is of the form
- *
- * e [T1, ..., Tn] (ps1)...(psn)
- *
- * the list of uninstantiated type variables matching one of `T1`, ..., `Tn`
- * which also appear in one of the parameter sections `ps1`, ..., `psn`, otherwise Nil.
+
+ /** The list of uninstantiated type variables bound by some prefix of type `T` which
+ * occur in at least one formal parameter type of a prefix application.
+ * Considered prefixes are:
+ * - The function `f` of an application node `f(e1, .., en)`
+ * - The function `f` of a type application node `f[T1, ..., Tn]`
+ * - The prefix `p` of a selection `p.f`.
+ * - The result expression `e` of a block `{s1; .. sn; e}`.
*/
def tvarsInParams(tree: Tree)(implicit ctx: Context): List[TypeVar] = {
- def occursInParam(mtp: Type, tvar: TypeVar, secCount: Int): Boolean = mtp match {
- case mtp: MethodType =>
- secCount > 0 && (
- mtp.paramTypes.exists(tvar.occursIn) ||
- occursInParam(mtp.resultType, tvar, secCount - 1))
- case _ => false
- }
- def collect(tree: Tree, secCount: Int): List[TypeVar] = tree match {
- case Apply(fn, _) => collect(fn, secCount + 1)
- case TypeApply(_, targs) =>
- targs.tpes.collect {
- case tvar: TypeVar
- if !tvar.isInstantiated && occursInParam(tree.tpe, tvar, secCount) => tvar
+ @tailrec def boundVars(tree: Tree, acc: List[TypeVar]): List[TypeVar] = tree match {
+ case Apply(fn, _) => boundVars(fn, acc)
+ case TypeApply(fn, targs) =>
+ val tvars = targs.tpes.collect {
+ case tvar: TypeVar if !tvar.isInstantiated => tvar
}
- case _ => Nil
+ boundVars(fn, acc ::: tvars)
+ case Select(pre, _) => boundVars(pre, acc)
+ case Block(_, expr) => boundVars(expr, acc)
+ case _ => acc
}
- collect(tree, 0)
+ @tailrec def occurring(tree: Tree, toTest: List[TypeVar], acc: List[TypeVar]): List[TypeVar] =
+ if (toTest.isEmpty) acc
+ else tree match {
+ case Apply(fn, _) =>
+ fn.tpe match {
+ case mtp: MethodType =>
+ val (occ, nocc) = toTest.partition(tvar => mtp.paramTypes.exists(tvar.occursIn))
+ occurring(fn, nocc, occ ::: acc)
+ case _ =>
+ occurring(fn, toTest, acc)
+ }
+ case TypeApply(fn, targs) => occurring(fn, toTest, acc)
+ case Select(pre, _) => occurring(pre, toTest, acc)
+ case Block(_, expr) => occurring(expr, toTest, acc)
+ case _ => acc
+ }
+ occurring(tree, boundVars(tree, Nil), Nil)
}
/** The instantiation direction for given poly param computed
diff --git a/tests/pos/i739.scala b/tests/pos/i739.scala
index 340478f4f..61fed4e5d 100644
--- a/tests/pos/i739.scala
+++ b/tests/pos/i739.scala
@@ -3,8 +3,15 @@ class Foo
object Test {
def foo[T](x: T)(implicit ev: T): T = ???
+ class Fn[T] {
+ def invoke(implicit ev: T): T = ???
+ }
+
+ def bar[T](x: T): Fn[T] = ???
+
def test: Unit = {
implicit val evidence: Foo = new Foo
foo(new Foo)
+ bar(new Foo).invoke
}
}