aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/src/dotty/tools/dotc/Compiler.scala4
-rw-r--r--compiler/src/dotty/tools/dotc/core/Types.scala7
-rw-r--r--compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala21
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TreeChecker.scala2
-rw-r--r--compiler/src/dotty/tools/dotc/typer/RefChecks.scala3
-rw-r--r--compiler/src/dotty/tools/dotc/typer/Typer.scala37
-rw-r--r--compiler/test/dotc/tests.scala1
-rw-r--r--tests/neg/t1569-failedAvoid.scala9
-rw-r--r--tests/pickling/default-param-interface.scala (renamed from tests/tasty/default-param-interface.scala)0
-rw-r--r--tests/pickling/i982.scala (renamed from tests/tasty/i982.scala)0
-rw-r--r--tests/pos-java-interop/varargsOverride/Base.java5
-rw-r--r--tests/pos-java-interop/varargsOverride/Sub.scala3
-rw-r--r--tests/pos/t1569.scala12
14 files changed, 72 insertions, 34 deletions
diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala
index 1d319242b..f413fc902 100644
--- a/compiler/src/dotty/tools/dotc/Compiler.scala
+++ b/compiler/src/dotty/tools/dotc/Compiler.scala
@@ -48,9 +48,9 @@ class Compiler {
List(new Pickler), // Generate TASTY info
List(new FirstTransform, // Some transformations to put trees into a canonical form
new CheckReentrant), // Internal use only: Check that compiled program has no data races involving global vars
- List(new RefChecks, // Various checks mostly related to abstract members and overriding
- new CheckStatic, // Check restrictions that apply to @static members
+ List(new CheckStatic, // Check restrictions that apply to @static members
new ElimRepeated, // Rewrite vararg parameters and arguments
+ new RefChecks, // Various checks mostly related to abstract members and overriding
new NormalizeFlags, // Rewrite some definition flags
new ExtensionMethods, // Expand methods of value classes with extension methods
new ExpandSAMs, // Expand single abstract method closures to anonymous classes
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index b8f81f1bb..639f5d142 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -3546,6 +3546,13 @@ object Types {
def apply(tp: Type) = tp
}
+ /** A type map that approximates NoTypes by upper or lower known bounds depending on
+ * variance.
+ *
+ * if variance > 0 : approximate by upper bound
+ * variance < 0 : approximate by lower bound
+ * variance = 0 : propagate NoType to next outer level
+ */
abstract class ApproximatingTypeMap(implicit ctx: Context) extends TypeMap { thisMap =>
def approx(lo: Type = defn.NothingType, hi: Type = defn.AnyType) =
if (variance == 0) NoType
diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
index 6af902d1b..67d44daa1 100644
--- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
+++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala
@@ -483,7 +483,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
else
Text()
- nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ node.pos.toString
+ nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ (node.pos.toString provided ctx.settings.Yprintpos.value)
case _ =>
tree.fallbackToText(this)
}
diff --git a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
index 258b7f234..d955628e3 100644
--- a/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ElimRepeated.scala
@@ -32,8 +32,21 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati
def transformInfo(tp: Type, sym: Symbol)(implicit ctx: Context): Type =
elimRepeated(tp)
+
+ override def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation =
+ super.transform(ref) match {
+ case ref1: SymDenotation if (ref1 ne ref) && overridesJava(ref1.symbol) =>
+ // This method won't override the corresponding Java method at the end of this phase,
+ // only the bridge added by `addVarArgsBridge` will.
+ ref1.copySymDenotation(initFlags = ref1.flags &~ Override)
+ case ref1 =>
+ ref1
+ }
+
override def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = sym is Method
+ private def overridesJava(sym: Symbol)(implicit ctx: Context) = sym.allOverriddenSymbols.exists(_ is JavaDefined)
+
private def elimRepeated(tp: Type)(implicit ctx: Context): Type = tp.stripTypeVar match {
case tp @ MethodType(paramNames, paramTypes) =>
val resultType1 = elimRepeated(tp.resultType)
@@ -93,10 +106,9 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati
*/
override def transformDefDef(tree: DefDef)(implicit ctx: Context, info: TransformerInfo): Tree = {
assert(ctx.phase == thisTransformer)
- def overridesJava = tree.symbol.allOverriddenSymbols.exists(_ is JavaDefined)
- if (tree.symbol.info.isVarArgsMethod && overridesJava)
- addVarArgsBridge(tree)(ctx.withPhase(thisTransformer.next))
- else
+ if (tree.symbol.info.isVarArgsMethod && overridesJava(tree.symbol))
+ addVarArgsBridge(tree)
+ else
tree
}
@@ -120,6 +132,7 @@ class ElimRepeated extends MiniPhaseTransform with InfoTransformer with Annotati
.appliedToArgs(vrefs :+ TreeGen.wrapArray(varArgRef, elemtp))
.appliedToArgss(vrefss1)
})
+
Thicket(ddef, bridgeDef)
}
diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
index 7a4af647f..51e2469b2 100644
--- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -446,7 +446,7 @@ class TreeChecker extends Phase with SymTransformer {
super.typedStats(trees, exprOwner)
}
- override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol], forcedDefined: Boolean = false)(implicit ctx: Context): Tree =
+ override def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(implicit ctx: Context): Tree =
tree
override def adapt(tree: Tree, pt: Type, original: untpd.Tree = untpd.EmptyTree)(implicit ctx: Context) = {
diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
index 23d05e087..e8ff7d572 100644
--- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
+++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala
@@ -766,6 +766,9 @@ class RefChecks extends MiniPhase { thisTransformer =>
override def phaseName: String = "refchecks"
+ // Needs to run after ElimRepeated for override checks involving varargs methods
+ override def runsAfter = Set(classOf[ElimRepeated])
+
val treeTransform = new Transform(NoLevelInfo)
class Transform(currentLevel: RefChecks.OptLevelInfo = RefChecks.NoLevelInfo) extends TreeTransform {
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 2578da649..ccfe218b3 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -625,14 +625,17 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
block.tpe namedPartsWith (tp => locals.contains(tp.symbol))
}
- /** Check that expression's type can be expressed without references to locally defined
- * symbols. The following two remedies are tried before giving up:
- * 1. If the expected type of the expression is fully defined, pick it as the
- * type of the result expressed by adding a type ascription.
- * 2. If (1) fails, force all type variables so that the block's type is
- * fully defined and try again.
+ /** Ensure that an expression's type can be expressed without references to locally defined
+ * symbols. This is done by adding a type ascription of a widened type that does
+ * not refer to the locally defined symbols. The widened type is computed using
+ * `TyperAssigner#avoid`. However, if the expected type is fully defined and not
+ * a supertype of the widened type, we ascribe with the expected type instead.
+ *
+ * There's a special case having to do with anonymous classes. Sometimes the
+ * expected type of a block is the anonymous class defined inside it. In that
+ * case there's technically a leak which is not removed by the ascription.
*/
- protected def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol], forcedDefined: Boolean = false)(implicit ctx: Context): Tree = {
+ protected def ensureNoLocalRefs(tree: Tree, pt: Type, localSyms: => List[Symbol])(implicit ctx: Context): Tree = {
def ascribeType(tree: Tree, pt: Type): Tree = tree match {
case block @ Block(stats, expr) =>
val expr1 = ascribeType(expr, pt)
@@ -640,16 +643,18 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
case _ =>
Typed(tree, TypeTree(pt.simplified))
}
- val leaks = escapingRefs(tree, localSyms)
- if (leaks.isEmpty) tree
- else if (isFullyDefined(pt, ForceDegree.none)) ascribeType(tree, pt)
- else if (!forcedDefined) {
+ def noLeaks(t: Tree): Boolean = escapingRefs(t, localSyms).isEmpty
+ if (noLeaks(tree)) tree
+ else {
fullyDefinedType(tree.tpe, "block", tree.pos)
- val tree1 = ascribeType(tree, avoid(tree.tpe, localSyms))
- ensureNoLocalRefs(tree1, pt, localSyms, forcedDefined = true)
- } else
- errorTree(tree,
- em"local definition of ${leaks.head.name} escapes as part of expression's type ${tree.tpe}"/*; full type: ${result.tpe.toString}"*/)
+ var avoidingType = avoid(tree.tpe, localSyms)
+ val ptDefined = isFullyDefined(pt, ForceDegree.none)
+ if (ptDefined && !(avoidingType <:< pt)) avoidingType = pt
+ val tree1 = ascribeType(tree, avoidingType)
+ assert(ptDefined || noLeaks(tree1), // `ptDefined` needed because of special case of anonymous classes
+ i"leak: ${escapingRefs(tree1, localSyms).toList}%, % in $tree1")
+ tree1
+ }
}
def typedIf(tree: untpd.If, pt: Type)(implicit ctx: Context): Tree = track("typedIf") {
diff --git a/compiler/test/dotc/tests.scala b/compiler/test/dotc/tests.scala
index a720f1294..0c4668a89 100644
--- a/compiler/test/dotc/tests.scala
+++ b/compiler/test/dotc/tests.scala
@@ -355,7 +355,6 @@ class tests extends CompilerTest {
@Test def tasty_dotc_util = compileDir(dotcDir, "util", testPickling)
@Test def tasty_tools_io = compileDir(toolsDir, "io", testPickling)
- @Test def tasty_tests = compileDir(testsDir, "tasty", testPickling)
@Test def tasty_bootstrap = {
val logging = if (false) List("-Ylog-classpath", "-verbose") else Nil
diff --git a/tests/neg/t1569-failedAvoid.scala b/tests/neg/t1569-failedAvoid.scala
deleted file mode 100644
index 45bb96f36..000000000
--- a/tests/neg/t1569-failedAvoid.scala
+++ /dev/null
@@ -1,9 +0,0 @@
-// This was t1569.scala.
-// It fails in dotty because the expected type of the anonymous function in the last line
-// is fully determined (C). So that type is taken as the type of the anonymous function.
-// See pos/t1569a.scala for related examples that work.
-object Bug {
- class C { type T }
- def foo(x: Int)(y: C)(z: y.T): Unit = {}
- foo(3)(new C { type T = String })("hello") // error
-}
diff --git a/tests/tasty/default-param-interface.scala b/tests/pickling/default-param-interface.scala
index 919f4b627..919f4b627 100644
--- a/tests/tasty/default-param-interface.scala
+++ b/tests/pickling/default-param-interface.scala
diff --git a/tests/tasty/i982.scala b/tests/pickling/i982.scala
index 838b250d9..838b250d9 100644
--- a/tests/tasty/i982.scala
+++ b/tests/pickling/i982.scala
diff --git a/tests/pos-java-interop/varargsOverride/Base.java b/tests/pos-java-interop/varargsOverride/Base.java
new file mode 100644
index 000000000..a4607b71c
--- /dev/null
+++ b/tests/pos-java-interop/varargsOverride/Base.java
@@ -0,0 +1,5 @@
+class Base {
+ public Object foo(Object... x) {
+ return x;
+ }
+}
diff --git a/tests/pos-java-interop/varargsOverride/Sub.scala b/tests/pos-java-interop/varargsOverride/Sub.scala
new file mode 100644
index 000000000..9d3e2bf0d
--- /dev/null
+++ b/tests/pos-java-interop/varargsOverride/Sub.scala
@@ -0,0 +1,3 @@
+class Sub extends Base {
+ override def foo(x: Object*): Object = x
+}
diff --git a/tests/pos/t1569.scala b/tests/pos/t1569.scala
new file mode 100644
index 000000000..a2fbcf11f
--- /dev/null
+++ b/tests/pos/t1569.scala
@@ -0,0 +1,12 @@
+// See pos/t1569a.scala for related examples that work.
+object Bug {
+ class C { type T }
+ def foo(x: Int)(y: C)(z: y.T): Unit = {}
+ foo(3)(new C { type T = String })("hello")
+}
+object Bug2 {
+ class C { type T }
+ class D extends C { type T = String }
+ def foo(x: Int)(y: C)(z: y.T): Unit = {}
+ foo(3)(new D {})("hello")
+}