From 5e340310a3a3b2a4bd1fc8071dc5d060bd2cc5bc Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 16 Jul 2016 15:14:10 +0200 Subject: [PATCH 1/6] Fix error printing in compiler test Error messages were suppressed so far, now get printed. --- test/test/CompilerTest.scala | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala index 3ee5597e6907..1d8fb9bf5789 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) { From bd45ecc06b04c3788d1ce706508eed5e0c50b50b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 16 Jul 2016 15:19:17 +0200 Subject: [PATCH 2/6] Add recursive calls to classBound As observed by @smarter, makes sense to do this. --- src/dotty/tools/dotc/core/Constants.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dotty/tools/dotc/core/Constants.scala b/src/dotty/tools/dotc/core/Constants.scala index 0f8c68bad4bf..1892e4bdcf06 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 From 0eb2d76c467a53786ae6147c9c983c23ab0894c8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 16 Jul 2016 15:21:12 +0200 Subject: [PATCH 3/6] Proparage function result constrains when inferring parameter types If an application has functions with implicit parameter types we need to be more aggressive about propagating knowledge of the expected result type into the constraint. Fixes #1378. --- src/dotty/tools/dotc/ast/TreeInfo.scala | 13 ++++++++++++- src/dotty/tools/dotc/typer/Applications.scala | 10 ++++++++++ src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 +- src/dotty/tools/dotc/typer/Typer.scala | 7 +++++++ tests/pos/i1378.scala | 3 +++ 5 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i1378.scala diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index c1efd0b0b020..55eb21687610 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 isFunctionWithImplicitParamType(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/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 6e78a570de2c..7a742112b641 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -553,6 +553,16 @@ 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, and the expected type is a value type, relate the + // normalized result type of the application with the expected type through `<:<`. + // This can add more constraints which help sharpen the inferred parameter + // types for the argument function literal(s). + // This tweak is needed to make i1348 compile. + if (tree.args.exists(untpd.isFunctionWithImplicitParamType(_))) + 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 a430d5f75a36..767ccbe7d089 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 11a7b6753059..13b6167b10ab 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -597,6 +597,13 @@ 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.isFunctionWithImplicitParamType(tree) => + 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/tests/pos/i1378.scala b/tests/pos/i1378.scala new file mode 100644 index 000000000000..31475daf2333 --- /dev/null +++ b/tests/pos/i1378.scala @@ -0,0 +1,3 @@ +object Test { + (1, x => 2): (Int, Int => Int) +} From 9d66f8688291cb59ad78784d792dcf28a5527142 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Jul 2016 11:05:23 +0200 Subject: [PATCH 4/6] Adress reviewers comments --- src/dotty/tools/dotc/ast/TreeInfo.scala | 2 +- src/dotty/tools/dotc/typer/Applications.scala | 11 +++++------ src/dotty/tools/dotc/typer/Typer.scala | 5 ++++- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/dotty/tools/dotc/ast/TreeInfo.scala b/src/dotty/tools/dotc/ast/TreeInfo.scala index 55eb21687610..a48651ebf981 100644 --- a/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -280,7 +280,7 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] => trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] => import TreeInfo._ - def isFunctionWithImplicitParamType(tree: Tree) = tree match { + def isFunctionWithUnknownParamType(tree: Tree) = tree match { case untpd.Function(args, _) => args.exists { case ValDef(_, tpt, _) => tpt.isEmpty diff --git a/src/dotty/tools/dotc/typer/Applications.scala b/src/dotty/tools/dotc/typer/Applications.scala index 7a742112b641..56183d2ffe6b 100644 --- a/src/dotty/tools/dotc/typer/Applications.scala +++ b/src/dotty/tools/dotc/typer/Applications.scala @@ -554,12 +554,11 @@ trait Applications extends Compatibility { self: Typer with Dynamic => if (proto.isTupled) proto = proto.tupled // If some of the application's arguments are function literals without explicitly declared - // parameter types, and the expected type is a value type, relate the - // normalized result type of the application with the expected type through `<:<`. - // This can add more constraints which help sharpen the inferred parameter - // types for the argument function literal(s). - // This tweak is needed to make i1348 compile. - if (tree.args.exists(untpd.isFunctionWithImplicitParamType(_))) + // 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") diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index 13b6167b10ab..d0d41a214f6c 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -599,7 +599,10 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val params = args.asInstanceOf[List[untpd.ValDef]] pt match { - case pt: TypeVar if untpd.isFunctionWithImplicitParamType(tree) => + 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 _ => } From bdb3cc84bbcd2cd1ab44e4ca984ee6b41036bd7f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sun, 17 Jul 2016 11:05:51 +0200 Subject: [PATCH 5/6] Add test to whitelist This should have been done in a PR that was merged before. --- test/dotc/scala-collections.whitelist | 1 + 1 file changed, 1 insertion(+) diff --git a/test/dotc/scala-collections.whitelist b/test/dotc/scala-collections.whitelist index 4c7be07680ac..29db48cf2c31 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 ./scala-scala/src/library/scala/collection/mutable/ArrayBuilder.scala From 9ccb47ae2e9ae34a0ebd6bafbf6f327b39fc8d4a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 18 Jul 2016 18:02:10 +0200 Subject: [PATCH 6/6] Disable stdlib test Interestingly, adding mutable.BufferLike to the whitelist succeeds under junit but fails under partest. Unfortunately I can't see any output in the log indicating what went wrong. I only see this: !! 306 - pos/compileStdLib [compilation failed] # Failed test paths (this command will update checkfiles) test/partest --update-check \ /Users/odersky/workspace/dotty/tests/partest-generated/pos/compileStdLib --- test/dotc/scala-collections.whitelist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotc/scala-collections.whitelist b/test/dotc/scala-collections.whitelist index 29db48cf2c31..50a3f3479537 100644 --- a/test/dotc/scala-collections.whitelist +++ b/test/dotc/scala-collections.whitelist @@ -83,7 +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 +#./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