diff options
-rw-r--r-- | src/dotty/tools/dotc/ast/TreeInfo.scala | 13 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/Constants.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Applications.scala | 9 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/ProtoTypes.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Typer.scala | 10 | ||||
-rw-r--r-- | test/dotc/scala-collections.whitelist | 1 | ||||
-rw-r--r-- | test/test/CompilerTest.scala | 16 | ||||
-rw-r--r-- | tests/pos/i1378.scala | 3 |
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) +} |