Skip to content

Commit 80a65f4

Browse files
authored
Merge pull request #1395 from dotty-staging/fix-#1378
Fix #1378: Propagate more knowledge of result type into applications
2 parents 9906636 + 9ccb47a commit 80a65f4

File tree

8 files changed

+45
-13
lines changed

8 files changed

+45
-13
lines changed

src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,18 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
278278
}
279279

280280
trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] =>
281-
// todo: fill with methods from TreeInfo that only apply to untpd.Tree's
281+
import TreeInfo._
282+
283+
def isFunctionWithUnknownParamType(tree: Tree) = tree match {
284+
case untpd.Function(args, _) =>
285+
args.exists {
286+
case ValDef(_, tpt, _) => tpt.isEmpty
287+
case _ => false
288+
}
289+
case _ => false
290+
}
291+
292+
// todo: fill with other methods from TreeInfo that only apply to untpd.Tree's
282293
}
283294

284295
trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>

src/dotty/tools/dotc/core/Constants.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ object Constants {
173173
ctx.typerState.constraint.entry(param) match {
174174
case TypeBounds(lo, hi) =>
175175
if (hi.classSymbol.isPrimitiveValueClass) hi //constrain further with high bound
176-
else lo
177-
case NoType => param.binder.paramBounds(param.paramNum).lo
176+
else classBound(lo)
177+
case NoType => classBound(param.binder.paramBounds(param.paramNum).lo)
178178
case inst => classBound(inst)
179179
}
180180
case pt => pt

src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,15 @@ trait Applications extends Compatibility { self: Typer with Dynamic =>
553553
// a modified tree but this would be more convoluted and less efficient.
554554
if (proto.isTupled) proto = proto.tupled
555555

556+
// If some of the application's arguments are function literals without explicitly declared
557+
// parameter types, relate the normalized result type of the application with the
558+
// expected type through `constrainResult`. This can add more constraints which
559+
// help sharpen the inferred parameter types for the argument function literal(s).
560+
// This tweak is needed to make i1378 compile.
561+
if (tree.args.exists(untpd.isFunctionWithUnknownParamType(_)))
562+
if (!constrainResult(fun1.tpe.widen, proto.derivedFunProto(resultType = pt)))
563+
typr.println(i"result failure for $tree with type ${fun1.tpe.widen}, expected = $pt")
564+
556565
fun1.tpe match {
557566
case ErrorType => tree.withType(ErrorType)
558567
case TryDynamicCallType =>

src/dotty/tools/dotc/typer/ProtoTypes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ object ProtoTypes {
175175
def isMatchedBy(tp: Type)(implicit ctx: Context) =
176176
typer.isApplicable(tp, Nil, typedArgs, resultType)
177177

178-
def derivedFunProto(args: List[untpd.Tree], resultType: Type, typer: Typer) =
178+
def derivedFunProto(args: List[untpd.Tree] = this.args, resultType: Type, typer: Typer = this.typer) =
179179
if ((args eq this.args) && (resultType eq this.resultType) && (typer eq this.typer)) this
180180
else new FunProto(args, resultType, typer)
181181

src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,16 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit
600600
untpd.TypeTree(defn.FunctionClass(args.length).typeRef), args :+ body), pt)
601601
else {
602602
val params = args.asInstanceOf[List[untpd.ValDef]]
603+
604+
pt match {
605+
case pt: TypeVar if untpd.isFunctionWithUnknownParamType(tree) =>
606+
// try to instantiate `pt` if this is possible. If it does not
607+
// work the error will be reported later in `inferredParam`,
608+
// when we try to infer the parameter type.
609+
isFullyDefined(pt, ForceDegree.noBottom)
610+
case _ =>
611+
}
612+
603613
val (protoFormals, protoResult) = decomposeProtoFunction(pt, params.length)
604614

605615
def refersTo(arg: untpd.Tree, param: untpd.ValDef): Boolean = arg match {

test/dotc/scala-collections.whitelist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
./scala-scala/src/library/scala/collection/immutable/Seq.scala
8484
./scala-scala/src/library/scala/collection/mutable/IndexedSeq.scala
8585
./scala-scala/src/library/scala/collection/mutable/ListBuffer.scala
86+
#./scala-scala/src/library/scala/collection/mutable/BufferLike.scala // works under junit, fails under partest, but can't see more info on the cause
8687

8788
./scala-scala/src/library/scala/collection/mutable/ArrayBuilder.scala
8889

test/test/CompilerTest.scala

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,14 @@ abstract class CompilerTest {
236236
val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main
237237
val storeReporter = new Reporter with UniqueMessagePositions with HideNonSensicalMessages {
238238
private val consoleReporter = new ConsoleReporter()
239-
private var innerStoreReporter = new StoreReporter(consoleReporter)
239+
private val innerStoreReporter = new StoreReporter(consoleReporter)
240240
def doReport(d: Diagnostic)(implicit ctx: Context): Unit = {
241-
if (innerStoreReporter == null) {
242-
consoleReporter.report(d)
243-
} else {
244-
innerStoreReporter.report(d)
245-
if (d.level == ERROR) {
246-
innerStoreReporter.flush()
247-
innerStoreReporter = null
248-
}
241+
if (d.level == ERROR) {
242+
innerStoreReporter.flush()
243+
consoleReporter.doReport(d)
249244
}
245+
else if (errorCount > 0) consoleReporter.doReport(d)
246+
else innerStoreReporter.doReport(d)
250247
}
251248
}
252249
val reporter = processor.process(allArgs, storeReporter)
@@ -260,6 +257,7 @@ abstract class CompilerTest {
260257
assert(nerrors == xerrors,
261258
s"""Wrong # of errors. Expected: $xerrors, found: $nerrors
262259
|Files with expected errors: $expectedErrorFiles
260+
|errors:
263261
""".stripMargin)
264262
// NEG TEST
265263
if (xerrors > 0) {

tests/pos/i1378.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
(1, x => 2): (Int, Int => Int)
3+
}

0 commit comments

Comments
 (0)