diff --git a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala index e8c9c91cc144..e4d85074dc65 100644 --- a/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala +++ b/compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala @@ -508,6 +508,17 @@ trait ConstraintHandling[AbstractContext] { case inst => prune(inst) } + case bound: ExprType => + // ExprTypes are not value types, so type parameters should not + // be instantiated to ExprTypes. A scenario where such an attempted + // instantiation can happen is if we unify (=> T) => () with A => () + // where A is a TypeParamRef. See the comment on EtaExpansion.etaExpand + // why types such as (=> T) => () can be constructed and i7969.scala + // as a test where this happens. + // Note that scalac by contrast allows such instantiations. But letting + // type variables be ExprTypes has its own problems (e.g. you can't write + // the resulting types down) and is largely unknown terrain. + NoType case _ => pruneLambdaParams(bound) } diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala index a180fb8cd922..33e112db700a 100644 --- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -198,6 +198,19 @@ object EtaExpansion extends LiftImpure { * In each case, the result is an untyped tree, with `es` and `expr` as typed splices. * * F[V](x) ==> (x => F[X]) + * + * Note: We allow eta expanding a method with a call by name parameter like + * + * def m(x: => T): T + * + * to a value of type (=> T) => T. This type cannot be written in source, since + * by-name types => T are not legal argument types. + * + * It would be simpler to not allow to eta expand by-name methods. That was the rule + * initially, but at some point, the rule was dropped. Enforcing the restriction again + * now would break existing code. Allowing by-name parameters in function types seems to + * be OK. After elimByName they are all converted to regular function types anyway. + * But see comment on the `ExprType` case in function `prune` in class `ConstraintHandling`. */ def etaExpand(tree: Tree, mt: MethodType, xarity: Int)(implicit ctx: Context): untpd.Tree = { import untpd._ diff --git a/tests/neg/i7969.scala b/tests/neg/i7969.scala new file mode 100644 index 000000000000..72e5609a9931 --- /dev/null +++ b/tests/neg/i7969.scala @@ -0,0 +1,5 @@ +object O{ + def f(i: => Int): Int = 1 + def m[A](a: A => Int) = 2 + def n = m(f) // error: cannot eta expand +} \ No newline at end of file