From 4a91353955b271763e0d75f7465d887384f8ef6d Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 19 Jun 2022 22:36:45 +0200 Subject: [PATCH 1/4] Fix findFunctionType for OrTypes Restore funtionality that was dropped in 6ac8b47 Fixes #15460 --- compiler/src/dotty/tools/dotc/core/Types.scala | 10 ++++++++-- tests/pos/i15460.scala | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 tests/pos/i15460.scala diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6557e3649377..b4abff9b4f2e 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1690,14 +1690,20 @@ object Types { * is returned. If no function type is found, Any is returned. */ def findFunctionType(using Context): Type = dealias match - case tp: AndOrType => + case tp: AndType => tp.tp1.findFunctionType & tp.tp2.findFunctionType + case tp: OrType => + val tf1 = tp.tp1.findFunctionType + val tf2 = tp.tp2.findFunctionType + if !tf1.exists then tf2 + else if !tf2.exists then tf1 + else NoType case t if defn.isNonRefinedFunction(t) => t case t @ SAMType(_) => t case _ => - defn.AnyType + NoType /** This type seen as a TypeBounds */ final def bounds(using Context): TypeBounds = this match { diff --git a/tests/pos/i15460.scala b/tests/pos/i15460.scala new file mode 100644 index 000000000000..c247cb0ae878 --- /dev/null +++ b/tests/pos/i15460.scala @@ -0,0 +1,5 @@ +type C = (() => Int) | (() => String) + +def foo(c: C): Unit = () + +val _ = foo(() => 1) From 35f3f9cac0865b8b1074b2b6161a27d0bfc0aa43 Mon Sep 17 00:00:00 2001 From: odersky Date: Sun, 19 Jun 2022 23:22:32 +0200 Subject: [PATCH 2/4] Fix test --- tests/neg/i11694.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/neg/i11694.scala b/tests/neg/i11694.scala index 67138fd5a7eb..d43fe4aa99e3 100644 --- a/tests/neg/i11694.scala +++ b/tests/neg/i11694.scala @@ -5,8 +5,8 @@ def test1 = { def f21: (Int => Int) | Null = x => x + 1 def f22: Null | (Int => Int) = x => x + 1 - def f31: (Int => Int) | (Int => Int) = x => x + 1 - def f32: (Int => Int) | (Int => Int) | Unit = x => x + 1 + def f31: (Int => Int) | (Int => Int) = x => x + 1 // error + def f32: (Int => Int) | (Int => Int) | Unit = x => x + 1 // error def f41: (Int => Int) & (Int => Int) = x => x + 1 def f42: (Int => Int) & (Int => Int) & Any = x => x + 1 From 3a8e66996913cc85012c46a15ea2be619513643d Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 20 Jun 2022 09:42:30 +0200 Subject: [PATCH 3/4] Fix comment --- compiler/src/dotty/tools/dotc/core/Types.scala | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index b4abff9b4f2e..6263647515c4 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1685,9 +1685,14 @@ object Types { case _ => resultType } - /** Determine the expected function type from the prototype. If multiple - * function types are found in a union or intersection, their intersection - * is returned. If no function type is found, Any is returned. + /** Determine the expected function type from the prototype. + * If no function type is found, Any is returned. If multiple + * function types are found in an intersection, their intersection + * is returned. This works since `&` invokes `TypeComparer.distributeAnd`, which + * ensures that `(A1 => B1) & (A2 => B2)` simplifies to `(A1 | A2) => (B1 & B2)`, + * so the result is again a function type. An analogous distribution mechanism + * does not exist for `|`. Therefore, a union of function types also yields `NoType`, + * since we cannot determine a single expected function type. */ def findFunctionType(using Context): Type = dealias match case tp: AndType => From e1ddcedcfcda36583d3a0853b1a8fc4b15c10381 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 20 Jun 2022 14:03:06 +0200 Subject: [PATCH 4/4] Update compiler/src/dotty/tools/dotc/core/Types.scala --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 6263647515c4..90674d151173 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -1686,7 +1686,7 @@ object Types { } /** Determine the expected function type from the prototype. - * If no function type is found, Any is returned. If multiple + * If no function type is found, NoType is returned. If multiple * function types are found in an intersection, their intersection * is returned. This works since `&` invokes `TypeComparer.distributeAnd`, which * ensures that `(A1 => B1) & (A2 => B2)` simplifies to `(A1 | A2) => (B1 & B2)`,