Otherwise a local class in a field initializer or anonymous init block
is copied into each constructor of the containing class (because
InitializersLowering calls deepCopy).
Since the code structure no longer resembles the original source code
here, record a custom EnclosingMethod mapping before moving such
classes, and use it in codegen.
Resolves the interaction of @JvmOverloads annotations and
parameterless main methods.
In the following code, both mechanisms generate methods that
ultimately produce the signature `public static void main(String[] args)`
of which there can be only one (true in general of any signature).
```
fun main() { }
@JvmOverloads
fun main(Array<String> args, x: Int = 42) { }
```
This PR simply shuffles the lowerings around, letting parameterless
main methods detect the presence of the default overload produced by
the annotation.
Additionally, this PR improves the testing of parameterless main
methods by actual bytecode patterns, and not simple check for
successful compilation (as @sfs and I discovered, there are issues in
flagging an error on duplicate signatures on the IR backend).
Support this for single file facades as well as for multi-file classes,
similar to code in
MultifileClassCodegen.writeKotlinMultifileFacadeAnnotationIfNeeded.
Extend the test on this attribute to also cover multi-file classes.
so that the enclosing method of objects defined inside lambdas is the
one they are declared in.
Note that this does not fix *all* enclosingInfo tests because JVM_IR
currently follows the KT-28064 proposal, i.e. does not regenerate
objects defined inside lambdas under any circumstances. For example,
this causes test boxInline/enclosingInfo/inlineChain2.kt to fail because
the enclosing method of objects is _2Kt.box instead of (non-existent in
source code) `_2Kt$box$inlined$call$1.invoke` or whatever. What's more
important is that OUTERCLASS no longer points to a non-existent
`box$lambda-N` and therefore `.enclosingMethod` no longer throws.
This makes sense because this mode is the default in the production
compiler. Forgetting to enable it where necessary led to different
bizarre test failures, see for example changes around 3fee84b966 and
KT-34826
For example, a lambda `{ param -> captured }` of type `E.(T) -> U` will
be transformed by LocalDeclarationsLowering into a private static method
fun f$lambda-0($this: E, $captured: U, param: T) = $captured
The reason for such an ordering is that a lambda looks the same as a
local function, and local function can have default arguments, and those
arguments can reference captured variables; thus, captured variables
must come before actual declared arguments.
However, this is not the order that the inliner wants. Moreover, since
it was written to handle lambdas represented as `invoke` methods of
anonymous objects, it does not expect the actual callable method to have
any parameters corresponding to captured variables at all. This results
in it attempting to generate a temporary node with descriptor
(LE;LU;LT;LU;)LU;
while still using locals 1 and 2 as `param` and `$captured` respectively.
In the example above, this is not critical, as they both have reference
type and the lambda will eventually be pasted into a different node
anyway; however, if it happens that one of them is a primitive, or both
are primitives of different types, the bytecode will use incorrect
instructions, causing verification errors. The correct descriptor is
(LE;LT;LU;)LU;
Necessary to support importing file classes annotated @JvmPackageName,
since the actual package fragment they are a part of has the name from
the `package` declaration.
Create a separate _ir.txt bytecode listing file for JVM IR, to avoid
duplicate tests and to fix "Codegent tests on different JDKs"
configuration where this test is muted but passes because only execution
is checked there, not bytecode listing.
This directory is skipped in JVM IR test generator, so they won't show
up as failed anymore.
Note that only failing tests are moved to oldLanguageVersions/. Tests
which already pass are still being run. It may be useful not to break
them in case we _do_ need to support some pre-1.3 language feature
switches in JVM IR.
As for SAM wrappers, the bytecode sequence
new A
dup
new B
dup
invokespecial B.<init>
invokespecial A.<init>
breaks the inliner, so instead we do
new B
dup
invokespecial B.<init>
store x
new A
dup
load x
invokespecial A.<init>
Otherwise, the cached instances cannot be reused for different wrapped
types. Also, if the wrapped type is regenerated during inlining, the
inliner would produce a call to a nonexistent constructor that takes the
regenerated type as an argument.
To avoid bytecode sequences like
new _1Kt$sam$i$java_lang_Runnable$0
dup
new _1Kt$f$1
dup
invokespecial _1Kt$f$1.<init>()V
invokespecial _1Kt$sam$i$java_lang_Runnable$0.<init>(...)V
as the different order of `new` and `<init>` confuses the inliner.
Namely, anonymous objects defined in lambdas that have all captured
variables as loose fields instead of a single reference to the parent.
The question is, when a lambda inside an inline function defines an
anonymous object, and that object is not regenerated during codegen for
the inline function itself, but then has to be regenerated at call site
anyway, do we use an outer `this` or loose capture fields? For example,
before KT-28064:
inline fun f1(g: () -> Unit) = object { g() }
// -> f1$1 { $g: () -> Unit }
inline fun f2(g: () -> Unit) = f1 { object { g() } }
// -> f2$$inlined$f1$1 { $g: () -> Unit }
// f2$$inlined$f1$1$lambda$1 { this$0: f2$$inlined$f1$1 }
inline fun f3(g: () -> Unit) = f2 { object { g() } }
// -> f3$$inlined$f2$1 { $g: () -> Unit }
// f3$$inlined$f2$1$1 { this$0: f3$$inlined$f2$1 }
// f3$$inlined$f2$1$1$lambda$1 { this$0: f3$$inlined$f2$1$1 }
After KT-28064:
inline fun f2(g: () -> Unit) = f1 { object { g() } }
// -> f2$$inlined$f1$1 { $g: () -> Unit }
// f2$1$1 { $g: () -> Unit }
inline fun f3(g: () -> Unit) = f2 { object { g() } }
// -> f3$$inlined$f2$1 { $g: () -> Unit }
// f3$$inlined$f2$2 { ??? }
// f3$1$1 { $g: () -> Unit }
Should `???` be `this$0: f3$$inlined$f2$1` or `$g: () -> Unit`? This
commit chooses the latter for KT-28064 bytecode and keeps `this$0` when
inlining the old bytecode.
We should only insert a return statement at the end of a lambda or
function if the final statement is used as an expression (slice
USED_AS_RESULT_OF_LAMBDA and USED_AS_EXPRESSION).
- Added tests to demonstrate broken behaviour: the interaction of inline
functions and callable references with varargs and defaults in various
combinations.
- Refactored InlineCallableReferencesToLambdaPhase to look like and use
some of the infrastructure from CallableReferenceLowering.
- Lifted some of this infrastructure out to be broadly reusable.
Take branching and method calls into account when finding the line
number of the continuation. If there is no line number before
branching instructions or method calls, the following code is
still on the line of the suspend call itself.
This fixes a couple of issues with incorrect line numbers for
multiple throws on the same line or multipe suspend calls on
the same line.
In addition, it avoids the need to spam the method node with
repeated line number instructions in the IR backend.