diff --git a/compiler/src/dotty/tools/dotc/Compiler.scala b/compiler/src/dotty/tools/dotc/Compiler.scala index 49c28f1ea030..a8bb0b72c10d 100644 --- a/compiler/src/dotty/tools/dotc/Compiler.scala +++ b/compiler/src/dotty/tools/dotc/Compiler.scala @@ -93,6 +93,7 @@ class Compiler { new FunctionXXLForwarders, // Add forwarders for FunctionXXL apply method new ParamForwarding, // Add forwarders for aliases of superclass parameters new TupleOptimizations, // Optimize generic operations on tuples + new LetOverApply, // Lift blocks from receivers of applications new ArrayConstructors) :: // Intercept creation of (non-generic) arrays and intrinsify. List(new Erasure) :: // Rewrite types to JVM model, erasing all type parameters, abstract types and refinements. List(new ElimErasedValueType, // Expand erased value types to their underlying implmementation types diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 24ab78f4df7a..a127551dc45f 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -749,14 +749,13 @@ object Erasure { val origFunType = origFun.tpe.widen(using preErasureCtx) val ownArgs = if origFunType.isErasedMethod then Nil else args val fun1 = typedExpr(fun, AnyFunctionProto) - val fun1core = stripBlock(fun1) fun1.tpe.widen match case mt: MethodType => val (xmt, // A method type like `mt` but with bunched arguments expanded to individual ones bunchArgs, // whether arguments are bunched outers) = // the outer reference parameter(s) - if fun1core.isInstanceOf[Apply] then - (mt, fun1core.removeAttachment(BunchedArgs).isDefined, Nil) + if fun1.isInstanceOf[Apply] then + (mt, fun1.removeAttachment(BunchedArgs).isDefined, Nil) else val xmt = expandedMethodType(mt, origFun) (xmt, xmt ne mt, outer.args(origFun)) diff --git a/compiler/src/dotty/tools/dotc/transform/LetOverApply.scala b/compiler/src/dotty/tools/dotc/transform/LetOverApply.scala new file mode 100644 index 000000000000..2279302ef16e --- /dev/null +++ b/compiler/src/dotty/tools/dotc/transform/LetOverApply.scala @@ -0,0 +1,32 @@ +package dotty.tools +package dotc +package transform + +import core._ +import Contexts.Context, Symbols._, Decorators._ +import MegaPhase._ +import ast.Trees._ + +/** Rewrite `{ stats; expr}.f(args)` to `{ stats; expr.f(args) }` and + * `{ stats; expr }(args)` to `{ stats; expr(args) }` before proceeding, + * but leave closures alone. This is necessary to be able to + * collapse applies of IFTs (this is done in Erasure). + */ +class LetOverApply extends MiniPhase: + import ast.tpd._ + + override def phaseName: String = "letOverApply" + + override def transformApply(tree: Apply)(using Context): Tree = + tree.fun match + case Select(blk @ Block(stats, expr), name) if !expr.isInstanceOf[Closure] => + cpy.Block(blk)(stats, + cpy.Apply(tree)( + cpy.Select(tree.fun)(expr, name), tree.args)) + case Block(stats, expr) => + cpy.Block(tree.fun)(stats, + cpy.Apply(tree)(expr, tree.args)) + case _ => + tree + +end LetOverApply diff --git a/tests/pos/i8881.scala b/tests/pos/i8881.scala new file mode 100644 index 000000000000..ce3820aa5d6d --- /dev/null +++ b/tests/pos/i8881.scala @@ -0,0 +1,5 @@ +object Crash { + def f(a: String, b: String, c: Int = 0): Int ?=> String = "" + given Int = ??? + f(b = "b", a = "a") +} \ No newline at end of file