From 493fbbdd6cd0ca7fecd7e34f963563fe58e1f877 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Fri, 18 Sep 2015 17:37:56 +0200 Subject: 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. --- src/dotty/tools/dotc/typer/Inferencing.scala | 44 ++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 6 deletions(-) (limited to 'src/dotty/tools/dotc/typer/Inferencing.scala') diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala index 6c8bf49ef..a5cf8c4eb 100644 --- a/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/src/dotty/tools/dotc/typer/Inferencing.scala @@ -43,6 +43,11 @@ trait Inferencing { this: Checking => if (isFullyDefined(tp, ForceDegree.all)) tp else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $pos") // !!! DEBUG + + /** Instantiate selected type variables `tvars` in type `tp` */ + def instantiateSelected(tp: Type, tvars: List[Type])(implicit ctx: Context): Unit = + new IsFullyDefinedAccumulator(new ForceDegree.Value(tvars.contains)).process(tp) + /** The accumulator which forces type variables using the policy encoded in `force` * and returns whether the type is fully defined. The direction in which * a type variable is instantiated is determined as follows: @@ -73,8 +78,7 @@ trait Inferencing { this: Checking => case _: WildcardType | _: ProtoType => false case tvar: TypeVar if !tvar.isInstantiated => - if (force == ForceDegree.none) false - else { + force.appliesTo(tvar) && { val direction = instDirection(tvar.origin) if (direction != 0) { if (direction > 0) println(s"inst $tvar dir = up") @@ -111,6 +115,33 @@ 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. + */ + 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 + } + case _ => Nil + } + collect(tree, 0) + } /** The instantiation direction for given poly param computed * from the constraint: @@ -293,9 +324,10 @@ trait Inferencing { this: Checking => } /** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */ -@sharable object ForceDegree extends Enumeration { - val none, // don't force type variables - noBottom, // force type variables, fail if forced to Nothing or Null - all = Value // force type variables, don't fail +@sharable object ForceDegree { + class Value(val appliesTo: TypeVar => Boolean) + val none = new Value(_ => false) + val all = new Value(_ => true) + val noBottom = new Value(_ => true) } -- cgit v1.2.3