aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2015-02-13 11:53:09 +0100
committerDmitry Petrashko <dmitry.petrashko@gmail.com>2015-03-18 11:11:06 +0100
commit93747cdb576d0a2cb17db1d392e1bdb56e8e6049 (patch)
treedd28e66e5a9746bde6fbf1963ec653746678cb56 /src/dotty/tools/dotc
parent32892db46e66b26e378f765b45983cdac3dec573 (diff)
downloaddotty-93747cdb576d0a2cb17db1d392e1bdb56e8e6049.tar.gz
dotty-93747cdb576d0a2cb17db1d392e1bdb56e8e6049.tar.bz2
dotty-93747cdb576d0a2cb17db1d392e1bdb56e8e6049.zip
Stop type inference from creating oprphans.
A tweak in the answer to a fundamental question of inference: When should type variables be instantiated? Example: In a call f [ TVar ] ( g() ) A syntehsied type variable TVar can be instantiated as soon as the call is fully elaborated, but not before - in particular not when typing the nested call `g()`. This is so far achieved by looking at the `owningTree` of a type variable (in the example it would be the call above) and instantiating only if the current tree contains the owning tree. Problem is that this is fragile. If in the meantime the tree was copied, say due to eta-expansion, the contains test will fail. Now this is not a big deal, as long as we instantiate the type variable eventually. But previously that was never done. With the fix we now instantiate type variables also if we have fully elaborated the definition that closest encloses the point where the type variable is created. This is less fragile, as definitions can be compared using their symbols instead of looking at trees.
Diffstat (limited to 'src/dotty/tools/dotc')
-rw-r--r--src/dotty/tools/dotc/core/Types.scala6
-rw-r--r--src/dotty/tools/dotc/typer/Inferencing.scala14
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala4
4 files changed, 19 insertions, 7 deletions
diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala
index 5f30f484e..f113307ef 100644
--- a/src/dotty/tools/dotc/core/Types.scala
+++ b/src/dotty/tools/dotc/core/Types.scala
@@ -2269,8 +2269,12 @@ object Types {
* @param creatorState The typer state in which the variable was created.
* @param owningTree The function part of the TypeApply tree tree that introduces
* the type variable.
+ * @paran owner The current owner if the context where the variable was created.
+ *
+ * `owningTree` and `owner` are used to determine whether a type-variable can be instantiated
+ * at some given point. See `Inferencing#interpolateUndetVars`.
*/
- final class TypeVar(val origin: PolyParam, creatorState: TyperState, val owningTree: untpd.Tree) extends CachedProxyType with ValueType {
+ final class TypeVar(val origin: PolyParam, creatorState: TyperState, val owningTree: untpd.Tree, val owner: Symbol) extends CachedProxyType with ValueType {
/** The permanent instance type of the the variable, or NoType is none is given yet */
private[core] var inst: Type = NoType
diff --git a/src/dotty/tools/dotc/typer/Inferencing.scala b/src/dotty/tools/dotc/typer/Inferencing.scala
index 38c1e49c5..753125e6a 100644
--- a/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -163,10 +163,18 @@ trait Inferencing { this: Checking =>
* If such a variable appears covariantly in type `tp` or does not appear at all,
* approximate it by its lower bound. Otherwise, if it appears contravariantly
* in type `tp` approximate it by its upper bound.
+ * @param ownedBy if it is different from NoSymbol, all type variables owned by
+ * `ownedBy` qualify, independent of position.
+ * Without that second condition, it can be that certain variables escape
+ * interpolation, for instance when their tree was eta-lifted, so
+ * the typechecked tree is no longer the tree in which the variable
+ * was declared. A concrete example of this phenomenon can be
+ * observed when compiling core.TypeOps#asSeenFrom.
*/
- def interpolateUndetVars(tree: Tree)(implicit ctx: Context): Unit = {
+ def interpolateUndetVars(tree: Tree, ownedBy: Symbol)(implicit ctx: Context): Unit = {
val constraint = ctx.typerState.constraint
- val qualifies = (tvar: TypeVar) => tree contains tvar.owningTree
+ val qualifies = (tvar: TypeVar) =>
+ (tree contains tvar.owningTree) || ownedBy.exists && tvar.owner == ownedBy
def interpolate() = Stats.track("interpolateUndetVars") {
val tp = tree.tpe.widen
constr.println(s"interpolate undet vars in ${tp.show}, pos = ${tree.pos}, mode = ${ctx.mode}, undets = ${constraint.uninstVars map (tvar => s"${tvar.show}@${tvar.owningTree.pos}")}")
@@ -182,7 +190,7 @@ trait Inferencing { this: Checking =>
}
}
if (changed) // instantiations might have uncovered new typevars to interpolate
- interpolateUndetVars(tree)
+ interpolateUndetVars(tree, ownedBy)
else
for (tvar <- constraint.uninstVars)
if (!(vs contains tvar) && qualifies(tvar)) {
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index c0e30b12e..f646f7ecd 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -326,7 +326,7 @@ object ProtoTypes {
def newTypeVars(pt: PolyType): List[TypeVar] =
for (n <- (0 until pt.paramNames.length).toList)
- yield new TypeVar(PolyParam(pt, n), state, owningTree)
+ yield new TypeVar(PolyParam(pt, n), state, owningTree, ctx.owner)
val added =
if (state.constraint contains pt) pt.duplicate(pt.paramNames, pt.paramBounds, pt.resultType)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index e98b73cae..d194ccaae 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -1174,8 +1174,8 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context) = /*>|>*/ track("adapt") /*<|<*/ {
/*>|>*/ ctx.traceIndented(i"adapting $tree of type ${tree.tpe} to $pt", typr, show = true) /*<|<*/ {
- interpolateUndetVars(tree)
- tree overwriteType tree.tpe.simplified
+ interpolateUndetVars(tree, if (tree.isDef) tree.symbol else NoSymbol)
+ tree.overwriteType(tree.tpe.simplified)
adaptInterpolated(tree, pt, original)
}
}