aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorodersky <odersky@gmail.com>2016-07-21 15:57:02 +0200
committerGitHub <noreply@github.com>2016-07-21 15:57:02 +0200
commit80a65f4b2512bdf1dc46144bea1c000d39319872 (patch)
tree3153a177e298d5416a0a187163a48d4ba6503154
parent990663624bdaa93bd7db5f64be78f3ca26d59633 (diff)
parent9ccb47ae2e9ae34a0ebd6bafbf6f327b39fc8d4a (diff)
downloaddotty-80a65f4b2512bdf1dc46144bea1c000d39319872.tar.gz
dotty-80a65f4b2512bdf1dc46144bea1c000d39319872.tar.bz2
dotty-80a65f4b2512bdf1dc46144bea1c000d39319872.zip
Merge pull request #1395 from dotty-staging/fix-#1378
Fix #1378: Propagate more knowledge of result type into applications
-rw-r--r--src/dotty/tools/dotc/ast/TreeInfo.scala13
-rw-r--r--src/dotty/tools/dotc/core/Constants.scala4
-rw-r--r--src/dotty/tools/dotc/typer/Applications.scala9
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala2
-rw-r--r--src/dotty/tools/dotc/typer/Typer.scala10
-rw-r--r--test/dotc/scala-collections.whitelist1
-rw-r--r--test/test/CompilerTest.scala16
-rw-r--r--tests/pos/i1378.scala3
8 files changed, 45 insertions, 13 deletions
diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala
index c1efd0b0b..a48651ebf 100644
--- a/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -278,7 +278,18 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
}
trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] =>
- // todo: fill with methods from TreeInfo that only apply to untpd.Tree's
+ import TreeInfo._
+
+ def isFunctionWithUnknownParamType(tree: Tree) = tree match {
+ case untpd.Function(args, _) =>
+ args.exists {
+ case ValDef(_, tpt, _) => tpt.isEmpty
+ case _ => false
+ }
+ case _ => false
+ }
+
+ // todo: fill with other methods from TreeInfo that only apply to untpd.Tree's
}
trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
diff --git a/src/dotty/tools/dotc/core/Constants.scala b/src/dotty/tools/dotc/core/Constants.scala
index 0f8c68bad..1892e4bdc 100644
--- a/src/dotty/tools/dotc/core/Constants.scala
+++ b/src/dotty/tools/dotc/core/Constants.scala
@@ -173,8 +173,8 @@ object Constants {
ctx.typerState.constraint.entry(param) match {
case TypeBounds(lo, hi) =>
if (hi.classSymbol.isPrimitiveValueClass) hi //constrain further with high bound
- else lo
- case NoType => param.binder.paramBounds(param.paramNum).lo
+ else classBound(lo)
+ case NoType => classBound(param.binder.paramBounds(param.paramNum).lo)
case inst => classBound(inst)
}
case pt => pt
diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala
index 69ad4f107..f0a514e8c 100644
--- a/src/dotty/tools/dotc/typer/Applications.scala
+++ b/src/dotty/tools/dotc/typer/Applications.scala
@@ -553,6 +553,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
// a modified tree but this would be more convoluted and less efficient.
if (proto.isTupled) proto = proto.tupled
+ // If some of the application's arguments are function literals without explicitly declared
+ // parameter types, relate the normalized result type of the application with the
+ // expected type through `constrainResult`. This can add more constraints which
+ // help sharpen the inferred parameter types for the argument function literal(s).
+ // This tweak is needed to make i1378 compile.
+ if (tree.args.exists(untpd.isFunctionWithUnknownParamType(_)))
+ if (!constrainResult(fun1.tpe.widen, proto.derivedFunProto(resultType = pt)))
+ typr.println(i"result failure for $tree with type ${fun1.tpe.widen}, expected = $pt")
+
fun1.tpe match {
case ErrorType => tree.withType(ErrorType)
case TryDynamicCallType =>
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index a430d5f75..767ccbe7d 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -175,7 +175,7 @@ object ProtoTypes {
def isMatchedBy(tp: Type)(implicit ctx: Context) =
typer.isApplicable(tp, Nil, typedArgs, resultType)
- def derivedFunProto(args: List[untpd.Tree], resultType: Type, typer: Typer) =
+ def derivedFunProto(args: List[untpd.Tree] = this.args, resultType: Type, typer: Typer = this.typer) =
if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
else new FunProto(args, resultType, typer)
diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala
index df72f0095..e982f9aa9 100644
--- a/src/dotty/tools/dotc/typer/Typer.scala
+++ b/src/dotty/tools/dotc/typer/Typer.scala
@@ -600,6 +600,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt)
else {
val params = args.asInstanceOf[List[untpd.ValDef]]
+
+ pt match {
+ case pt: TypeVar if untpd.isFunctionWithUnknownParamType(tree) =>
+ // try to instantiate `pt` if this is possible. If it does not
+ // work the error will be reported later in `inferredParam`,
+ // when we try to infer the parameter type.
+ isFullyDefined(pt, ForceDegree.noBottom)
+ case _ =>
+ }
+
val (protoFormals, protoResult) = decomposeProtoFunction(pt, params.length)
def refersTo(arg: untpd.Tree, param: untpd.ValDef): Boolean = arg match {
diff --git a/test/dotc/scala-collections.whitelist b/test/dotc/scala-collections.whitelist
index 4c7be0768..50a3f3479 100644
--- a/test/dotc/scala-collections.whitelist
+++ b/test/dotc/scala-collections.whitelist
@@ -83,6 +83,7 @@
./scala-scala/src/library/scala/collection/immutable/Seq.scala
./scala-scala/src/library/scala/collection/mutable/IndexedSeq.scala
./scala-scala/src/library/scala/collection/mutable/ListBuffer.scala
+#./scala-scala/src/library/scala/collection/mutable/BufferLike.scala // works under junit, fails under partest, but can't see more info on the cause
./scala-scala/src/library/scala/collection/mutable/ArrayBuilder.scala
diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala
index 3ee5597e6..1d8fb9bf5 100644
--- a/test/test/CompilerTest.scala
+++ b/test/test/CompilerTest.scala
@@ -236,17 +236,14 @@ abstract class CompilerTest {
val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main
val storeReporter = new Reporter with UniqueMessagePositions with HideNonSensicalMessages {
private val consoleReporter = new ConsoleReporter()
- private var innerStoreReporter = new StoreReporter(consoleReporter)
+ private val innerStoreReporter = new StoreReporter(consoleReporter)
def doReport(d: Diagnostic)(implicit ctx: Context): Unit = {
- if (innerStoreReporter == null) {
- consoleReporter.report(d)
- } else {
- innerStoreReporter.report(d)
- if (d.level == ERROR) {
- innerStoreReporter.flush()
- innerStoreReporter = null
- }
+ if (d.level == ERROR) {
+ innerStoreReporter.flush()
+ consoleReporter.doReport(d)
}
+ else if (errorCount > 0) consoleReporter.doReport(d)
+ else innerStoreReporter.doReport(d)
}
}
val reporter = processor.process(allArgs, storeReporter)
@@ -260,6 +257,7 @@ abstract class CompilerTest {
assert(nerrors == xerrors,
s"""Wrong # of errors. Expected: $xerrors, found: $nerrors
|Files with expected errors: $expectedErrorFiles
+ |errors:
""".stripMargin)
// NEG TEST
if (xerrors > 0) {
diff --git a/tests/pos/i1378.scala b/tests/pos/i1378.scala
new file mode 100644
index 000000000..31475daf2
--- /dev/null
+++ b/tests/pos/i1378.scala
@@ -0,0 +1,3 @@
+object Test {
+ (1, x => 2): (Int, Int => Int)
+}