Skip to content

Commit 6ac8b47

Browse files
committed
Generalize search for function type in expected type
In particular, handle situations like: val x: (Int => Int) & (Int => Int) = x => x which end up arising in at least one test case during type inference after the avoidance fixes in this PR.
1 parent 4437469 commit 6ac8b47

File tree

3 files changed

+16
-13
lines changed

3 files changed

+16
-13
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,23 +1674,19 @@ object Types {
16741674
case _ => resultType
16751675
}
16761676

1677-
/** Find the function type in union.
1678-
* If there are multiple function types, NoType is returned.
1677+
/** Determine the expected function type from the prototype. If multiple
1678+
* function types are found in a union or intersection, their intersection
1679+
* is returned. If no function type is found, Any is returned.
16791680
*/
1680-
def findFunctionTypeInUnion(using Context): Type = this match {
1681-
case t: OrType =>
1682-
val t1 = t.tp1.findFunctionTypeInUnion
1683-
if t1 == NoType then t.tp2.findFunctionTypeInUnion else
1684-
val t2 = t.tp2.findFunctionTypeInUnion
1685-
// Returen NoType if the union contains multiple function types
1686-
if t2 == NoType then t1 else NoType
1681+
def findFunctionType(using Context): Type = dealias match
1682+
case tp: AndOrType =>
1683+
tp.tp1.findFunctionType & tp.tp2.findFunctionType
16871684
case t if defn.isNonRefinedFunction(t) =>
16881685
t
16891686
case t @ SAMType(_) =>
16901687
t
16911688
case _ =>
1692-
NoType
1693-
}
1689+
defn.AnyType
16941690

16951691
/** This type seen as a TypeBounds */
16961692
final def bounds(using Context): TypeBounds = this match {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,7 +1169,7 @@ class Typer extends Namer
11691169
pt1 match {
11701170
case tp: TypeParamRef =>
11711171
decomposeProtoFunction(ctx.typerState.constraint.entry(tp).bounds.hi, defaultArity, pos)
1172-
case _ => pt1.findFunctionTypeInUnion match {
1172+
case _ => pt1.findFunctionType match {
11731173
case pt1 if defn.isNonRefinedFunction(pt1) =>
11741174
// if expected parameter type(s) are wildcards, approximate from below.
11751175
// if expected result type is a wildcard, approximate from above.
@@ -1444,7 +1444,7 @@ class Typer extends Namer
14441444
if (tree.tpt.isEmpty)
14451445
meth1.tpe.widen match {
14461446
case mt: MethodType =>
1447-
pt.findFunctionTypeInUnion match {
1447+
pt.findFunctionType match {
14481448
case pt @ SAMType(sam)
14491449
if !defn.isFunctionType(pt) && mt <:< sam =>
14501450
// SAMs of the form C[?] where C is a class cannot be conversion targets.

tests/neg/i11694.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,19 @@ def test1 = {
44

55
def f21: (Int => Int) | Null = x => x + 1
66
def f22: Null | (Int => Int) = x => x + 1
7+
8+
def f31: (Int => Int) | (Int => Int) = x => x + 1
9+
def f32: (Int => Int) | (Int => Int) | Unit = x => x + 1
10+
11+
def f41: (Int => Int) & (Int => Int) = x => x + 1
12+
def f42: (Int => Int) & (Int => Int) & Any = x => x + 1
713
}
814

915
def test2 = {
1016
def f1: (Int => String) | (Int => Int) | Null = x => x + 1 // error
1117
def f2: (Int => String) | Function[String, Int] | Null = x => "" + x // error
1218
def f3: Function[Int, Int] | Function[String, Int] | Null = x => x + 1 // error
19+
def f4: (Int => Int) & (Int => Int) & Unit = x => x + 1 // error
1320
}
1421

1522
def test3 = {

0 commit comments

Comments
 (0)