Skip to content

Commit 8532c98

Browse files
committedOct 7, 2015
Merge pull request #799 from dotty-staging/change-inference
Change inference
2 parents a8c8bda + 22a2c79 commit 8532c98

File tree

5 files changed

+122
-16
lines changed

5 files changed

+122
-16
lines changed
 

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

+95-14
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 =>
@@ -43,9 +44,26 @@ trait Inferencing { this: Checking =>
4344
if (isFullyDefined(tp, ForceDegree.all)) tp
4445
else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $pos") // !!! DEBUG
4546

47+
48+
/** Instantiate selected type variables `tvars` in type `tp` */
49+
def instantiateSelected(tp: Type, tvars: List[Type])(implicit ctx: Context): Unit =
50+
new IsFullyDefinedAccumulator(new ForceDegree.Value(tvars.contains)).process(tp)
51+
4652
/** The accumulator which forces type variables using the policy encoded in `force`
47-
* and returns whether the type is fully defined. Two phases:
48-
* 1st Phase: Try to instantiate covariant and non-variant type variables to
53+
* and returns whether the type is fully defined. The direction in which
54+
* a type variable is instantiated is determined as follows:
55+
* 1. T is minimized if the constraint over T is only from below (i.e.
56+
* constrained lower bound != given lower bound and
57+
* constrained upper bound == given upper bound).
58+
* 2. T is maximized if the constraint over T is only from above (i.e.
59+
* constrained upper bound != given upper bound and
60+
* constrained lower bound == given lower bound).
61+
* If (1) and (2) do not apply:
62+
* 3. T is maximized if it appears only contravariantly in the given type.
63+
* 4. T is minimized in all other cases.
64+
*
65+
* The instantiation is done in two phases:
66+
* 1st Phase: Try to instantiate minimizable type variables to
4967
* their lower bound. Record whether successful.
5068
* 2nd Phase: If first phase was successful, instantiate all remaining type variables
5169
* to their upper bound.
@@ -61,14 +79,20 @@ trait Inferencing { this: Checking =>
6179
case _: WildcardType | _: ProtoType =>
6280
false
6381
case tvar: TypeVar if !tvar.isInstantiated =>
64-
if (force == ForceDegree.none) false
65-
else {
66-
val minimize =
67-
variance >= 0 && !(
68-
force == ForceDegree.noBottom &&
69-
isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
70-
if (minimize) instantiate(tvar, fromBelow = true)
71-
else toMaximize = true
82+
force.appliesTo(tvar) && {
83+
val direction = instDirection(tvar.origin)
84+
if (direction != 0) {
85+
if (direction > 0) println(s"inst $tvar dir = up")
86+
instantiate(tvar, direction < 0)
87+
}
88+
else {
89+
val minimize =
90+
variance >= 0 && !(
91+
force == ForceDegree.noBottom &&
92+
isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
93+
if (minimize) instantiate(tvar, fromBelow = true)
94+
else toMaximize = true
95+
}
7296
foldOver(x, tvar)
7397
}
7498
case tp =>
@@ -93,6 +117,62 @@ trait Inferencing { this: Checking =>
93117
}
94118
}
95119

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}`.
127+
*/
128+
def tvarsInParams(tree: Tree)(implicit ctx: Context): List[TypeVar] = {
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
134+
}
135+
boundVars(fn, acc ::: tvars)
136+
case Select(pre, _) => boundVars(pre, acc)
137+
case Block(_, expr) => boundVars(expr, acc)
138+
case _ => acc
139+
}
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)
157+
}
158+
159+
/** The instantiation direction for given poly param computed
160+
* from the constraint:
161+
* @return 1 (maximize) if constraint is uniformly from above,
162+
* -1 (minimize) if constraint is uniformly from below,
163+
* 0 if unconstrained, or constraint is from below and above.
164+
*/
165+
private def instDirection(param: PolyParam)(implicit ctx: Context): Int = {
166+
val constrained = ctx.typerState.constraint.fullBounds(param)
167+
val original = param.binder.paramBounds(param.paramNum)
168+
val cmp = ctx.typeComparer
169+
val approxBelow =
170+
if (!cmp.isSubTypeWhenFrozen(constrained.lo, original.lo)) 1 else 0
171+
val approxAbove =
172+
if (!cmp.isSubTypeWhenFrozen(original.hi, constrained.hi)) 1 else 0
173+
approxAbove - approxBelow
174+
}
175+
96176
def isBottomType(tp: Type)(implicit ctx: Context) =
97177
tp == defn.NothingType || tp == defn.NullType
98178

@@ -257,9 +337,10 @@ trait Inferencing { this: Checking =>
257337
}
258338

259339
/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
260-
@sharable object ForceDegree extends Enumeration {
261-
val none, // don't force type variables
262-
noBottom, // force type variables, fail if forced to Nothing or Null
263-
all = Value // force type variables, don't fail
340+
@sharable object ForceDegree {
341+
class Value(val appliesTo: TypeVar => Boolean)
342+
val none = new Value(_ => false)
343+
val all = new Value(_ => true)
344+
val noBottom = new Value(_ => true)
264345
}
265346

‎src/dotty/tools/dotc/typer/Typer.scala

+2
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13521352
case wtp: ExprType =>
13531353
adaptInterpolated(tree.withType(wtp.resultType), pt, original)
13541354
case wtp: ImplicitMethodType if constrainResult(wtp, followAlias(pt)) =>
1355+
val tvarsToInstantiate = tvarsInParams(tree)
1356+
wtp.paramTypes.foreach(instantiateSelected(_, tvarsToInstantiate))
13551357
val constr = ctx.typerState.constraint
13561358
def addImplicitArgs = {
13571359
def implicitArgError(msg: => String): Tree = {

‎tests/neg/i739.scala

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class Foo[A, B]
2+
class Test {
3+
implicit val f: Foo[Int, String] = ???
4+
def t[A, B >: A](a: A)(implicit f: Foo[A, B]) = ???
5+
t(1) // error
6+
}
7+

‎tests/pos/i739.scala

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class Foo
2+
3+
object Test {
4+
def foo[T](x: T)(implicit ev: T): T = ???
5+
6+
class Fn[T] {
7+
def invoke(implicit ev: T): T = ???
8+
}
9+
10+
def bar[T](x: T): Fn[T] = ???
11+
12+
def test: Unit = {
13+
implicit val evidence: Foo = new Foo
14+
foo(new Foo)
15+
bar(new Foo).invoke
16+
}
17+
}

‎tests/run/liftedTry.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,14 @@ object Test {
1212

1313
foo(try 3 catch handle)
1414

15-
def main(args: Array[String]): Unit = {
15+
def main(args: Array[String]) = {
1616
assert(x == 1)
1717
assert(foo(2) == 2)
1818
assert(foo(try raise(3) catch handle) == 3)
1919
Tr.foo
2020
}
2121
}
2222

23-
2423
object Tr {
2524
def fun(a: Int => Unit) = a(2)
2625
def foo: Int = {

0 commit comments

Comments
 (0)
Please sign in to comment.