Skip to content

Commit 493fbbd

Browse files
committed
Fixes #739
by adding the following rule: Before typing an implicit parameter list of a method m, instantiate all type parameters of m that occur in the type of some preceding value parameter of m.
1 parent 7a97e86 commit 493fbbd

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

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

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ trait Inferencing { this: Checking =>
4343
if (isFullyDefined(tp, ForceDegree.all)) tp
4444
else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $pos") // !!! DEBUG
4545

46+
47+
/** Instantiate selected type variables `tvars` in type `tp` */
48+
def instantiateSelected(tp: Type, tvars: List[Type])(implicit ctx: Context): Unit =
49+
new IsFullyDefinedAccumulator(new ForceDegree.Value(tvars.contains)).process(tp)
50+
4651
/** The accumulator which forces type variables using the policy encoded in `force`
4752
* and returns whether the type is fully defined. The direction in which
4853
* a type variable is instantiated is determined as follows:
@@ -73,8 +78,7 @@ trait Inferencing { this: Checking =>
7378
case _: WildcardType | _: ProtoType =>
7479
false
7580
case tvar: TypeVar if !tvar.isInstantiated =>
76-
if (force == ForceDegree.none) false
77-
else {
81+
force.appliesTo(tvar) && {
7882
val direction = instDirection(tvar.origin)
7983
if (direction != 0) {
8084
if (direction > 0) println(s"inst $tvar dir = up")
@@ -111,6 +115,33 @@ trait Inferencing { this: Checking =>
111115
res
112116
}
113117
}
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.
125+
*/
126+
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
140+
}
141+
case _ => Nil
142+
}
143+
collect(tree, 0)
144+
}
114145

115146
/** The instantiation direction for given poly param computed
116147
* from the constraint:
@@ -293,9 +324,10 @@ trait Inferencing { this: Checking =>
293324
}
294325

295326
/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
296-
@sharable object ForceDegree extends Enumeration {
297-
val none, // don't force type variables
298-
noBottom, // force type variables, fail if forced to Nothing or Null
299-
all = Value // force type variables, don't fail
327+
@sharable object ForceDegree {
328+
class Value(val appliesTo: TypeVar => Boolean)
329+
val none = new Value(_ => false)
330+
val all = new Value(_ => true)
331+
val noBottom = new Value(_ => true)
300332
}
301333

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
13121312
case wtp: ExprType =>
13131313
adaptInterpolated(tree.withType(wtp.resultType), pt, original)
13141314
case wtp: ImplicitMethodType if constrainResult(wtp, followAlias(pt)) =>
1315+
val tvarsToInstantiate = tvarsInParams(tree)
1316+
wtp.paramTypes.foreach(instantiateSelected(_, tvarsToInstantiate))
13151317
val constr = ctx.typerState.constraint
13161318
def addImplicitArgs = {
13171319
def implicitArgError(msg: => String): Tree = {

0 commit comments

Comments
 (0)