aboutsummaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala6
-rw-r--r--compiler/src/dotty/tools/dotc/transform/Erasure.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Applications.scala35
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Inferencing.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala11
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala4
-rw-r--r--compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala4
8 files changed, 51 insertions, 19 deletions
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 89bc21929..7e6620f8e 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -2862,14 +2862,14 @@ object Types {
*
* @param origin The parameter that's tracked by the type variable.
* @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.
+ * @param bindingTree The TypeTree which introduces the type variable, or EmptyTree
+ * if the type variable does not correspond to a source term.
* @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, val owner: Symbol) extends CachedProxyType with ValueType {
+ final class TypeVar(val origin: PolyParam, creatorState: TyperState, val bindingTree: untpd.Tree, val owner: Symbol) extends CachedProxyType with ValueType {
/** The permanent instance type of the variable, or NoType is none is given yet */
private[core] var inst: Type = NoType
diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
index d1f5bd532..5c880c7bd 100644
--- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
@@ -94,7 +94,7 @@ class Erasure extends Phase with DenotTransformer { thisTransformer =>
assertErased(tree)
tree match {
case res: tpd.This =>
- assert(!ExplicitOuter.referencesOuter(ctx.owner.enclosingClass, res),
+ assert(!ExplicitOuter.referencesOuter(ctx.owner.lexicallyEnclosingClass, res),
i"Reference to $res from ${ctx.owner.showLocated}")
case ret: tpd.Return =>
// checked only after erasure, as checking before erasure is complicated
@@ -412,7 +412,7 @@ object Erasure extends TypeTestsCasts{
}
override def typedThis(tree: untpd.This)(implicit ctx: Context): Tree =
- if (tree.symbol == ctx.owner.enclosingClass || tree.symbol.isStaticOwner) promote(tree)
+ if (tree.symbol == ctx.owner.lexicallyEnclosingClass || tree.symbol.isStaticOwner) promote(tree)
else {
ctx.log(i"computing outer path from ${ctx.owner.ownersIterator.toList}%, % to ${tree.symbol}, encl class = ${ctx.owner.enclosingClass}")
outer.path(tree.symbol)
diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index 3fec47e9f..a32e1c921 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -330,7 +330,7 @@ object ExplicitOuter {
/** The path of outer accessors that references `toCls.this` starting from
* the context owner's this node.
*/
- def path(toCls: Symbol, start: Tree = This(ctx.owner.enclosingClass.asClass)): Tree = try {
+ def path(toCls: Symbol, start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass)): Tree = try {
def loop(tree: Tree): Tree = {
val treeCls = tree.tpe.widen.classSymbol
val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore
diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala
index 6c398cd72..11121e1f3 100644
--- a/compiler/src/dotty/tools/dotc/typer/Applications.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala
@@ -250,8 +250,37 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
/** Splice new method reference into existing application */
def spliceMeth(meth: Tree, app: Tree): Tree = app match {
- case Apply(fn, args) => Apply(spliceMeth(meth, fn), args)
- case TypeApply(fn, targs) => TypeApply(spliceMeth(meth, fn), targs)
+ case Apply(fn, args) =>
+ spliceMeth(meth, fn).appliedToArgs(args)
+ case TypeApply(fn, targs) =>
+ // Note: It is important that the type arguments `targs` are passed in new trees
+ // instead of being spliced in literally. Otherwise, a type argument to a default
+ // method could be constructed as the definition site of the type variable for
+ // that default constructor. This would interpolate type variables too early,
+ // causing lots of tests (among them tasty_unpickleScala2) to fail.
+ //
+ // The test case is in i1757.scala. Here we have a variable `s` and a method `cpy`
+ // defined like this:
+ //
+ // var s
+ // def cpy[X](b: List[Int] = b): B[X] = new B[X](b)
+ //
+ // The call `s.cpy()` then gets expanded to
+ //
+ // { val $1$: B[Int] = this.s
+ // $1$.cpy[X']($1$.cpy$default$1[X']
+ // }
+ //
+ // A type variable gets interpolated if it does not appear in the type
+ // of the current tree and the current tree contains the variable's "definition".
+ // Previously, the polymorphic function tree to which the variable was first added
+ // was taken as the variable's definition. But that fails here because that
+ // tree was `s.cpy` but got transformed into `$1$.cpy`. We now take the type argument
+ // [X'] of the variable as its definition tree, which is more robust. But then
+ // it's crucial that the type tree is not copied directly as argument to
+ // `cpy$default$1`. If it was, the variable `X'` would already be interpolated
+ // when typing the default argument, which is too early.
+ spliceMeth(meth, fn).appliedToTypes(targs.tpes)
case _ => meth
}
@@ -333,7 +362,7 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
val getter = findDefaultGetter(n + numArgs(normalizedFun))
if (getter.isEmpty) missingArg(n)
else {
- addTyped(treeToArg(spliceMeth(getter withPos appPos, normalizedFun)), formal)
+ addTyped(treeToArg(spliceMeth(getter withPos normalizedFun.pos, normalizedFun)), formal)
matchArgs(args1, formals1, n + 1)
}
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
index aede4974a..1cb86dd72 100644
--- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala
@@ -216,10 +216,10 @@ object Inferencing {
def interpolateUndetVars(tree: Tree, ownedBy: Symbol)(implicit ctx: Context): Unit = {
val constraint = ctx.typerState.constraint
val qualifies = (tvar: TypeVar) =>
- (tree contains tvar.owningTree) || ownedBy.exists && tvar.owner == ownedBy
+ (tree contains tvar.bindingTree) || 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}")}")
+ constr.println(s"interpolate undet vars in ${tp.show}, pos = ${tree.pos}, mode = ${ctx.mode}, undets = ${constraint.uninstVars map (tvar => s"${tvar.show}@${tvar.bindingTree.pos}")}")
constr.println(s"qualifying undet vars: ${constraint.uninstVars filter qualifies map (tvar => s"$tvar / ${tvar.show}")}, constraint: ${constraint.show}")
val vs = variances(tp, qualifies)
diff --git a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 9a20a452e..ed6b95c3b 100644
--- a/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -353,20 +353,23 @@ object ProtoTypes {
* Also, if `owningTree` is non-empty, add a type variable for each parameter.
* @return The added polytype, and the list of created type variables.
*/
- def constrained(pt: PolyType, owningTree: untpd.Tree)(implicit ctx: Context): (PolyType, List[TypeVar]) = {
+ def constrained(pt: PolyType, owningTree: untpd.Tree)(implicit ctx: Context): (PolyType, List[TypeTree]) = {
val state = ctx.typerState
assert(!(ctx.typerState.isCommittable && owningTree.isEmpty),
s"inconsistent: no typevars were added to committable constraint ${state.constraint}")
- def newTypeVars(pt: PolyType): List[TypeVar] =
+ def newTypeVars(pt: PolyType): List[TypeTree] =
for (n <- (0 until pt.paramNames.length).toList)
- yield new TypeVar(PolyParam(pt, n), state, owningTree, ctx.owner)
+ yield {
+ val tt = new TypeTree().withPos(owningTree.pos)
+ tt.withType(new TypeVar(PolyParam(pt, n), state, tt, ctx.owner))
+ }
val added =
if (state.constraint contains pt) pt.newLikeThis(pt.paramNames, pt.paramBounds, pt.resultType)
else pt
val tvars = if (owningTree.isEmpty) Nil else newTypeVars(added)
- ctx.typeComparer.addToConstraint(added, tvars)
+ ctx.typeComparer.addToConstraint(added, tvars.tpes.asInstanceOf[List[TypeVar]])
(added, tvars)
}
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 94b13b22b..ae6b719e4 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1978,12 +1978,12 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
if (pt.isInstanceOf[PolyProto]) tree
else {
var typeArgs = tree match {
- case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo
+ case Select(qual, nme.CONSTRUCTOR) => qual.tpe.widenDealias.argTypesLo.map(TypeTree)
case _ => Nil
}
if (typeArgs.isEmpty) typeArgs = constrained(poly, tree)._2
convertNewGenericArray(
- adaptInterpolated(tree.appliedToTypes(typeArgs), pt, original))
+ adaptInterpolated(tree.appliedToTypeTrees(typeArgs), pt, original))
}
case wtp =>
pt match {
diff --git a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala
index c77ba501f..d9a5d8a38 100644
--- a/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala
+++ b/compiler/test/dotty/tools/dotc/transform/PatmatExhaustivityTest.scala
@@ -9,9 +9,9 @@ import dotty.tools.dotc.Main
import dotty.tools.dotc.reporting.TestReporter
class PatmatExhaustivityTest {
- val testsDir = "./tests/patmat"
+ val testsDir = "../tests/patmat"
// stop-after: patmatexhaust-huge.scala crash compiler
- val options = List("-color:never", "-Ystop-after:splitter", "-Ycheck-all-patmat")
+ val options = List("-color:never", "-Ystop-after:splitter", "-Ycheck-all-patmat") ++ (new dotc.tests).classPath
private def compileFile(file: File) = {
val stringBuffer = new StringWriter()