Skip to content

Commit b34ad70

Browse files
authored
Merge pull request #15478 from dotty-staging/fix-15460
Fix findFunctionType for OrTypes
2 parents b0671c0 + e1ddced commit b34ad70

File tree

3 files changed

+23
-7
lines changed

3 files changed

+23
-7
lines changed

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

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,19 +1672,30 @@ object Types {
16721672
case _ => resultType
16731673
}
16741674

1675-
/** Determine the expected function type from the prototype. If multiple
1676-
* function types are found in a union or intersection, their intersection
1677-
* is returned. If no function type is found, Any is returned.
1675+
/** Determine the expected function type from the prototype.
1676+
* If no function type is found, NoType is returned. If multiple
1677+
* function types are found in an intersection, their intersection
1678+
* is returned. This works since `&` invokes `TypeComparer.distributeAnd`, which
1679+
* ensures that `(A1 => B1) & (A2 => B2)` simplifies to `(A1 | A2) => (B1 & B2)`,
1680+
* so the result is again a function type. An analogous distribution mechanism
1681+
* does not exist for `|`. Therefore, a union of function types also yields `NoType`,
1682+
* since we cannot determine a single expected function type.
16781683
*/
16791684
def findFunctionType(using Context): Type = dealias match
1680-
case tp: AndOrType =>
1685+
case tp: AndType =>
16811686
tp.tp1.findFunctionType & tp.tp2.findFunctionType
1687+
case tp: OrType =>
1688+
val tf1 = tp.tp1.findFunctionType
1689+
val tf2 = tp.tp2.findFunctionType
1690+
if !tf1.exists then tf2
1691+
else if !tf2.exists then tf1
1692+
else NoType
16821693
case t if defn.isNonRefinedFunction(t) =>
16831694
t
16841695
case t @ SAMType(_) =>
16851696
t
16861697
case _ =>
1687-
defn.AnyType
1698+
NoType
16881699

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

tests/neg/i11694.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ def test1 = {
55
def f21: (Int => Int) | Null = x => x + 1
66
def f22: Null | (Int => Int) = x => x + 1
77

8-
def f31: (Int => Int) | (Int => Int) = x => x + 1
9-
def f32: (Int => Int) | (Int => Int) | Unit = x => x + 1
8+
def f31: (Int => Int) | (Int => Int) = x => x + 1 // error
9+
def f32: (Int => Int) | (Int => Int) | Unit = x => x + 1 // error
1010

1111
def f41: (Int => Int) & (Int => Int) = x => x + 1
1212
def f42: (Int => Int) & (Int => Int) & Any = x => x + 1

tests/pos/i15460.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type C = (() => Int) | (() => String)
2+
3+
def foo(c: C): Unit = ()
4+
5+
val _ = foo(() => 1)

0 commit comments

Comments
 (0)