Compare commits

...

215 Commits

Author SHA1 Message Date
Svyatoslav Scherbina
99b395b0fa WIP: support Native binary options in Gradle 2021-08-18 18:37:35 +03:00
Svyatoslav Scherbina
0c5bf63844 Native: use binary options machinery for memory model
Old compiler flag (-memory-model) will work too.
2021-08-18 18:29:22 +03:00
Svyatoslav Scherbina
fd7c4c0c2d Native: use binary options machinery for runtime assertions mode 2021-08-18 18:28:19 +03:00
Svyatoslav Scherbina
4a62466671 Native: introduce binary options machinery 2021-08-18 18:27:30 +03:00
pyos
47d0211370 FE: do not enhance ? in jspecify NullMarked scope
No clue whether this should be done for `@TypeQualifierDefault` since it
appears to have no specification whatsoever.

 #KT-48262 Fixed
2021-08-18 16:41:00 +03:00
Jinseong Jeon
5819959cce Consolidate arrayOf call names 2021-08-18 16:04:36 +03:00
Andrey Zinovyev
1cd321a90f [FIR] Add INAPPLICABLE_OPERATOR_MODIFIER diagnostic 2021-08-18 16:03:01 +03:00
Ilya Goncharov
16f41bd80c [Gradle, JS] Use webpack-dev-server rc.1 2021-08-18 15:50:38 +03:00
Mikhael Bogdanov
8ab546ba51 [FIR]: Pass special origins for local functions (named and anonymous) 2021-08-18 09:58:27 +00:00
Mikhael Bogdanov
a5e59e09ee Copy methods for lambdas to DefaultImpls without receiver transformation
#KT-48230 Fixed
2021-08-18 09:58:27 +00:00
pyos
6d7eb2bd21 Add test for KT-48230 2021-08-18 09:58:27 +00:00
Sebastian Sellmair
21f7e16ee6 [Gradle] NativeDistributionCommonizationCache: Acquire FileLock
A `.lock` file will be acquired before running the native
distribution commonizer. This is done to protect data corruption
when multiple process try to commonize at the same time.

This could happen when e.g. two new projects are opened that
both trigger the commonizer during syncing.

^KT-46343 Verification Pending
2021-08-18 09:22:46 +00:00
Tianyu Geng
fb1eac0985 FIR: report SMARTCAST_IMPOSSIBLE on inherited alien properties [KT-48101] 2021-08-18 12:02:02 +03:00
Mikhail Glukhikh
0a6e51e47f FirJavaGenericVarianceViolationTypeChecker: make code a bit more clear 2021-08-18 12:02:01 +03:00
Ilya Goncharov
f37d880964 [Gradle, JS] Add test on valid of webpack config
^KT-48273 fixed
2021-08-18 11:56:19 +03:00
Ivan Kochurkin
301f446433 Restore KtModifierKeywordToken instead of String in modifier diagnostics
Remove KeywordType
2021-08-18 00:45:57 +03:00
Denis.Zharkov
a8077aebb0 FIR: Ignore suspicious test on StrictJavaNullabilityAssertions
^KT-48302 Open
2021-08-17 21:38:01 +03:00
Denis.Zharkov
753ba99b04 FIR: Support enhanced types when checking if Java type is primitive 2021-08-17 21:38:01 +03:00
Denis.Zharkov
a0553f4dfd FIR: Do not build synthetic property named with first capital character 2021-08-17 21:38:01 +03:00
Denis.Zharkov
c3a327e118 FIR: Fix ambiguity on Int2IntMap in IC 2021-08-17 21:38:01 +03:00
Mikhail Glukhikh
1a5552bef8 FIR2IR: fix argument mapping for deserialized annotation #KT-48298 Fixed 2021-08-17 18:22:33 +03:00
Mikhail Glukhikh
6660c9b26b FIR: add test repeating a problem with annotation mapping (KT-48298) 2021-08-17 18:22:33 +03:00
Andrey Zinovyev
ab158a53c3 [FIR] ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION diag 2021-08-17 16:05:42 +03:00
Andrey Zinovyev
1cdbbad367 [FIR] ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION diag 2021-08-17 16:05:42 +03:00
Nikita Bobko
5e87d753b7 Fix coop-dev project import 2021-08-17 13:55:36 +02:00
Ilya Goncharov
a7cc275c7d [Gradle, JS] Update webpack-dev-server
^KT-48273 fixed
2021-08-17 14:44:29 +03:00
Elena Lepilkina
12d694de46 [K/N] Added returns before building DFG 2021-08-17 16:14:07 +05:00
Igor Chevdar
16f0ba8e46 [K/N][optmz] Reworked a bit work with fields 2021-08-17 16:14:07 +05:00
pyos
49c412b022 JVM_IR: implement view caching in kotlin-android-extensions
#KT-47733 Fixed
2021-08-17 13:46:26 +03:00
Pavel Punegov
6ea2dea28e Fix JDK 16 and 17 env variables to correspond to the TC 2021-08-17 09:51:53 +00:00
Yahor Berdnikau
e7a08b14e3 Fix 'jvmTarget' is not updated on reusing configuration cache.
Before this change 'kotlinOptions.jvmTarget' was updated
on 'providedJvm' property value calculation, but, as configuration
cache reuses property value from the cache - 'jvmTarget' update does not
 happen.

This change adds additional call to set 'jvmTarget' on task execution
 phase to ensure even on configuration cache reuse field is set
 to correct value. Update is based whether 'providedJvm' property is set
 or not.

^KT-48226 Fixed
2021-08-17 09:13:29 +00:00
Pavel Punegov
7e1c776376 [Native][tests] Fix warnings in debugger tests 2021-08-17 08:42:11 +00:00
Dmitriy Dolovov
4049cf94b1 [Gradle][Native] Mute BuildCacheRelocationIT.testRelocation on MinGW 2021-08-17 11:01:08 +03:00
Dmitriy Dolovov
da72f26d94 [IR][Tests] Unmute NativeIrLinkerIssuesIT (as far as K/N version is already updated)
^KT-44626
2021-08-17 07:53:47 +00:00
Dmitriy Dolovov
e18c3517a9 [Gradle] Advance K/N version to 1.6.0-dev-2972 2021-08-17 07:53:46 +00:00
Dmitriy Dolovov
cd08dc49a0 [IR][Tests] Mute NativeIrLinkerIssuesIT until K/N version is updated
^KT-44626
2021-08-17 07:53:46 +00:00
Dmitriy Dolovov
4edc1239ac [IR] Use only ASCII-printable chars in IR linker error reports
^KT-44626
2021-08-17 07:53:46 +00:00
Dmitriy Dolovov
af12d61388 [IR] Enhance error reporting for IR linking issues
^KT-44626

Support correct error reporting both with native static caches and without native static caches.
2021-08-17 07:53:45 +00:00
Dmitriy Dolovov
3cd43dced4 [IR] Fix tests for IR linking error reporting
- Run "ktor 1_5_4 and coroutines 1_5_0-RC-native-mt (KT-46697)" test only on Mac host
- Fix application entry point function FQN
- Use OS-neutral URI for configuration of local Maven repos instead of OS-specific path

^KT-44626
2021-08-17 07:53:45 +00:00
Andrey Zinovyev
a17a61341b [FIR] Fix false positive NON_INTERNAL_PUBLISHED_API on constructor val
#KT-48234 Fixed
2021-08-16 19:12:31 +03:00
Tianyu Geng
68f14fdd87 FIR: PrimitiveTypes -> StandardTypes 2021-08-16 16:54:33 +03:00
Tianyu Geng
5a26e79b08 FIR checker: move JAVA_TYPE_MISMATCH to FirJvmErrors 2021-08-16 16:54:32 +03:00
Tianyu Geng
b77dc4136b FIR checker: fix JAVA_TYPE_MISMATCH again 2021-08-16 16:54:22 +03:00
Tianyu Geng
64ebddcbc6 FIR checker: add convention check for ++ and +=, etc 2021-08-16 15:14:30 +03:00
sebastian.sellmair
68e7476765 [Commonizer] ClassSuperTypeCommonizer: Don't find consumed TypeNodes
This commit will also add some simple documentation
to this class and its implementation.

^KT-47430
2021-08-16 10:44:04 +00:00
sebastian.sellmair
1e95717b8d [Commonizer] Implement SimpleCirSupertypesResolverTest
^KT-47430
2021-08-16 10:44:03 +00:00
sebastian.sellmair
f64a0efa8b [Commonizer] Respect artificial supertypes when loading dependencies
CirProvided.ExportedForwardDeclarationClass will now correctly
report artificial superclasses.

The InlineTypeAliasCirNodeTransformer does not need to know anything
about artificial supertypes anymore. When inlining any
type alias, it is enough to resolve the type-alias's expansions
supertypes.

^KT-47430
2021-08-16 10:44:03 +00:00
sebastian.sellmair
26ede5d885 [Commonizer] Add small documentation on CirSupertypesResolver
^KT-47430
2021-08-16 10:44:03 +00:00
sebastian.sellmair
9fb41b6334 [Commonizer] CirKnownClassifiers: Store indices and target dependencies as 'TargetDependent'
^KT-47430
2021-08-16 10:44:02 +00:00
sebastian.sellmair
367db345a8 [Commonizer] Do not re-calculate classifier indices for transformer
^KT-47430
2021-08-16 10:44:02 +00:00
sebastian.sellmair
dda9bb93f6 [Commonizer] Consider exportForwardDeclarations as dependency
This will make follow-up commits easier:
forward declarations are closer to dependencies than being part
of the library. They will be used in the module, bot not
directly provided.

This commit also enables tracking of provided dependency classifiers
in the CirTreeRoot and CirRootNode

^KT-47430
2021-08-16 10:44:01 +00:00
sebastian.sellmair
3d4e861f05 [Commonizer] ModulesProvider: refactor 'loadModuleInfos()' to property
This is done to signal that accessing this data is indeed lightweight.

^KT-47430
2021-08-16 10:44:01 +00:00
sebastian.sellmair
6c246738a5 [Commonizer] TargetDependent: Support index based access
^KT-47430
2021-08-16 10:44:01 +00:00
sebastian.sellmair
dff392f2cd [Commonizer] ClassSuperTypeCommonizer: Include transitive supertypes
This commit still has some left-over todos that shall be done
in a separate commit.

TODOs:
- CirClassifierIndex is calculated once too often
- Reconsider position of classifierIndices in 'CirKnownClassifiers'
- Add documentation/description to complicated 'ClassSuperTypeCommonizer'
- Add documentation/description to CirSupertypesResolver

^KT-47430 Verification Pending
2021-08-16 10:44:00 +00:00
sebastian.sellmair
1857096071 [Commonizer] Implement ClassSuperTypeCommonizer
This implementation runs as regular part of the commonization.
Previous implementation inside the CommonizationVisitor was fully
replaced by it.

As a side effect: CirClass.supertypes was now marked immutable.

^KT-47430 In Progress
2021-08-16 10:44:00 +00:00
sebastian.sellmair
50a343f91e [Commonizer] Deserialize supertypes from provided dependencies
^KT-47430 In Progress
2021-08-16 10:43:59 +00:00
sebastian.sellmair
cdfe8d60a4 [Commonizer] InlineTypeAliasCirNodeTransformer: add artificial supertypes
When inlining any TypeAlias pointing towards forward declarations,
the inlined class will respect implicit supertypes.

This logic is analog to
KlibResolvedModuleDescriptorsFactoryImpl.createForwardDeclarationsModule

^KT-47430 In Progress
2021-08-16 10:43:59 +00:00
Sergey Bogolepov
0c35a3b699 [K/N] A bit cleaner reflection of code coverage state in docs. 2021-08-16 09:22:32 +00:00
Ilmir Usmanov
486c6b3c15 Remove obsolete experimental coroutines support
in compiler.
2021-08-13 22:31:30 +02:00
Ilmir Usmanov
ebb340fe68 Do not just merge consequent LVT ranges, but also extend them 2021-08-13 23:12:10 +03:00
Ivan Kochurkin
8d764fa50e [FIR] Add FirPropertyAccessExpression that inherits FirQualifiedAccessExpression 2021-08-13 20:05:43 +03:00
Alexander Udalov
0fb398d45e Build: enable Werror for almost all compileKotlin tasks
The only exception at this point is :kotlin-gradle-plugin:compileKotlin.
2021-08-13 17:46:57 +02:00
Ivan Kochurkin
f2ffead881 Reduce allocations in KotlinTarget and modifier checkers 2021-08-13 18:32:29 +03:00
Ivan Kochurkin
2c1c24c042 [FIR] Implement WRONG_MODIFIER_CONTAINING_DECLARATION, DEPRECATED_MODIFIER_CONTAINING_DECLARATION 2021-08-13 18:32:28 +03:00
Ivan Kochurkin
cd6384eb20 [FIR] Fix handling of WRONG_MODIFIER_TARGET
Implement DEPRECATED_MODIFIER, DEPRECATED_MODIFIER_FOR_TARGET, REDUNDANT_MODIFIER_FOR_TARGET
2021-08-13 18:32:27 +03:00
Ivan Kochurkin
e85940a1ac Unbind modifiers checks from psi
Use common code in FE and FIR in modifier checker, refactor
2021-08-13 18:32:26 +03:00
Dmitry Petrov
ed0e3b0fed JVM_IR KT-47984 minor fixes after review 2021-08-13 18:08:55 +03:00
Dmitry Petrov
f8503ba1bf JVM_IR KT-47984 minor avoid using @Deprecated function in tests 2021-08-13 18:08:55 +03:00
Dmitry Petrov
55663a0fb1 JVM_IR KT-47984 allow only limited list of GETSTATICs in arg loading 2021-08-13 18:08:54 +03:00
Dmitry Petrov
32c51cbb45 JVM_IR KT-47984 minor drop unneeded caching 2021-08-13 18:08:53 +03:00
Dmitry Petrov
15c41b2610 JVM_IR KT-47984 add test for argument reordering 2021-08-13 18:08:52 +03:00
Dmitry Petrov
edd2ca775b JVM_IR KT-47984 use stack size calculator from ASM 2021-08-13 18:08:52 +03:00
Dmitry Petrov
5096e8c5c4 JVM_IR KT-47984 transform inplace arguments before inlining 2021-08-13 18:08:49 +03:00
Dmitry Petrov
7a99f9ff2e JVM_IR KT-47984 allow noinline functional inplace args 2021-08-13 18:08:48 +03:00
Dmitry Petrov
9be941def2 JVM_IR KT-47984 don't move inplace arguments with suspension points 2021-08-13 18:08:47 +03:00
Dmitry Petrov
9acdcc7590 JVM_IR KT-47984 minor cleanup 2021-08-13 18:08:47 +03:00
Dmitry Petrov
bf362abb57 JVM_IR KT-47984 update LVT entries for transformed instructions 2021-08-13 18:08:46 +03:00
Dmitry Petrov
6b18f33f92 JVM_IR KT-47984 don't transform calls with non-local jumps in arguments 2021-08-13 18:08:45 +03:00
Dmitry Petrov
b01c13a4df JVM_IR KT-47984 inplace arguments inlining for @InlineOnly functions 2021-08-13 18:08:44 +03:00
Dmitry Petrov
ec90649854 JVM_IR minor cleanup in inliner 2021-08-13 18:08:43 +03:00
Pavel Kunyavskiy
d88a665fa8 [K/N] Implement Lazy for new mm 2021-08-13 13:20:59 +00:00
Ivan Kylchik
2f2e608502 Expand the possibilities of object's interpretation
It is possible to create object in interpreter even if its
receiver symbol came from function parameter instead of object's class.
#KT-48174 Fixed
2021-08-13 16:18:36 +03:00
Ivan Kylchik
492b8acf93 Rename some methods in interpreter's stack to make their purpose clearer 2021-08-13 16:18:34 +03:00
Ivan Kylchik
69fe7e66a5 Introduce some helpful type aliases in interpreter 2021-08-13 16:18:32 +03:00
Ivan Kylchik
1808f14677 Switch from using of MutableList to ArrayDeque in interpreter's stack 2021-08-13 16:18:32 +03:00
Ivan Kylchik
ac2dffa74e Speed up interpreter's stack by using map of variables instead of list 2021-08-13 16:18:31 +03:00
Ivan Kylchik
a630273af2 Speed up interpreter's intrinsic check by introducing map of handlers 2021-08-13 16:18:30 +03:00
Ivan Kylchik
bc9b2fd78b Uncomment some test cases in reflection test data for interpreter 2021-08-13 16:18:29 +03:00
Ivan Kylchik
23b315446f Support sam conversion in ir interpreter 2021-08-13 16:18:28 +03:00
Ivan Kylchik
b85a796492 Support interpretation for floorDiv and mod functions 2021-08-13 16:18:28 +03:00
Ivan Kylchik
f9607292b5 Add additional useful ir classes into IrInterpreterEnvironment 2021-08-13 16:18:26 +03:00
Ivan Kylchik
b46a42be33 Drop toIrConst function with IrBuiltIns parameter 2021-08-13 16:18:25 +03:00
Pavel Kunyavskiy
7bddc2a815 [K/N] Add new exception for CallsChecker 2021-08-13 13:12:21 +00:00
Mikhail Glukhikh
4e4d36f85a FIR: take lower priority into account during references EagerResolve
#KT-48158 Fixed
2021-08-13 11:14:04 +03:00
Mikhail Glukhikh
a21d281c19 FIR: fix capturing on intersection types #KT-48109 Fixed 2021-08-13 11:14:03 +03:00
Mikhail Glukhikh
a04913a197 FIR: use captureFromTypeParameterUpperBoundIfNeeded for argument types
#KT-48161 Fixed
2021-08-13 11:14:02 +03:00
Mikhail Glukhikh
73a8b4544a FIR: don't report EQUALITY_NOT_APPLICABLE for classes from java.*
Workaround for KT-48113
2021-08-13 11:14:01 +03:00
Mikhail Glukhikh
b617aca8ee FIR: fix scope order for super-type resolve #KT-48159 Fixed 2021-08-13 11:14:01 +03:00
Mikhail Glukhikh
ca98417a0c FIR: add test for erroneous type inference in UAST (KT-48159) 2021-08-13 11:14:00 +03:00
Mikhail Glukhikh
b1bcbaf48f FirConstChecks: support "Some string".length case properly
#KT-48165 Fixed
2021-08-13 11:13:59 +03:00
Mikhail Glukhikh
f6413c41a0 FIR: fix serialization of JvmField-properties of local classes
#KT-48175 Fixed
2021-08-13 11:13:58 +03:00
Mikhail Glukhikh
2e2edf398c FIR: consider enum class overridden members non-final #KT-48164 Fixed 2021-08-13 11:13:57 +03:00
Nikolay Krasko
8e32bbbe90 Clean up 203.8084.24 dependencies a bit 2021-08-12 21:15:32 +03:00
Nikolay Krasko
23c438aa03 Clean up 203.6682.168 dependencies 2021-08-12 21:15:31 +03:00
Nikolay Krasko
63d1e195e0 Clean up 202.7660.26 dependencies 2021-08-12 21:15:31 +03:00
Nikolay Krasko
9e0ba8c3d2 Clean up 193.6494.7 mentionings 2021-08-12 21:15:30 +03:00
Nikolay Krasko
c56b6455f1 Clean up 202.7660.3 mentionings 2021-08-12 21:15:29 +03:00
Igor Yakovlev
9b9a529b7f Reflect addition of new 'kotlin.jvm-run-configurations' module in Gradle 2021-08-12 18:16:00 +02:00
Ivan Kochurkin
d346953de9 [FIR] Move FirCommaInWhenConditionChecker to syntax subdirectory 2021-08-12 18:42:26 +03:00
Tianyu Geng
1679da45ab FIR checker: COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT
FIR simply ignores anything after the first comma if the when expression
doesn't have a subject. Hence, the checker has to rely on PSI structure
instead.
2021-08-12 18:42:26 +03:00
Sergey Bogolepov
db12a96e54 Fix test that was broken by e159392d by disabling native caches. 2021-08-12 18:02:23 +03:00
Ting-Yuan Huang
39c6be86cb K2JsIrCompiler: pass right configuration when creating lib module 2021-08-12 18:01:59 +03:00
Ting-Yuan Huang
06d3c6f233 Support repeated analysis and frontend-only-mode in K2JsIrCompiler 2021-08-12 18:01:58 +03:00
Ting-Yuan Huang
e75ca75e3e K2JsIrCompiler: hoist common front-end preparation logic
Instead of creating ModuleStructure and run analysis in each backend,
the common preparation logic is moved into K2JsIrCompiler.doExecute().
2021-08-12 18:01:56 +03:00
Igor Laevsky
94af3adb4b WASM: Disable flaky test 2021-08-12 17:32:35 +03:00
Alexander Udalov
1b98723b3f JVM IR: fix incorrect detection of interface method impls in Java
The problem in the test case was that `JImpl.entrySet` was detected by
ReplaceDefaultImplsOverriddenSymbols as a class fake override, which
overrides non-abstract interface method. Thus, overriddenSymbols of
`MyMap.entrySet` were changed in
`ReplaceDefaultImplsOverriddenSymbols.visitSimpleFunction`.

Later, BridgeLowering tried to determine which special bridges to
generate for `MyMap.<get-entries>`, and for that it inspected existing
methods and their overrides.

Normally we would generate the following special bridge:

    getEntries()Ljava/util/Set;
        invokespecial JImpl.entrySet()Ljava/util/Set;

However, because of incorrect overrides, the generated class method was
selected here instead of the expected `Map.<get-entries>`:
06001fc091/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/BridgeLowering.kt (L282)
and since the JVM signature of the generated class method is the same as
that of the fake override in MyMap, we never got to generating the
special bridge.

The solution is to skip Java classes when looking for class methods
which override non-abstract interface methods. This logic only makes
sense for Kotlin code, because only Kotlin has DefaultImpls, and the
requirement to generate non-abstract fake overrides of interface methods
as actual methods in the bytecode, delegating to DefaultImpls.

 #KT-48167 Fixed
2021-08-12 13:51:33 +02:00
Alexander Udalov
d124239025 JVM IR: do not attempt to mangle function expressions
For some reasons, lambdas and function expressions are represented
slightly differently in psi2ir. Lambdas are translated to a block with a
function of origin LOCAL_FUNCTION_FOR_LAMBDA and name "<anonymous>", but
function expressions are translated to a block with DEFINED function
"<no name provided>".

Tweak the condition for detecting local functions a bit, to avoid
similar situation in the future if we add some other origins for local
functions.

 #KT-48207 Fixed
2021-08-12 13:50:23 +02:00
Mikhail Glukhikh
dd3eb53904 Drop forgotten foreign annotation test data 2021-08-12 14:25:18 +03:00
Yahor Berdnikau
3acb96e474 Allow running KotlinJavaToolchainTest on any user JDK. 2021-08-12 10:00:23 +02:00
Bingran
c57302abba Only check ExternalDependency when customizing kotlin dependencies
This commit fixes the issue where kgp checks group/version of project
dependencies which is uncompatible with project isolation. With this
change, kgp will only check ExternalDependency which should be enough
for setting up kotlin dependencies.

This change also changes the way we apply cache redirector gradle
files to all projects when setting up test projects. To make it
compatible with project isolation, we should move away from using
project.getAllProjects() function.

^KT-47792 Fixed
Test: existing + SimpleKotlinGradleIT.testProjectIsolation
2021-08-12 09:51:20 +02:00
Andrey Zinovyev
1338675833 [FIR] Fix while's label, when condition has lambda
#KT-48116 Fixed
2021-08-12 10:20:45 +03:00
Alexander Shabalin
06001fc091 [K/N] Tweak fronted warning messages for the new MM 2021-08-11 20:06:19 +00:00
Andrey Zinovyev
d3905fd763 Add dist dependency for tests
Because some tests require stdlib
2021-08-11 21:57:16 +03:00
Andrey Zinovyev
3ec9599bc4 [FIR][CFG] Partial support of postponed Nothing calls
In try blocks, last call won't be completed when building node for it
This is workaround to partially reconstruct nothing stub node for such
calls. Should work for non-local returns in try only.
#KT-48160 Fixed
2021-08-11 21:57:14 +03:00
Ivan Kochurkin
445e5122c1 [FIR] Fix conversion of underscored value parameters in functions
Fix false REDECLARATION
2021-08-11 21:52:46 +03:00
Ilya Kirillov
ebe96ec79a FIR IDE: fix reference resolve with invalid number of type args 2021-08-11 18:09:05 +02:00
Ilya Kirillov
a8f7bf5fbc HL API: cleanup reference resolve testdata 2021-08-11 18:09:05 +02:00
Ilya Kirillov
2e3b576342 FIR IDE: change destructing declaration reference behaviour to match FE1.0 plugin behaviour 2021-08-11 18:09:05 +02:00
Pavel Punegov
aef45f0997 [Native] Exclude on wasm initializers tests.
Tests use exceptions and workers that are not supported in wasm
2021-08-11 13:56:48 +00:00
Pavel Punegov
d7f5015faa [Native] wasm: use JS pow method
Replace usage of C pow() function with JS to fix the issue
with stack overflow caused by invocation of missing pow function
2021-08-11 13:56:47 +00:00
Pavel Punegov
cd487efbe9 [Native][test] Exclude FP parsing tests that require exceptions on WASM 2021-08-11 13:56:47 +00:00
pyos
623b289616 Regenerate foreign annotation test data for FIR 2021-08-11 15:58:02 +03:00
pyos
58110709f3 Get rid of lambdas in AbstractForeignAnnotationsTestBase
Also enable the features from the previous two commits
2021-08-11 15:58:01 +03:00
pyos
28c473074c Permit overriding the FIR test in FirTestDataConsistencyHandler 2021-08-11 15:58:01 +03:00
pyos
cd26ef2bb5 Add FIR version of JspecifyDiagnosticComplianceHandler 2021-08-11 15:58:01 +03:00
Mads Ager
608b88996a [JVM_IR] Fix inlining of callable references to extension methods.
Check directly that the referenced function is an extension
function instead of relying on the annotation on the type.

^ KT-47988 Fixed.
2021-08-11 13:29:11 +02:00
Mikhael Bogdanov
1760befa37 [KAPT] Add experimental JDK 17 support
#KT-47583 Fixed
2021-08-11 10:05:24 +02:00
Igor Chevdar
81ce59cf48 [K/N][IR][codegen] Implemented eager initialization
Properties marked with @EagerInitialization will be initialized at program/worker start
even in lazy initialization mode
2021-08-11 11:53:19 +05:00
Sergey Bogolepov
e159392d22 [K/N] Enable caches for iosArm64 and linuxX64 by default 2021-08-11 06:38:59 +00:00
Nikita Bobko
5455800de4 [imltogradle] Exclude 'kotlin.util.compiler-dependencies' module from generation
This module is used as helper module in JPS project module to make sure that IDEA will download
all required dependencies. There are some dependencies which IDEA cannot determine as used so
we force it to download them (kotlinc.kotlin-dist, kotlinc.kotlin-compiler-testdata)

We don't need this module in Gradle project model

This commit fixes:
```
Could not resolve project :prepare:ide-plugin-dependencies:kotlin-compiler-testdata-for-ide.
Required by:
    project :kotlin-ide.kotlin.util.compiler-dependencies
```
2021-08-11 02:17:52 +02:00
Nikita Bobko
747cc7d55d [imltogradle] Fix other kotlinc libraries which don't follow kotlinc.* naming
e.g. kotlin-reflect
2021-08-11 02:17:51 +02:00
Nikita Bobko
784273ac5b [imltogradle] Add additional check for absence of snapshot version in JpsLikeJarDependency 2021-08-11 02:17:51 +02:00
Nikita Bobko
493fdbd418 Fix kotlin stdlib handling for 212 IDEA in ide-iml-to-gradle-generator 2021-08-11 02:17:51 +02:00
Nikita Bobko
8ad368e990 Update verification-metadata.xml with 212.4746.92 artifacts 2021-08-11 02:17:50 +02:00
Ilya Goncharov
40d19b50c5 [Gradle, JS] Use Gradle's hashers 2021-08-10 18:45:09 +00:00
Ilya Goncharov
bfcd954dd3 [Gradle, JS] Add test on not updating Node.JS if it was downloaded
^KT-47845 fixed
2021-08-10 18:45:09 +00:00
Ilya Goncharov
b8330deefa [Gradle, JS] Consider potential hash of nodejs and yarn
^KT-47845 fixed
2021-08-10 18:45:08 +00:00
Ilya Goncharov
5ec19c2417 [Gradle, JS] Up-to-date checks for Node js and yarn
^KT-47845 fixed
2021-08-10 18:45:08 +00:00
Ilya Kirillov
1a1f6b0c0b Regenerate FirIdeSpecTest 2021-08-10 20:06:36 +02:00
Ilya Kirillov
017448e359 FIR IDE: make KtExpression.getKtType() to return null for non-expressions 2021-08-10 18:58:06 +02:00
Roman Artemev
d3ddeef67f [JS IR] Wrap private top level function with internal accessor stub
In case internal inline function references private top level function
after inline such function (T.L.P.) couldn't be referenced
in klib and IC cache. So create internally visible accessors for P.T.L.
function similar to what JVM backend does.

 - add box test
2021-08-10 19:52:08 +03:00
Roman Artemev
b3dbca7ea6 [JS IC] Fix test runner 2021-08-10 19:52:07 +03:00
Tianyu Geng
06ee84f809 FIR checker: report AMBIGUOUS_SUPER 2021-08-10 19:36:44 +03:00
Ivan Kochurkin
5b9ce7e823 [FIR] Use typeArgumentsList from delegatedTypeRef instead of accessing via tree 2021-08-10 19:36:43 +03:00
Tianyu Geng
280c445783 FIR checker: check super reference
This change touches the following diagnostics to make them behave closer
to FE1.0

* SUPER_NOT_AVAILABLE
* SUPER_IS_NOT_AN_EXPRESSION
* INSTANCE_ACCESS_BEFORE_SUPER_CALL
* NOT_A_SUPERTYPE

Other than tweaking the diagnostics, this change also alters resolution
by consider marking `super` with mismatched type parameter as
errorenous. As a result, the following code no longer resolves.

```
class A: B() {
  fun test() {
    super<String>.length
    //            ^^^^^^ FIR currently resolves this to `String.length`.
    //                   With this change, `length` becomes unresolved
    //                   instead
  }
}
```

Also, now we report `UNRESOLVED_LABEL` on unresolved label on `super`
reference, though FE1.0 reports `UNRESOLVED_REFERENCE`.

All the errors above are reported as ConeDiagnostics and hence some
checkers are deleted.

In addition, it also suppresses more downstream (mostly unresolved)
errors if the receiver has errors. FE1.0 doesn't do it for all the cases
we have here. But it seems nicer to reduce these "redundant" unresolved
errors.
2021-08-10 19:36:43 +03:00
Tianyu Geng
bcf6202863 FIR checker: fix position strategy for UNRESOLVED_LABEL 2021-08-10 19:36:04 +03:00
Tianyu Geng
45d31fdba2 FIR: fix atomic qualified acess sharing the same PSI with callee ref
Consider an atomic reference `i`, it's FIR representation is

- FirQualifiedAccessExpression
  - calleeReference : FirNamedReference

Currently, both of the above FIR elements uses the same PSI element as
the source. Such problems are not present with `this` or `super` because
we manually mark them as `ExplicitThisOrSuperReference`.

This change generalizes the previous `ExplicitThisOrSuperReference` as
`ReferenceInAtomicQualifiedAccess` and fixes it for more cases.
2021-08-10 19:35:19 +03:00
Alexander Udalov
3bc0eaff59 Fix warnings in stdlib samples and test modules 2021-08-10 17:57:50 +02:00
Alexander Udalov
0d1380c232 Fix warnings in generator modules 2021-08-10 17:57:50 +02:00
Ivan Kochurkin
2ca3adbcb2 [FIR] Throw REDECLARATION for duplicated type parameters in declarations 2021-08-10 15:09:27 +00:00
Ivan Kochurkin
c19598c2fc [FIR] Throw REDECLARATION for duplicated enum entries 2021-08-10 15:09:26 +00:00
Ivan Kochurkin
9736cc162b [FIR] Throw REDECLARATION for duplicated value parameters in function
Add new test file
2021-08-10 15:09:26 +00:00
Ivan Kochurkin
fd92b851a2 [FIR] Implement PACKAGE_OR_CLASSIFIER_REDECLARATION
Fix REDECLARATION positioning
2021-08-10 15:09:25 +00:00
Nikolay Krasko
1c678be0d3 Drop 202 bunch support 2021-08-10 15:25:46 +03:00
Dmitriy Dolovov
cfc4e715e4 [IR] Tests for IR linking error reporting
^KT-44626
2021-08-10 14:02:45 +03:00
Dmitriy Dolovov
c1fb40a436 [IR] Enhance error reporting for IR linking issues
^KT-44626

Typical use case:
- There are two KLIB libraries: A and B.
- Library A has two versions: A.v1 (older) and A.v2 (newer).
- A.v2 is ABI-incompatible with A.v1.
- B depends on A and was compiled against A.v1.
- An attempt to build the application with A.v2 and B fails with weird error message. It's unclear for end user what's wrong and what needs to be done to fix the issue.

The fix improves error reporting for the following particular cases:
- A symbol that is gone (KT-41378)
- A class that became a typealias (KT-47285, KT-46697)
- A typealias that became a class (KT-46340)
2021-08-10 14:02:40 +03:00
Dmitriy Dolovov
672b972b38 [Native] Add '-Xexternal-dependencies' CLI parameter to pass external deps
^KT-44626
2021-08-10 14:02:35 +03:00
Dmitriy Dolovov
ac387b1f26 [Gradle, Native] Pass external dependencies to Kotlin/Native link tasks
^KT-44626
2021-08-10 14:02:27 +03:00
Mikhail Glukhikh
2c31d2e67d FirTestDataConsistencyHandler: return back FIR files auto-generation 2021-08-10 13:19:28 +03:00
Mikhail Glukhikh
8c51c3c5c3 FirTestDataConsistencyHandler: fix behavior on Windows (partial revert) 2021-08-10 13:19:27 +03:00
Mikhail Glukhikh
512a851c65 Minor fix of test data for consistency with FIR 2021-08-10 13:19:26 +03:00
Mikhail Glukhikh
85a2a3255d Add new SENSELESS_COMPARISON in FIR foreign annotation tests 2021-08-10 13:19:26 +03:00
pyos
cdc0f36859 Permit silencing FIR tests with results depending on configuration 2021-08-10 13:19:25 +03:00
pyos
33251f6d50 Generate foreign annotation test data for FIR 2021-08-10 13:19:23 +03:00
pyos
5873511f64 Generalize AbstractForeignAnnotationsTestBase to FIR 2021-08-10 13:19:22 +03:00
pyos
e2e0358505 Remove "FIR" foreign annotation tests
They do not actually use FIR.
2021-08-10 13:19:21 +03:00
Tianyu Geng
1607a8231a FIR checker: ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS 2021-08-10 13:02:10 +03:00
Tianyu Geng
927723c766 FIR checker: fix JAVA_TYPE_MISMATCH checker
First, the order of arguments is swapped.
Second, projection erasure for argType was too aggressive. We should
instead retain the projections that are under an invariant position.
2021-08-10 13:00:18 +03:00
Tianyu Geng
cc531149e5 Ignore kotlin-ide directory 2021-08-10 13:00:14 +03:00
Hung Nguyen
eb94167ff2 Move RuntimeModuleData from :core:descriptors.runtime to :core:descriptors.jvm
We are working on a feature in the Kotlin Gradle plugin called
`kotlin.incremental.useClasspathSnapshot` to improve incremental
Kotlin compilation.

To allow reuse when writing this feature, this commit moves most of the
code in RuntimeModuleData (in the ':core:descriptors.runtime' project)
to DeserializationComponentsForJava (in the ':core:descriptors.jvm'
project), so that the API can be accessed from the
':kotlin-gradle-plugin' and ':kotlin-build-common' projects where the
feature is written.

Bug: KT-45777
Test: Existing tests should pass (this is a refactoring-only change)
2021-08-10 12:29:45 +03:00
Hung Nguyen
170184dce4 KT-45777: Refactor RuntimeModuleData to support classpath snapshotting
We are working on a feature in the Kotlin Gradle plugin called
`kotlin.incremental.useClasspathSnapshot` to improve incremental
Kotlin compilation.

In this feature, we need to extract ABI information from a .class file.
If the .class file is a Kotlin class, this info can be found in the
class header data. But if the .class file is a Java class, this info is
not readily available.

The RuntimeModuleData class in the ':core:descriptors.runtime' project
can help with that: It uses reflection to generate `ClassDescriptor`s.

However, reflection requires a full classpath to work correctly, whereas
we want to generate a `ClassDescriptor` directly for each class file
(also, reflection is probably slow).

To address that, this commit refactors RuntimeModuleData so that it can
support a generic Kotlin/JavaClassFinder, which can be based on either
reflection or bytecode analysis. The existing code continues to use
reflection while the new feature will use bytecode analysis (e.g., using
the existing BinaryJavaClass).

Bug: KT-45777
Test: Existing tests should pass (this is a refactoring-only change)
2021-08-10 12:29:44 +03:00
Hung Nguyen
206457d9ff KT-45777: Take snapshots and compute changes for Kotlin classes
Reuse the existing IncrementalJvmCache to take snapshots and compute
changes for Kotlin classes.

Java classes will be handled next.

Bug: KT-45777
Test: New ClasspathSnapshotterTest, ClasspathChangesComputerTest
2021-08-10 12:22:58 +03:00
Alexander Shabalin
7e04bb4bf1 [K/N] Refactor unhandled exception handling API
* Do not reset unhandled exception hook
* Add processUnhandledException to perform default unhandled exception
  processing
* Add terminateWithUnhandledException to report the unhandled exception
  and terminate the program
* Use the default unhandled exception processing in entrypoint, interop
  boundaries and in Worker.executeAfter
* Add -Xworker-exception-handling to control exception processing of
  Worker.executeAfter. By default its the old behaviour with the old MM,
  and new behaviour with the new MM.
2021-08-10 08:22:55 +00:00
Ilya Goncharov
766857881a [JS IR] Review remarks
- Use intrinsic on this
- Enqueue invoke for DCE
- Change transform
- Ignore instead of target backend

^KT-46204 fixed
2021-08-10 07:24:51 +00:00
Ilya Goncharov
2f0f88062a [JS IR] Change global map in context to mapping
^KT-46204 fixed
2021-08-10 07:24:50 +00:00
Ilya Goncharov
a28138eb72 [JS IR] Change js function on Kotlin code
^KT-46204 fixed
2021-08-10 07:24:49 +00:00
Ilya Goncharov
b6c3132614 [JS IR] Ignore test for legacy backend
^KT-46204 fixed
2021-08-10 07:24:49 +00:00
Ilya Goncharov
627af332b1 [JS IR] Use PublishedApi for intrinsic
^KT-46204 fixed
2021-08-10 07:24:48 +00:00
Ilya Goncharov
e6af3ff6a8 [JS IR] Rename and doc new intrinsics, add new intrinsic to call suspend fun as supertype
^KT-46204 fixed
2021-08-10 07:24:48 +00:00
Ilya Goncharov
a70fc99130 [JS IR] Add intrinsic to call suspend functions as super type
^KT-46204 fixed
2021-08-10 07:24:47 +00:00
Ilya Goncharov
22d202e657 [JS IR] Add test on type check of suspend functional interfaces
^KT-46204 fixed
2021-08-10 07:24:47 +00:00
Ilya Goncharov
755f847ab9 [JS IR] Use invoke for coroutines in runtime
^KT-46204 fixed
2021-08-10 07:24:46 +00:00
Ilya Goncharov
3c9dcdbbee [JS IR] Generate suspend function as invoke
[JS IR] Fix type check utils to work with array of arities

[JS IR] Store multiple arities for suspend functional interface implementers

^KT-46204 fixed
2021-08-10 07:24:46 +00:00
Ilya Goncharov
8a812996dd [Frontend, JS] Not report error in for inheritance suspend function interface
^KT-46204 fixed
2021-08-10 07:24:45 +00:00
Georgy Bronnikov
1d913a6bf0 JVM_IR: add test for serialization of raw types 2021-08-10 00:37:46 +03:00
Georgy Bronnikov
3b8cb4b00d ModuleTransformerForTwoFilesBoxTests -> SplittingModuleTransformerForBoxTests
Need to include Java files in IR serialization tests, so generalize
TwoFilesBoxTest for more than two files.
2021-08-10 00:37:44 +03:00
Georgy Bronnikov
13cf9329b2 IR: always serialize constant initializers for fields. 2021-08-10 00:37:42 +03:00
Georgy Bronnikov
7e71bd8f1c Add module dependency to fir/checkers/checkers-component-generator
This is a transitive dependency needed when bootstrapping in
-Xserialize-ir mode.
2021-08-10 00:37:41 +03:00
Georgy Bronnikov
307de0be89 IR: always update deserializedSymbols in referenceLocalIrSymbol
The symbol created in deserializeIrSymbolToDeclare might be discarded
when an existing declaration is used in deserialization (as it happens
when deserializing IR bodies for JVM declarations).
2021-08-10 00:37:37 +03:00
Georgy Bronnikov
eccbf38061 IR: use existing type parameters when deserializing IR 2021-08-10 00:37:36 +03:00
Georgy Bronnikov
fb801bdc33 IR: fix mangling of toplevel properties 2021-08-10 00:37:36 +03:00
Georgy Bronnikov
54957ead5c JVM_IR: add test for signatures of flexible types 2021-08-10 00:37:27 +03:00
Georgy Bronnikov
1d2d1f9e8d IR: change mangling for flexible types in DescriptorMangleComputer
This reverts commit 4af2aaedb1.
2021-08-10 00:37:24 +03:00
Alexander Udalov
afacff326d JVM IR: fix smart cast on argument of 'throw'
#KT-48163 Fixed
2021-08-09 22:34:44 +02:00
Ilya Kirillov
cb37a05b79 Restore LC compiler testdata 2021-08-09 20:29:22 +02:00
Jinseong Jeon
e64f7ffb98 FIR LC: populate ctor in anonymous objects
Note that enum entries are modeled as anonymous objects in FIR too.
2021-08-09 20:29:20 +02:00
Jinseong Jeon
75c76e2b57 FIR IDE: resolve implicit ctor delegation calls 2021-08-09 20:29:19 +02:00
Jinseong Jeon
f7f51cf38e FIR IDE: allow implicit ctor call for psi retrieval 2021-08-09 20:29:19 +02:00
Jinseong Jeon
4396482fed FIR IDE: fix nullability of KtType variants 2021-08-09 20:29:19 +02:00
Jinseong Jeon
46a0c4be4b FIR LC: populate property from primary ctor later 2021-08-09 20:29:18 +02:00
Jinseong Jeon
fba480875f FIR LC: populate constructors after member methods 2021-08-09 20:29:18 +02:00
Jinseong Jeon
edc134ef2d FIR IDE: drop stale test results in kt files 2021-08-09 20:29:17 +02:00
Jinseong Jeon
ba8f2e6bf3 FIR LC: introduce FirLightParameterList
LightParameterListBuilder, as a subtype of PsiParameterList, is good
enough for LightMethod's parameter list abstraction. However, it does
not have a parent link, which bothers upward conversion in UAST
(a.k.a. convertParent APIs). So we need an abstraction similar to
KtLightParameterList (in FE 1.0 LC).
2021-08-09 20:29:17 +02:00
Ivan Kochurkin
c1afb6354b [FIR] Restore UPPER_BOUND_VIOLATED and TYPE_VARIANCE_CONFLICT as errors, fix TestStep.kt 2021-08-09 18:19:58 +03:00
Viacheslav Kormushkin
d670743a2f Cocoapods plugin: error reporting in case CocoaPods is not installed on users machine
#KT-47362
2021-08-09 12:54:29 +00:00
1303 changed files with 25223 additions and 22346 deletions

1
.bunch
View File

@@ -1,2 +1 @@
203
202

1
.gitignore vendored
View File

@@ -68,3 +68,4 @@ distTmp/
outTmp/
/test.output
/kotlin-native/dist
kotlin-ide/

View File

@@ -25,6 +25,7 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.build.GeneratedJvmClass
import org.jetbrains.kotlin.incremental.storage.*
import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
@@ -113,7 +114,7 @@ open class IncrementalJvmCache(
}
open fun saveFileToCache(generatedClass: GeneratedJvmClass, changesCollector: ChangesCollector) {
saveClassToCache(KotlinClassInfo(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
saveClassToCache(KotlinClassInfo.createFrom(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
}
/**
@@ -612,16 +613,6 @@ class KotlinClassInfo private constructor(
val inlineFunctionsMap: LinkedHashMap<String, Long>
) {
constructor(kotlinClass: LocalFileKotlinClass) : this(
kotlinClass.classId,
kotlinClass.classHeader.kind,
kotlinClass.classHeader.data,
kotlinClass.classHeader.strings,
kotlinClass.classHeader.multifileClassName,
getConstantsMap(kotlinClass.fileContents),
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
)
val className: JvmClassName by lazy { JvmClassName.byClassId(classId) }
fun scopeFqName(companion: Boolean = false) = when (classKind) {
@@ -630,6 +621,36 @@ class KotlinClassInfo private constructor(
}
else -> className.packageFqName
}
companion object {
fun createFrom(kotlinClass: LocalFileKotlinClass): KotlinClassInfo {
return KotlinClassInfo(
kotlinClass.classId,
kotlinClass.classHeader.kind,
kotlinClass.classHeader.data,
kotlinClass.classHeader.strings,
kotlinClass.classHeader.multifileClassName,
getConstantsMap(kotlinClass.fileContents),
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
)
}
/** Creates [KotlinClassInfo] from the given classContents, or returns `null` if the class is not a kotlinc-generated class. */
fun tryCreateFrom(classContents: ByteArray): KotlinClassInfo? {
return FileBasedKotlinClass.create(classContents) { classId, _, classHeader, _ ->
KotlinClassInfo(
classId,
classHeader.kind,
classHeader.data,
classHeader.strings,
classHeader.multifileClassName,
getConstantsMap(classContents),
getInlineFunctionsMap(classHeader, classContents)
)
}
}
}
}
private fun getConstantsMap(bytes: ByteArray): LinkedHashMap<String, Any> {
@@ -694,4 +715,4 @@ private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray):
}, 0)
return result
}
}

View File

@@ -148,7 +148,7 @@ extra["versions.kotlinx-collections-immutable-jvm"] = immutablesVersion
extra["versions.ktor-network"] = "1.0.1"
if (!project.hasProperty("versions.kotlin-native")) {
extra["versions.kotlin-native"] = "1.6.0-dev-1728"
extra["versions.kotlin-native"] = "1.6.0-dev-2972"
}
val useJvmFir by extra(project.kotlinBuildProperties.useFir)
@@ -315,15 +315,7 @@ extra["compilerArtifactsForIde"] = listOf(
// TODO: fix remaining warnings and remove this property.
extra["tasksWithWarnings"] = listOf(
":kotlin-stdlib:compileTestKotlin",
":kotlin-stdlib-jdk7:compileTestKotlin",
":kotlin-stdlib-jdk8:compileTestKotlin",
":plugins:uast-kotlin-base:compileKotlin",
":plugins:uast-kotlin-base:compileTestKotlin",
":plugins:uast-kotlin:compileKotlin",
":plugins:uast-kotlin:compileTestKotlin",
":plugins:uast-kotlin-fir:compileKotlin",
":plugins:uast-kotlin-fir:compileTestKotlin"
":kotlin-gradle-plugin:compileKotlin"
)
val tasksWithWarnings: List<String> by extra
@@ -482,15 +474,10 @@ allprojects {
}
if (!kotlinBuildProperties.disableWerror) {
// For compiler and stdlib, allWarningsAsErrors is configured in the corresponding "root" projects
// (compiler/build.gradle.kts and libraries/commonConfiguration.gradle).
val projectsWithWarningsAsErrors = listOf("core", "plugins").map { File(it).absoluteFile }
if (projectsWithWarningsAsErrors.any(projectDir::startsWith)) {
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
if (path !in tasksWithWarnings) {
kotlinOptions {
allWarningsAsErrors = true
}
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
if (path !in tasksWithWarnings) {
kotlinOptions {
allWarningsAsErrors = true
}
}
}

View File

@@ -79,7 +79,6 @@ val jpsStandalone by configurations.creating
val jpsStandaloneForIde by configurations.creating
val intellijCore by configurations.creating
val intellijCoreForIde by configurations.creating
val nodeJSPlugin by configurations.creating
/**
* Special repository for annotations.jar required for idea runtime only.

View File

@@ -82,8 +82,6 @@ fun Project.intellijCoreDep() = "kotlin.build:intellij-core:${rootProject.extra[
fun Project.jpsStandalone() = "kotlin.build:jps-standalone:${rootProject.extra["versions.intellijSdk"]}"
fun Project.nodeJSPlugin() = "kotlin.build:NodeJS:${rootProject.extra["versions.idea.NodeJS"]}"
fun Project.jpsBuildTest() = "com.jetbrains.intellij.idea:jps-build-test:${rootProject.extra["versions.intellijSdk"]}"
fun Project.kotlinxCollectionsImmutable() = "org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:${rootProject.extra["versions.kotlinx-collections-immutable"]}"

View File

@@ -5,21 +5,15 @@
package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.coroutinesIntrinsicsPackageFqName
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
import org.jetbrains.kotlin.name.Name
val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED")
fun FunctionDescriptor.isBuiltInIntercepted(languageVersionSettings: LanguageVersionSettings): Boolean =
!languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines) &&
isTopLevelInPackage("intercepted", languageVersionSettings.coroutinesIntrinsicsPackageFqName().asString())
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings: LanguageVersionSettings): Boolean =
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(): Boolean =
isTopLevelInPackage(
"suspendCoroutineUninterceptedOrReturn",
languageVersionSettings.coroutinesIntrinsicsPackageFqName().asString()
StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.asString()
)

View File

@@ -475,7 +475,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
List<Type> superCtorArgTypes = new ArrayList<>();
if (superClassAsmType.equals(LAMBDA) || functionReferenceTarget != null ||
CoroutineCodegenUtilKt.isCoroutineSuperClass(state.getLanguageVersionSettings(), superClassAsmType.getInternalName())
CoroutineCodegenUtilKt.isCoroutineSuperClass(superClassAsmType.getInternalName())
) {
iv.iconst(CodegenUtilKt.getArity(funDescriptor));
superCtorArgTypes.add(Type.INT_TYPE);

View File

@@ -89,7 +89,6 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
import org.jetbrains.kotlin.types.*;
import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl;
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
import org.jetbrains.kotlin.types.model.KotlinTypeMarker;
import org.jetbrains.kotlin.types.model.TypeParameterMarker;
import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
import org.jetbrains.kotlin.util.OperatorNameConventions;
@@ -1288,11 +1287,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@NotNull
private static CallableDescriptor unwrapOriginalReceiverOwnerForSuspendLambda(@NotNull MethodContext context) {
FunctionDescriptor originalForDoResume =
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME);
FunctionDescriptor originalForInvokeSuspend =
context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND);
if (originalForDoResume != null) {
return originalForDoResume;
if (originalForInvokeSuspend != null) {
return originalForInvokeSuspend;
}
if (context.getFunctionDescriptor().isSuspend()) {
@@ -2617,26 +2616,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
? coroutineInstanceValueForSuspensionPoint
: getContinuationParameterFromEnclosingSuspendFunction(resolvedCall);
if (coroutineInstanceValue != null && needsExperimentalCoroutinesWrapper(resolvedCall.getCandidateDescriptor())) {
StackValue releaseContinuation = coroutineInstanceValue;
coroutineInstanceValue = new StackValue(CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE) {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
) {
releaseContinuation.put(CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE, v);
invokeCoroutineMigrationMethod(
v,
"toExperimentalContinuation",
Type.getMethodDescriptor(
CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE,
CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE
)
);
}
};
}
tempVariables.put(continuationExpression, coroutineInstanceValue);
}
@@ -2774,7 +2753,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
SuspensionPointKind suspensionPointKind =
CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this, state.getLanguageVersionSettings());
CoroutineCodegenUtilKt.isSuspensionPoint(resolvedCall, this);
boolean maybeSuspensionPoint = suspensionPointKind != SuspensionPointKind.NEVER && !insideCallableReference();
boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
if (!(callableMethod instanceof IntrinsicWithSpecialReceiver)) {
@@ -2833,7 +2812,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
KotlinType unboxedInlineClass = CoroutineCodegenUtilKt.originalReturnTypeOfSuspendFunctionReturningUnboxedInlineClass(
(FunctionDescriptor) resolvedCall.getResultingDescriptor(), typeMapper);
if (unboxedInlineClass != null) {
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v, state.getLanguageVersionSettings());
CoroutineCodegenUtilKt.generateCoroutineSuspendedCheck(v);
}
}
@@ -2948,7 +2927,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
FunctionDescriptor original =
CoroutineCodegenUtilKt.getOriginalSuspendFunctionView(
unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal())),
bindingContext, state
bindingContext
);
FunctionDescriptor functionDescriptor =
@@ -5243,7 +5222,7 @@ The "returned" value of try expression with no finally is either the last expres
}
CodegenUtilKt.generateAsCast(
v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings(), state.getUnifiedNullChecks()
v, rightKotlinType, boxedRightType, safeAs, state.getUnifiedNullChecks()
);
return Unit.INSTANCE;
@@ -5297,7 +5276,7 @@ The "returned" value of try expression with no finally is either the last expres
return null;
}
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type, state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type);
return null;
});
}

View File

@@ -481,8 +481,7 @@ public class FunctionCodegen {
}
if (!functionDescriptor.isExternal()) {
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen, state.getJvmDefaultMode(),
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen, state.getJvmDefaultMode());
}
else if (staticInCompanionObject) {
// native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class
@@ -583,8 +582,7 @@ public class FunctionCodegen {
@NotNull JvmMethodSignature signature,
@NotNull FunctionGenerationStrategy strategy,
@NotNull MemberCodegen<?> parentCodegen,
@NotNull JvmDefaultMode jvmDefaultMode,
boolean isReleaseCoroutines
@NotNull JvmDefaultMode jvmDefaultMode
) {
mv.visitCode();
@@ -594,8 +592,7 @@ public class FunctionCodegen {
KotlinTypeMapper typeMapper = parentCodegen.typeMapper;
if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, typeMapper::mapAsmMethod)) {
generateTypeCheckBarrierIfNeeded(
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper,
isReleaseCoroutines);
new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), null, typeMapper);
}
Label methodEntry = null;
@@ -1430,8 +1427,7 @@ public class FunctionCodegen {
MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv);
if (delegateTo.getArgumentTypes().length > 0 && isSpecialBridge) {
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper,
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes(), typeMapper);
}
iv.load(0, OBJECT_TYPE);
@@ -1477,8 +1473,7 @@ public class FunctionCodegen {
@NotNull FunctionDescriptor descriptor,
@NotNull Type returnType,
@Nullable Type[] delegateParameterTypes,
@NotNull KotlinTypeMapper typeMapper,
boolean isReleaseCoroutines
@NotNull KotlinTypeMapper typeMapper
) {
BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription typeSafeBarrierDescription =
BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor);
@@ -1512,7 +1507,7 @@ public class FunctionCodegen {
} else {
targetBoxedType = boxType(delegateParameterTypes[i]);
}
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType, isReleaseCoroutines);
CodegenUtilKt.generateIsCheck(iv, kotlinType, targetBoxedType);
iv.ifeq(defaultBranch);
}
}

View File

@@ -5,13 +5,12 @@
package org.jetbrains.kotlin.codegen
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.coroutines.isSuspendLambdaOrLocalFunction
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
@@ -33,8 +32,7 @@ class JvmRuntimeTypes(
private val generateOptimizedCallableReferenceSuperClasses: Boolean
) {
private val kotlinJvmInternalPackage = MutablePackageFragmentDescriptor(module, FqName("kotlin.jvm.internal"))
private val kotlinCoroutinesJvmInternalPackage =
MutablePackageFragmentDescriptor(module, languageVersionSettings.coroutinesJvmInternalPackageFqName())
private val kotlinCoroutinesJvmInternalPackage = MutablePackageFragmentDescriptor(module, COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME)
private fun internal(className: String, packageFragment: PackageFragmentDescriptor = kotlinJvmInternalPackage): Lazy<ClassDescriptor> =
lazy { createClass(packageFragment, className) }
@@ -53,24 +51,16 @@ class JvmRuntimeTypes(
private val localVariableReference: ClassDescriptor by internal("LocalVariableReference")
private val mutableLocalVariableReference: ClassDescriptor by internal("MutableLocalVariableReference")
private val coroutineImpl: ClassDescriptor by internal("CoroutineImpl", kotlinCoroutinesJvmInternalPackage)
private val continuationImpl: ClassDescriptor by coroutinesInternal("ContinuationImpl")
private val restrictedContinuationImpl: ClassDescriptor by coroutinesInternal("RestrictedContinuationImpl")
private val suspendLambda: ClassDescriptor by coroutinesInternal("SuspendLambda")
private val restrictedSuspendLambda: ClassDescriptor by coroutinesInternal("RestrictedSuspendLambda")
private val suspendFunctionInterface: ClassDescriptor? by lazy {
if (languageVersionSettings.isReleaseCoroutines())
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
else null
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
}
private fun createCoroutineSuperClass(className: String): ClassDescriptor {
return if (languageVersionSettings.isReleaseCoroutines())
createClass(kotlinCoroutinesJvmInternalPackage, className)
else
coroutineImpl
}
private fun createCoroutineSuperClass(className: String): ClassDescriptor = createClass(kotlinCoroutinesJvmInternalPackage, className)
private val propertyReferences: List<ClassDescriptor> by propertyClasses("PropertyReference", "")
private val mutablePropertyReferences: List<ClassDescriptor> by propertyClasses("MutablePropertyReference", "")
@@ -94,7 +84,7 @@ class JvmRuntimeTypes(
fun getSupertypesForClosure(descriptor: FunctionDescriptor): Collection<KotlinType> {
val actualFunctionDescriptor =
if (descriptor.isSuspend)
getOrCreateJvmSuspendFunctionView(descriptor, languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
getOrCreateJvmSuspendFunctionView(descriptor)
else
descriptor
@@ -118,7 +108,7 @@ class JvmRuntimeTypes(
if (descriptor.isSuspend) {
return mutableListOf<KotlinType>().apply {
if (actualFunctionDescriptor.extensionReceiverParameter?.type
?.isRestrictsSuspensionReceiver(languageVersionSettings) == true
?.isRestrictsSuspensionReceiver() == true
) {
if (descriptor.isSuspendLambdaOrLocalFunction()) {
add(restrictedSuspendLambda.defaultType)

View File

@@ -477,7 +477,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
SimpleFunctionDescriptor jvmSuspendFunctionView =
CoroutineCodegenUtilKt.getOrCreateJvmSuspendFunctionView(
functionDescriptor,
languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
this.bindingContext
);
@@ -714,54 +713,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
super.visitCallExpression(expression);
checkSamCall(expression);
checkCrossinlineCall(expression);
recordSuspendFunctionTypeWrapperForArguments(expression);
}
private void recordSuspendFunctionTypeWrapperForArguments(@NotNull KtCallExpression expression) {
ResolvedCall<?> call = CallUtilKt.getResolvedCall(expression, bindingContext);
if (call == null) return;
CallableDescriptor descriptor = call.getResultingDescriptor();
if (!CodegenUtilKt.needsExperimentalCoroutinesWrapper(descriptor)) return;
List<ResolvedValueArgument> argumentsByIndex = call.getValueArgumentsByIndex();
if (argumentsByIndex == null) return;
for (ValueParameterDescriptor parameter : descriptor.getValueParameters()) {
ResolvedValueArgument resolvedValueArgument = argumentsByIndex.get(parameter.getIndex());
if (!(resolvedValueArgument instanceof ExpressionValueArgument)) continue;
ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
if (valueArgument == null) continue;
KtExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression == null) continue;
recordSuspendFunctionTypeWrapperForArgument(parameter, argumentExpression);
}
ReceiverValue receiver = call.getExtensionReceiver();
if (descriptor.getExtensionReceiverParameter() != null && receiver instanceof ExpressionReceiver) {
recordSuspendFunctionTypeWrapperForArgument(
descriptor.getExtensionReceiverParameter(),
((ExpressionReceiver) receiver).getExpression()
);
}
}
private void recordSuspendFunctionTypeWrapperForArgument(ParameterDescriptor parameter, KtExpression argumentExpression) {
if (FunctionTypesKt.isSuspendFunctionTypeOrSubtype(parameter.getType())) {
// SuspendFunctionN type is mapped to is mapped to FunctionTypeN+1, but we also need to remove an argument for return type
// So, it could be parameter.getType().getArguments().size() + 1 - 1
int functionTypeArity = parameter.getType().getArguments().size();
Type functionType = Type.getObjectType(NUMBERED_FUNCTION_PREFIX + functionTypeArity);
bindingTrace.record(
FUNCTION_TYPE_FOR_SUSPEND_WRAPPER,
argumentExpression,
functionType
);
}
}
private void checkCrossinlineCall(@NotNull KtCallExpression expression) {

View File

@@ -13,15 +13,13 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.context.CodegenContext
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.coroutines.unwrapInitialDescriptorForSuspendFunction
import org.jetbrains.kotlin.codegen.inline.NUMBERED_FUNCTION_PREFIX
import org.jetbrains.kotlin.codegen.inline.ReificationArgument
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
@@ -45,8 +43,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.Synthetic
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor.CoroutinesCompatibilityMode
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
@@ -70,8 +66,7 @@ internal val JAVA_LANG_DEPRECATED = Type.getType(Deprecated::class.java).descrip
fun generateIsCheck(
v: InstructionAdapter,
kotlinType: KotlinType,
asmType: Type,
isReleaseCoroutines: Boolean
asmType: Type
) {
if (TypeUtils.isNullableType(kotlinType)) {
val nope = Label()
@@ -82,7 +77,7 @@ fun generateIsCheck(
ifnull(nope)
TypeIntrinsics.instanceOf(this, kotlinType, asmType, isReleaseCoroutines)
TypeIntrinsics.instanceOf(this, kotlinType, asmType)
goTo(end)
@@ -93,7 +88,7 @@ fun generateIsCheck(
mark(end)
}
} else {
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
}
}
@@ -102,7 +97,6 @@ fun generateAsCast(
kotlinType: KotlinType,
asmType: Type,
isSafe: Boolean,
languageVersionSettings: LanguageVersionSettings,
unifiedNullChecks: Boolean,
) {
if (!isSafe) {
@@ -112,7 +106,7 @@ fun generateAsCast(
} else {
with(v) {
dup()
TypeIntrinsics.instanceOf(v, kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
val ok = Label()
ifne(ok)
pop()
@@ -444,14 +438,10 @@ fun KotlinType.isInlineClassTypeWithPrimitiveEquality(): Boolean {
return false
}
fun CallableDescriptor.needsExperimentalCoroutinesWrapper() =
(this as? DeserializedMemberDescriptor)?.coroutinesExperimentalCompatibilityMode == CoroutinesCompatibilityMode.NEEDS_WRAPPER
fun recordCallLabelForLambdaArgument(declaration: KtFunctionLiteral, bindingTrace: BindingTrace) {
val labelName = getCallLabelForLambdaArgument(declaration, bindingTrace.bindingContext) ?: return
val functionDescriptor = bindingTrace[BindingContext.FUNCTION, declaration] ?: return
bindingTrace.record(CodegenBinding.CALL_LABEL_FOR_LAMBDA_ARGUMENT, functionDescriptor, labelName)
}
fun getCallLabelForLambdaArgument(declaration: KtFunctionLiteral, bindingContext: BindingContext): String? {
@@ -647,7 +637,7 @@ private fun generateLambdaForRunSuspend(
}
visitVarInsn(ALOAD, 1)
val continuationInternalName = state.languageVersionSettings.continuationAsmType().internalName
val continuationInternalName = CONTINUATION_ASM_TYPE.internalName
visitTypeInsn(
CHECKCAST,

View File

@@ -6,9 +6,9 @@
package org.jetbrains.kotlin.codegen.context
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.binding.MutableClosure
import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.descriptors.isTopLevelInPackage
@@ -17,25 +17,26 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getParentResolvedCall
import org.jetbrains.kotlin.resolve.source.getPsi
class InlineLambdaContext(
functionDescriptor: FunctionDescriptor,
contextKind: OwnerKind,
parentContext: CodegenContext<*>,
closure: MutableClosure?,
val isCrossInline: Boolean,
private val isPropertyReference: Boolean
functionDescriptor: FunctionDescriptor,
contextKind: OwnerKind,
parentContext: CodegenContext<*>,
closure: MutableClosure?,
val isCrossInline: Boolean,
private val isPropertyReference: Boolean
) : MethodContext(functionDescriptor, contextKind, parentContext, closure, false) {
override fun getFirstCrossInlineOrNonInlineContext(): CodegenContext<*> {
if (isCrossInline && !isSuspendIntrinsicParameter()) return this
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else { parentContext as? ClosureContext } ?:
throw AssertionError(
"Parent of inlining lambda body should be " +
"${if (isPropertyReference) "ClosureContext" else "AnonymousClassContext"}, but: $parentContext"
)
val parent = if (isPropertyReference) parentContext as? AnonymousClassContext else {
parentContext as? ClosureContext
} ?: throw AssertionError(
"Parent of inlining lambda body should be " +
"${if (isPropertyReference) "ClosureContext" else "AnonymousClassContext"}, but: $parentContext"
)
val grandParent = parent.parentContext ?:
throw AssertionError("Parent context of lambda class context should exist: $contextDescriptor")
val grandParent =
parent.parentContext ?: throw AssertionError("Parent context of lambda class context should exist: $contextDescriptor")
return grandParent.firstCrossInlineOrNonInlineContext
}
@@ -44,7 +45,7 @@ class InlineLambdaContext(
if (contextDescriptor !is AnonymousFunctionDescriptor) return false
val resolvedCall = (contextDescriptor.source.getPsi() as? KtElement).getParentResolvedCall(state.bindingContext) ?: return false
val descriptor = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return false
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(state.languageVersionSettings)
|| descriptor.isTopLevelInPackage("suspendCoroutine", state.languageVersionSettings.coroutinesPackageFqName().asString())
return descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn()
|| descriptor.isTopLevelInPackage("suspendCoroutine", StandardNames.COROUTINES_PACKAGE_FQ_NAME.asString())
}
}

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.optimization.boxing.isPrimitiveBoxing
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
@@ -15,10 +16,9 @@ import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.MethodInsnNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import java.util.*
private val BOXING_CLASS_INTERNAL_NAME =
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("Boxing")).topLevelClassInternalName()
@OptIn(ExperimentalStdlibApi::class)
object ChangeBoxingMethodTransformer : MethodTransformer() {

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.codegen.coroutines
import com.intellij.util.ArrayUtil
import org.jetbrains.kotlin.backend.common.CodegenUtil
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.binding.CodegenBinding.CAPTURES_CROSSINLINE_LAMBDA
@@ -17,8 +18,6 @@ import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHO
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
@@ -41,7 +40,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -56,7 +54,7 @@ abstract class AbstractCoroutineCodegen(
element: KtElement,
closureContext: ClosureContext,
classBuilder: ClassBuilder,
private val userDataForDoResume: Map<out CallableDescriptor.UserDataKey<*>, *>? = null
private val userDataForInvokeSuspend: Map<out CallableDescriptor.UserDataKey<*>, *>? = null
) : ClosureCodegen(
outerExpressionCodegen.state,
element, null, closureContext, null,
@@ -67,17 +65,10 @@ abstract class AbstractCoroutineCodegen(
protected val languageVersionSettings = outerExpressionCodegen.state.languageVersionSettings
protected val methodToImplement =
if (languageVersionSettings.isReleaseCoroutines())
createImplMethod(
INVOKE_SUSPEND_METHOD_NAME,
SUSPEND_CALL_RESULT_NAME to classDescriptor.module.getResult(classDescriptor.builtIns.anyType)
)
else
createImplMethod(
DO_RESUME_METHOD_NAME,
"data" to classDescriptor.builtIns.nullableAnyType,
"throwable" to classDescriptor.builtIns.throwable.defaultType.makeNullable()
)
createImplMethod(
INVOKE_SUSPEND_METHOD_NAME,
SUSPEND_CALL_RESULT_NAME to classDescriptor.module.getResult(classDescriptor.builtIns.anyType)
)
private fun createImplMethod(name: String, vararg parameters: Pair<String, KotlinType>) =
SimpleFunctionDescriptorImpl.create(
@@ -94,7 +85,7 @@ abstract class AbstractCoroutineCodegen(
builtIns.nullableAnyType,
Modality.FINAL,
DescriptorVisibilities.PUBLIC,
userDataForDoResume
userDataForInvokeSuspend
)
}
@@ -109,7 +100,7 @@ abstract class AbstractCoroutineCodegen(
override fun generateConstructor(): Method {
val args = calculateConstructorParameters(typeMapper, languageVersionSettings, closure, asmType)
val argTypes = args.map { it.fieldType }.plus(languageVersionSettings.continuationAsmType()).toTypedArray()
val argTypes = args.map { it.fieldType }.plus(CONTINUATION_ASM_TYPE).toTypedArray()
val constructor = Method("<init>", Type.VOID_TYPE, argTypes)
val mv = v.newMethod(
@@ -124,18 +115,17 @@ abstract class AbstractCoroutineCodegen(
iv.generateClosureFieldsInitializationFromParameters(closure, args)
iv.load(0, AsmTypes.OBJECT_TYPE)
val hasArityParameter = !languageVersionSettings.isReleaseCoroutines() || passArityToSuperClass
if (hasArityParameter) {
iv.iconst(if (passArityToSuperClass) funDescriptor.arity else 0)
if (passArityToSuperClass) {
iv.iconst(funDescriptor.arity)
}
iv.load(argTypes.map { it.size }.sum(), AsmTypes.OBJECT_TYPE)
val parameters =
if (hasArityParameter)
listOf(Type.INT_TYPE, languageVersionSettings.continuationAsmType())
if (passArityToSuperClass)
listOf(Type.INT_TYPE, CONTINUATION_ASM_TYPE)
else
listOf(languageVersionSettings.continuationAsmType())
listOf(CONTINUATION_ASM_TYPE)
val superClassConstructorDescriptor = Type.getMethodDescriptor(
Type.VOID_TYPE,
@@ -148,9 +138,7 @@ abstract class AbstractCoroutineCodegen(
FunctionCodegen.endVisit(iv, "constructor", element)
}
if (languageVersionSettings.isReleaseCoroutines()) {
v.newField(JvmDeclarationOrigin.NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "label", "I", null, null)
}
v.newField(JvmDeclarationOrigin.NO_ORIGIN, AsmUtil.NO_FLAG_PACKAGE_PRIVATE, "label", "I", null, null)
return constructor
}
@@ -167,7 +155,7 @@ class CoroutineCodegenForLambda private constructor(
private val forInline: Boolean
) : AbstractCoroutineCodegen(
outerExpressionCodegen, element, closureContext, classBuilder,
userDataForDoResume = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME to originalSuspendFunctionDescriptor)
userDataForInvokeSuspend = mapOf(INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND to originalSuspendFunctionDescriptor)
) {
private val builtIns = funDescriptor.builtIns
@@ -215,8 +203,7 @@ class CoroutineCodegenForLambda private constructor(
funDescriptor.typeParameters,
funDescriptor.valueParameters,
funDescriptor.module.getContinuationOfTypeOrAny(
builtIns.unitType,
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
builtIns.unitType
),
funDescriptor.modality,
DescriptorVisibilities.PUBLIC
@@ -231,14 +218,11 @@ class CoroutineCodegenForLambda private constructor(
"too many arguments of create to have an erased signature: $argumentsNum: $typedCreate"
}
return typedCreate.module.resolveClassByFqName(
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(
if (languageVersionSettings.isReleaseCoroutines())
Name.identifier("BaseContinuationImpl")
else
Name.identifier("CoroutineImpl")
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(
Name.identifier("BaseContinuationImpl")
),
NoLookupLocation.FROM_BACKEND
).sure { "BaseContinuationImpl or CoroutineImpl is not found" }.defaultType.memberScope
).sure { "BaseContinuationImpl is not found" }.defaultType.memberScope
.getContributedFunctions(typedCreate.name, NoLookupLocation.FROM_BACKEND)
.find { it.valueParameters.size == argumentsNum }
.sure { "erased parent of $typedCreate is not found" }
@@ -365,7 +349,7 @@ class CoroutineCodegenForLambda private constructor(
v.thisName,
typeMapper.mapFunctionName(createCoroutineDescriptor, null),
Type.getMethodDescriptor(
languageVersionSettings.continuationAsmType(),
CONTINUATION_ASM_TYPE,
*createArgumentTypes.toTypedArray()
),
false
@@ -373,11 +357,7 @@ class CoroutineCodegenForLambda private constructor(
checkcast(Type.getObjectType(v.thisName))
// .doResume(Unit)
if (languageVersionSettings.isReleaseCoroutines()) {
invokeInvokeSuspendWithUnit(v.thisName)
} else {
invokeDoResumeWithUnit(v.thisName)
}
invokeInvokeSuspendWithUnit(v.thisName)
areturn(AsmTypes.OBJECT_TYPE)
}
@@ -540,15 +520,14 @@ class CoroutineCodegenForLambda private constructor(
override fun wrapMethodVisitor(mv: MethodVisitor, access: Int, name: String, desc: String): MethodVisitor {
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null,
containingClassInternalName = v.thisName,
obtainClassBuilderForCoroutineState = { v },
isForNamedFunction = false,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = false,
reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(element, state, it) },
lineNumber = CodegenUtil.getLineNumberForElement(element, false) ?: 0,
sourceFile = element.containingKtFile.name,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = v.thisName,
isForNamedFunction = false,
languageVersionSettings = languageVersionSettings,
disableTailCallOptimizationForFunctionReturningUnit = false,
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS),
initialVarsCountByType = varsCountByType
)
@@ -625,7 +604,7 @@ class CoroutineCodegenForNamedFunction private constructor(
private val labelFieldStackValue by lazy {
StackValue.field(
FieldInfo.createForHiddenField(
computeLabelOwner(languageVersionSettings, v.thisName),
Type.getObjectType(v.thisName),
Type.INT_TYPE,
COROUTINE_LABEL_FIELD_NAME
),
@@ -647,44 +626,25 @@ class CoroutineCodegenForNamedFunction private constructor(
}
override fun generateClosureBody() {
generateResumeImpl()
if (!languageVersionSettings.isReleaseCoroutines()) {
generateGetLabelMethod()
generateSetLabelMethod()
}
generateInvokeSuspend()
v.newField(
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor, null, null
CONTINUATION_RESULT_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor, null, null
)
if (!languageVersionSettings.isReleaseCoroutines()) {
v.newField(
JvmDeclarationOrigin.NO_ORIGIN, Opcodes.ACC_SYNTHETIC or AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor, null, null
)
}
}
private fun generateResumeImpl() {
private fun generateInvokeSuspend() {
functionCodegen.generateMethod(
OtherOrigin(element),
methodToImplement,
object : FunctionGenerationStrategy.CodegenBased(state) {
override fun doGenerateBody(codegen: ExpressionCodegen, signature: JvmMethodSignature) {
StackValue.field(
AsmTypes.OBJECT_TYPE, Type.getObjectType(v.thisName), languageVersionSettings.dataFieldName(), false,
AsmTypes.OBJECT_TYPE, Type.getObjectType(v.thisName), CONTINUATION_RESULT_FIELD_NAME, false,
StackValue.LOCAL_0
).store(StackValue.local(1, AsmTypes.OBJECT_TYPE), codegen.v)
if (!languageVersionSettings.isReleaseCoroutines()) {
StackValue.field(
AsmTypes.JAVA_THROWABLE_TYPE, Type.getObjectType(v.thisName), EXCEPTION_FIELD_NAME, false,
StackValue.LOCAL_0
).store(StackValue.local(2, AsmTypes.JAVA_THROWABLE_TYPE), codegen.v)
}
labelFieldStackValue.store(
StackValue.operation(Type.INT_TYPE) {
labelFieldStackValue.put(Type.INT_TYPE, it)
@@ -736,7 +696,7 @@ class CoroutineCodegenForNamedFunction private constructor(
with(codegen.v) {
// We need to box the returned inline class in resume path.
// But first, check for COROUTINE_SUSPENDED, since the function can return it
generateCoroutineSuspendedCheck(languageVersionSettings)
generateCoroutineSuspendedCheck()
// Now we box the inline class
StackValue.coerce(AsmTypes.OBJECT_TYPE, typeMapper.mapType(inlineClassToBoxInInvokeSuspend), this)
StackValue.boxInlineClass(inlineClassToBoxInInvokeSuspend, this, typeMapper)

View File

@@ -9,15 +9,10 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.optimization.common.*
import org.jetbrains.kotlin.codegen.optimization.fixStack.FixStackMethodTransformer
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.*
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
@@ -49,7 +44,6 @@ class CoroutineTransformerMethodVisitor(
obtainClassBuilderForCoroutineState: () -> ClassBuilder,
private val isForNamedFunction: Boolean,
private val shouldPreserveClassInitialization: Boolean,
private val languageVersionSettings: LanguageVersionSettings,
// Since tail-call optimization of functions with Unit return type relies on ability of call-site to recognize them,
// in order to ignore return value and push Unit, when we cannot ensure this ability, for example, when the function overrides function,
// returning Any, we need to disable tail-call optimization for these functions.
@@ -73,7 +67,6 @@ class CoroutineTransformerMethodVisitor(
private var continuationIndex = if (isForNamedFunction) -1 else 0
private var dataIndex = if (isForNamedFunction) -1 else 1
private var exceptionIndex = if (isForNamedFunction || languageVersionSettings.isReleaseCoroutines()) -1 else 2
override fun performTransformations(methodNode: MethodNode) {
removeFakeContinuationConstructorCall(methodNode)
@@ -89,9 +82,7 @@ class CoroutineTransformerMethodVisitor(
val suspensionPoints = collectSuspensionPoints(methodNode)
RedundantLocalsEliminationMethodTransformer(suspensionPoints)
.transform(containingClassInternalName, methodNode)
if (languageVersionSettings.isReleaseCoroutines()) {
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
}
ChangeBoxingMethodTransformer.transform(containingClassInternalName, methodNode)
updateMaxStack(methodNode)
checkForSuspensionPointInsideMonitor(methodNode, suspensionPoints)
@@ -105,7 +96,6 @@ class CoroutineTransformerMethodVisitor(
}
val examiner = MethodNodeExaminer(
languageVersionSettings,
containingClassInternalName,
methodNode,
suspensionPoints,
@@ -119,9 +109,6 @@ class CoroutineTransformerMethodVisitor(
}
dataIndex = methodNode.maxLocals++
if (!languageVersionSettings.isReleaseCoroutines()) {
exceptionIndex = methodNode.maxLocals++
}
continuationIndex = methodNode.maxLocals++
prepareMethodNodePreludeForNamedFunction(methodNode)
@@ -158,7 +145,7 @@ class CoroutineTransformerMethodVisitor(
insertBefore(
actualCoroutineStart,
insnListOf(
*withInstructionAdapter { loadCoroutineSuspendedMarker(languageVersionSettings) }.toArray(),
*withInstructionAdapter { loadCoroutineSuspendedMarker() }.toArray(),
tableSwitchLabel,
// Allow debugger to stop on enter into suspend function
LineNumberNode(lineNumber, tableSwitchLabel),
@@ -176,7 +163,7 @@ class CoroutineTransformerMethodVisitor(
)
insert(firstStateLabel, withInstructionAdapter {
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
generateResumeWithExceptionCheck(dataIndex)
})
insert(last, defaultLabel)
@@ -192,11 +179,9 @@ class CoroutineTransformerMethodVisitor(
dropUnboxInlineClassMarkers(methodNode, suspensionPoints)
methodNode.removeEmptyCatchBlocks()
updateLvtAccordingToLiveness(methodNode, isForNamedFunction)
updateLvtAccordingToLiveness(methodNode, isForNamedFunction, stateLabels)
if (languageVersionSettings.isReleaseCoroutines()) {
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
}
writeDebugMetadata(methodNode, suspensionPointLineNumbers, spilledToVariableMapping)
}
// When suspension point is inlined, it is in range of fake inliner variables.
@@ -263,7 +248,7 @@ class CoroutineTransformerMethodVisitor(
methodNode.localVariables.add(
LocalVariableNode(
SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME,
languageVersionSettings.continuationAsmType().descriptor,
CONTINUATION_ASM_TYPE.descriptor,
null,
startLabel,
endLabel,
@@ -402,7 +387,7 @@ class CoroutineTransformerMethodVisitor(
methodNode.instructions.add(withInstructionAdapter { mark(endLabel) })
methodNode.visitLocalVariable(
CONTINUATION_VARIABLE_NAME,
languageVersionSettings.continuationAsmType().descriptor,
CONTINUATION_ASM_TYPE.descriptor,
null,
startLabel,
endLabel,
@@ -430,33 +415,17 @@ class CoroutineTransformerMethodVisitor(
}
private fun InstructionAdapter.getLabel() {
if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines())
invokevirtual(
classBuilderForCoroutineState.thisName,
"getLabel",
Type.getMethodDescriptor(Type.INT_TYPE),
false
)
else
getfield(
computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
getfield(
Type.getObjectType(classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
}
private fun InstructionAdapter.setLabel() {
if (isForNamedFunction && !languageVersionSettings.isReleaseCoroutines())
invokevirtual(
classBuilderForCoroutineState.thisName,
"setLabel",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE),
false
)
else
putfield(
computeLabelOwner(languageVersionSettings, classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
putfield(
Type.getObjectType(classBuilderForCoroutineState.thisName).internalName,
COROUTINE_LABEL_FIELD_NAME, Type.INT_TYPE.descriptor
)
}
private fun updateMaxStack(methodNode: MethodNode) {
@@ -534,8 +503,7 @@ class CoroutineTransformerMethodVisitor(
needDispatchReceiver,
internalNameForDispatchReceiver,
containingClassInternalName,
classBuilderForCoroutineState,
languageVersionSettings
classBuilderForCoroutineState
)
visitVarInsn(Opcodes.ASTORE, continuationIndex)
@@ -543,19 +511,13 @@ class CoroutineTransformerMethodVisitor(
visitLabel(afterCoroutineStateCreated)
visitVarInsn(Opcodes.ALOAD, continuationIndex)
getfield(classBuilderForCoroutineState.thisName, languageVersionSettings.dataFieldName(), AsmTypes.OBJECT_TYPE.descriptor)
getfield(classBuilderForCoroutineState.thisName, CONTINUATION_RESULT_FIELD_NAME, AsmTypes.OBJECT_TYPE.descriptor)
visitVarInsn(Opcodes.ASTORE, dataIndex)
val resultStartLabel = Label()
visitLabel(resultStartLabel)
addContinuationAndResultToLvt(methodNode, afterCoroutineStateCreated, resultStartLabel)
if (!languageVersionSettings.isReleaseCoroutines()) {
visitVarInsn(Opcodes.ALOAD, continuationIndex)
getfield(classBuilderForCoroutineState.thisName, EXCEPTION_FIELD_NAME, AsmTypes.JAVA_THROWABLE_TYPE.descriptor)
visitVarInsn(Opcodes.ASTORE, exceptionIndex)
}
})
}
@@ -692,7 +654,7 @@ class CoroutineTransformerMethodVisitor(
// k + 1 - data
// k + 2 - exception
for (slot in 0 until localsCount) {
if (slot == continuationIndex || slot == dataIndex || slot == exceptionIndex) continue
if (slot == continuationIndex || slot == dataIndex) continue
val value = frame.getLocal(slot)
if (value.type == null || !livenessFrame.isAlive(slot)) continue
@@ -992,7 +954,7 @@ class CoroutineTransformerMethodVisitor(
insert(possibleTryCatchBlockStart, withInstructionAdapter {
nop()
generateResumeWithExceptionCheck(languageVersionSettings.isReleaseCoroutines(), dataIndex, exceptionIndex)
generateResumeWithExceptionCheck(dataIndex)
// Load continuation argument just like suspending function returns it
load(dataIndex, AsmTypes.OBJECT_TYPE)
@@ -1118,8 +1080,7 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
needDispatchReceiver: Boolean,
internalNameForDispatchReceiver: String?,
containingClassInternalName: String,
classBuilderForCoroutineState: ClassBuilder,
languageVersionSettings: LanguageVersionSettings
classBuilderForCoroutineState: ClassBuilder
) {
anew(objectTypeForState)
dup()
@@ -1128,8 +1089,7 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
getParameterTypesIndicesForCoroutineConstructor(
methodNode.desc,
methodNode.access,
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName,
languageVersionSettings
needDispatchReceiver, internalNameForDispatchReceiver ?: containingClassInternalName
)
for ((type, index) in parameterTypesAndIndices) {
load(index, type)
@@ -1149,22 +1109,11 @@ internal fun InstructionAdapter.generateContinuationConstructorCall(
)
}
private fun InstructionAdapter.generateResumeWithExceptionCheck(isReleaseCoroutines: Boolean, dataIndex: Int, exceptionIndex: Int) {
private fun InstructionAdapter.generateResumeWithExceptionCheck(dataIndex: Int) {
// Check if resumeWithException has been called
if (isReleaseCoroutines) {
load(dataIndex, AsmTypes.OBJECT_TYPE)
invokestatic("kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false)
} else {
load(exceptionIndex, AsmTypes.OBJECT_TYPE)
dup()
val noExceptionLabel = Label()
ifnull(noExceptionLabel)
athrow()
mark(noExceptionLabel)
pop()
}
load(dataIndex, AsmTypes.OBJECT_TYPE)
invokestatic("kotlin/ResultKt", "throwOnFailure", "(Ljava/lang/Object;)V", false)
}
private fun Type.fieldNameForVar(index: Int) = descriptor.first() + "$" + index
@@ -1235,16 +1184,15 @@ private fun getParameterTypesIndicesForCoroutineConstructor(
desc: String,
containingFunctionAccess: Int,
needDispatchReceiver: Boolean,
thisName: String,
languageVersionSettings: LanguageVersionSettings
thisName: String
): Collection<Pair<Type, Int>> {
return mutableListOf<Pair<Type, Int>>().apply {
if (needDispatchReceiver) {
add(Type.getObjectType(thisName) to 0)
}
val continuationIndex =
getAllParameterTypes(desc, !isStatic(containingFunctionAccess), thisName).dropLast(1).map(Type::getSize).sum()
add(languageVersionSettings.continuationAsmType() to continuationIndex)
getAllParameterTypes(desc, !isStatic(containingFunctionAccess), thisName).dropLast(1).sumOf(Type::getSize)
add(CONTINUATION_ASM_TYPE to continuationIndex)
}
}
@@ -1269,7 +1217,7 @@ private fun MethodNode.nodeTextWithLiveness(liveness: List<VariableLivenessFrame
* This means, that function parameters do not longer span the whole function, including `this`.
* This might and will break some bytecode processors, including old versions of R8. See KT-24510.
*/
private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: Boolean) {
private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction: Boolean, suspensionPoints: List<LabelNode>) {
val liveness = analyzeLiveness(method)
fun List<LocalVariableNode>.findRecord(insnIndex: Int, variableIndex: Int): LocalVariableNode? {
@@ -1288,8 +1236,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
fun nextLabel(node: AbstractInsnNode?): LabelNode? {
var current = node
while (current != null) {
if (current is LabelNode) return current as LabelNode
current = current!!.next
if (current is LabelNode) return current
current = current.next
}
return null
}
@@ -1346,33 +1294,17 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
// Attempt to extend existing local variable node corresponding to the record in
// the original local variable table, if there is no back-edge
val recordToExtend: LocalVariableNode? = oldLvtNodeToLatestNewLvtNode[lvtRecord]
var recordExtended = false
if (recordToExtend != null) {
var hasBackEdgeOrStore = false
var current: AbstractInsnNode? = recordToExtend.end
while (current != null && current != endLabel) {
if (current is JumpInsnNode) {
if (method.instructions.indexOf((current as JumpInsnNode).label) < method.instructions.indexOf(current)) {
hasBackEdgeOrStore = true
break
}
}
if (current!!.isStoreOperation() && (current as VarInsnNode).`var` == recordToExtend.index) {
hasBackEdgeOrStore = true
break
}
current = current!!.next
}
if (!hasBackEdgeOrStore) {
recordToExtend.end = endLabel
recordExtended = true
}
}
if (!recordExtended) {
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
method.localVariables.add(node)
oldLvtNodeToLatestNewLvtNode[lvtRecord] = node
val latest = oldLvtNodeToLatestNewLvtNode[lvtRecord]
// if we can extend the previous range to where the local variable dies, we do not need a
// new entry, we know we cannot extend it to the lvt.endOffset, if we could we would have
// done so when we added it below.
val extended = latest?.extendRecordIfPossible(method, suspensionPoints, lvtRecord.end) ?: false
if (!extended) {
val new = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
oldLvtNodeToLatestNewLvtNode[lvtRecord] = new
method.localVariables.add(new)
// see if we can extend it all the way to the old end
new.extendRecordIfPossible(method, suspensionPoints, lvtRecord.end)
}
}
}
@@ -1395,3 +1327,35 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
}
}
}
/* We cannot extend a record if there is STORE instruction or a back-edge.
* STORE instructions can signify a unspilling operation, in which case, the variable will become visible before it unspilled,
* back-edges occur in loops.
*
* @return true if the range has been extended
*/
private fun LocalVariableNode.extendRecordIfPossible(
method: MethodNode,
suspensionPoints: List<LabelNode>,
endLabel: LabelNode
): Boolean {
val nextSuspensionPointLabel = suspensionPoints.find { it in InsnSequence(end, endLabel) } ?: endLabel
var current: AbstractInsnNode? = end
while (current != null && current != nextSuspensionPointLabel) {
if (current is JumpInsnNode) {
if (method.instructions.indexOf(current.label) < method.instructions.indexOf(current)) {
return false
}
}
// TODO: HACK
// TODO: Find correct label, which is OK to be used as end label.
if (current.opcode == Opcodes.ARETURN && nextSuspensionPointLabel != endLabel) return false
if (current.isStoreOperation() && (current as VarInsnNode).`var` == index) {
return false
}
current = current.next
}
end = nextSuspensionPointLabel
return true
}

View File

@@ -88,18 +88,17 @@ class SuspendFunctionGenerationStrategy(
return CoroutineTransformerMethodVisitor(
mv, access, name, desc, null, null, containingClassInternalName, this::classBuilderForCoroutineState,
isForNamedFunction = true,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(),
reportSuspensionPointInsideMonitor = { reportSuspensionPointInsideMonitor(declaration, state, it) },
lineNumber = CodegenUtil.getLineNumberForElement(declaration, false) ?: 0,
sourceFile = declaration.containingKtFile.name,
shouldPreserveClassInitialization = constructorCallNormalizationMode.shouldPreserveClassInitialization,
needDispatchReceiver = originalSuspendDescriptor.dispatchReceiverParameter != null,
internalNameForDispatchReceiver = (originalSuspendDescriptor.containingDeclaration as? ClassDescriptor)?.let {
if (it.isInlineClass()) state.typeMapper.mapType(it).internalName else null
} ?: containingClassInternalNameOrNull(),
languageVersionSettings = languageVersionSettings,
disableTailCallOptimizationForFunctionReturningUnit = originalSuspendDescriptor.returnType?.isUnit() == true &&
originalSuspendDescriptor.overriddenDescriptors.isNotEmpty() &&
!originalSuspendDescriptor.allOverriddenFunctionsReturnUnit(),
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
)
}
@@ -155,8 +154,7 @@ class SuspendFunctionGenerationStrategy(
needDispatchReceiver,
internalNameForDispatchReceiver,
containingClassInternalName,
classBuilderForCoroutineState,
languageVersionSettings
classBuilderForCoroutineState
)
addFakeContinuationConstructorCallMarker(this, false)
pop() // Otherwise stack-transformation breaks

View File

@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.sure
import org.jetbrains.org.objectweb.asm.Label
@@ -27,7 +26,6 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
internal class MethodNodeExaminer(
val languageVersionSettings: LanguageVersionSettings,
containingClassInternalName: String,
val methodNode: MethodNode,
suspensionPoints: List<SuspensionPoint>,
@@ -116,7 +114,7 @@ internal class MethodNodeExaminer(
val label = Label()
methodNode.instructions.insertBefore(pop, withInstructionAdapter {
dup()
loadCoroutineSuspendedMarker(languageVersionSettings)
loadCoroutineSuspendedMarker()
ifacmpne(label)
areturn(AsmTypes.OBJECT_TYPE)
mark(label)

View File

@@ -9,6 +9,8 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.builtins.StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalClassDescriptor
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
@@ -54,67 +56,27 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
const val COROUTINE_LABEL_FIELD_NAME = "label"
const val SUSPEND_FUNCTION_CREATE_METHOD_NAME = "create"
const val DO_RESUME_METHOD_NAME = "doResume"
const val INVOKE_SUSPEND_METHOD_NAME = "invokeSuspend"
const val EXCEPTION_FIELD_NAME = "exception"
const val CONTINUATION_RESULT_FIELD_NAME = "result"
val RELEASE_COROUTINES_VERSION_SETTINGS = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3)
private const val GET_CONTEXT_METHOD_NAME = "getContext"
fun LanguageVersionSettings.isResumeImplMethodName(name: String) =
if (isReleaseCoroutines())
name == INVOKE_SUSPEND_METHOD_NAME
else
name == DO_RESUME_METHOD_NAME
val DEBUG_METADATA_ANNOTATION_ASM_TYPE: Type =
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("DebugMetadata")).topLevelClassAsmType()
fun LanguageVersionSettings.dataFieldName(): String = if (isReleaseCoroutines()) "result" else "data"
fun coroutineContextAsmType(): Type =
StandardNames.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
fun isResumeImplMethodNameFromAnyLanguageSettings(name: String) = name == INVOKE_SUSPEND_METHOD_NAME || name == DO_RESUME_METHOD_NAME
fun LanguageVersionSettings.coroutinesJvmInternalPackageFqName() =
coroutinesPackageFqName().child(Name.identifier("jvm")).child(Name.identifier("internal"))
val DEBUG_METADATA_ANNOTATION_ASM_TYPE = RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName()
.child(Name.identifier("DebugMetadata")).topLevelClassAsmType()
fun LanguageVersionSettings.continuationAsmType() =
continuationInterfaceFqName().topLevelClassAsmType()
fun continuationAsmTypes() = listOf(
LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3).continuationAsmType(),
LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_2, ApiVersion.KOTLIN_1_2).continuationAsmType()
)
fun LanguageVersionSettings.coroutineContextAsmType() =
coroutinesPackageFqName().child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
fun LanguageVersionSettings.isCoroutineSuperClass(internalName: String): Boolean {
val coroutinesJvmInternalPackage = coroutinesJvmInternalPackageFqName()
return if (isReleaseCoroutines())
coroutinesJvmInternalPackage.identifiedChild("ContinuationImpl") == internalName ||
coroutinesJvmInternalPackage.identifiedChild("RestrictedContinuationImpl") == internalName ||
coroutinesJvmInternalPackage.identifiedChild("SuspendLambda") == internalName ||
coroutinesJvmInternalPackage.identifiedChild("RestrictedSuspendLambda") == internalName
else
coroutinesJvmInternalPackage.identifiedChild("CoroutineImpl") == internalName
}
fun String.isCoroutineSuperClass(): Boolean =
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("ContinuationImpl") == this ||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("RestrictedContinuationImpl") == this ||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("SuspendLambda") == this ||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.identifiedChild("RestrictedSuspendLambda") == this
private fun FqName.identifiedChild(name: String) = child(Name.identifier(name)).topLevelClassInternalName()
private fun LanguageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName() =
coroutinesIntrinsicsPackageFqName().child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
private fun LanguageVersionSettings.internalCoroutineIntrinsicsOwnerInternalName() =
coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineIntrinsics")).topLevelClassInternalName()
fun computeLabelOwner(languageVersionSettings: LanguageVersionSettings, thisName: String): Type =
if (languageVersionSettings.isReleaseCoroutines())
Type.getObjectType(thisName)
else
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("CoroutineImpl")).topLevelClassAsmType()
private const val NORMALIZE_CONTINUATION_METHOD_NAME = "normalizeContinuation"
private const val GET_CONTEXT_METHOD_NAME = "getContext"
private val coroutinesIntrinsicsFileFacadeInternalName: Type =
COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.child(Name.identifier("IntrinsicsKt")).topLevelClassAsmType()
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
@@ -122,7 +84,7 @@ data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val
val INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
@JvmField
val INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
val INITIAL_SUSPEND_DESCRIPTOR_FOR_INVOKE_SUSPEND = object : CallableDescriptor.UserDataKey<FunctionDescriptor> {}
val CONTINUATION_PARAMETER_NAME = Name.identifier("continuation")
@@ -158,9 +120,9 @@ fun ResolvedCall<*>.replaceSuspensionFunctionWithRealDescriptor(
val newCandidateDescriptor =
when (function) {
is FunctionImportedFromObject ->
getOrCreateJvmSuspendFunctionView(function.callableFromObject, isReleaseCoroutines, bindingContext).asImportedFromObject()
getOrCreateJvmSuspendFunctionView(function.callableFromObject, bindingContext).asImportedFromObject()
is SimpleFunctionDescriptor ->
getOrCreateJvmSuspendFunctionView(function, isReleaseCoroutines, bindingContext)
getOrCreateJvmSuspendFunctionView(function, bindingContext)
else ->
throw AssertionError("Unexpected suspend function descriptor: $function")
}
@@ -223,10 +185,10 @@ private fun NewResolvedCallImpl<VariableDescriptor>.asDummyOldResolvedCall(bindi
enum class SuspensionPointKind { NEVER, NOT_INLINE, ALWAYS }
fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen, languageVersionSettings: LanguageVersionSettings): SuspensionPointKind {
fun ResolvedCall<*>.isSuspensionPoint(codegen: ExpressionCodegen): SuspensionPointKind {
val functionDescriptor = resultingDescriptor as? FunctionDescriptor ?: return SuspensionPointKind.NEVER
if (!functionDescriptor.unwrapInitialDescriptorForSuspendFunction().isSuspend) return SuspensionPointKind.NEVER
if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings)) return SuspensionPointKind.ALWAYS
if (functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm()) return SuspensionPointKind.ALWAYS
if (functionDescriptor.isInline) return SuspensionPointKind.NEVER
val isInlineLambda = this.safeAs<VariableAsFunctionResolvedCall>()
@@ -242,7 +204,6 @@ fun CallableDescriptor.isSuspendFunctionNotSuspensionView(): Boolean {
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, state: GenerationState): D = getOrCreateJvmSuspendFunctionView(
function,
state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines),
state.bindingContext
)
@@ -252,7 +213,6 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(function: D, stat
@JvmOverloads
fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
function: D,
isReleaseCoroutines: Boolean,
bindingContext: BindingContext? = null
): D {
assert(function.isSuspend) {
@@ -272,7 +232,7 @@ fun <D : FunctionDescriptor> getOrCreateJvmSuspendFunctionView(
outType = if (function.containingDeclaration.safeAs<ClassDescriptor>()?.isBuiltinFunctionalClassDescriptor == true)
function.builtIns.nullableAnyType
else
function.getContinuationParameterTypeOfSuspendFunction(isReleaseCoroutines),
function.getContinuationParameterTypeOfSuspendFunction(),
declaresDefaultValue = false, isCrossinline = false,
isNoinline = false, varargElementType = null,
source = SourceElement.NO_SOURCE
@@ -309,8 +269,7 @@ fun <D : FunctionDescriptor> D.createCustomCopy(
return result as D
}
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction(isReleaseCoroutines: Boolean) =
module.getContinuationOfTypeOrAny(returnType!!, if (this.needsExperimentalCoroutinesWrapper()) false else isReleaseCoroutines)
private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() = module.getContinuationOfTypeOrAny(returnType!!)
fun ModuleDescriptor.getResult(kotlinType: KotlinType) =
module.resolveTopLevelClass(
@@ -323,44 +282,11 @@ fun ModuleDescriptor.getResult(kotlinType: KotlinType) =
)
} ?: ErrorUtils.createErrorType("For Result")
private fun MethodNode.invokeNormalizeContinuation(languageVersionSettings: LanguageVersionSettings) {
visitMethodInsn(
Opcodes.INVOKESTATIC,
languageVersionSettings.internalCoroutineIntrinsicsOwnerInternalName(),
NORMALIZE_CONTINUATION_METHOD_NAME,
Type.getMethodDescriptor(languageVersionSettings.continuationAsmType(), languageVersionSettings.continuationAsmType()),
false
)
}
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm() =
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn() == true
fun FunctionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings: LanguageVersionSettings) =
getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION)?.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) == true
fun createMethodNodeForIntercepted(languageVersionSettings: LanguageVersionSettings): MethodNode {
val node =
MethodNode(
Opcodes.API_VERSION,
Opcodes.ACC_STATIC,
"fake",
Type.getMethodDescriptor(languageVersionSettings.continuationAsmType(), languageVersionSettings.continuationAsmType()),
null, null
)
node.visitVarInsn(Opcodes.ALOAD, 0)
node.invokeNormalizeContinuation(languageVersionSettings)
node.visitInsn(Opcodes.ARETURN)
node.visitMaxs(1, 1)
return node
}
fun createMethodNodeForCoroutineContext(
functionDescriptor: FunctionDescriptor,
languageVersionSettings: LanguageVersionSettings
): MethodNode {
assert(functionDescriptor.isBuiltInCoroutineContext(languageVersionSettings)) {
fun createMethodNodeForCoroutineContext(functionDescriptor: FunctionDescriptor): MethodNode {
assert(functionDescriptor.isBuiltInCoroutineContext()) {
"functionDescriptor must be kotlin.coroutines.intrinsics.coroutineContext property getter"
}
@@ -369,7 +295,7 @@ fun createMethodNodeForCoroutineContext(
Opcodes.API_VERSION,
Opcodes.ACC_STATIC,
"fake",
Type.getMethodDescriptor(languageVersionSettings.coroutineContextAsmType()),
Type.getMethodDescriptor(coroutineContextAsmType()),
null, null
)
@@ -377,20 +303,20 @@ fun createMethodNodeForCoroutineContext(
addFakeContinuationMarker(v)
v.invokeGetContext(languageVersionSettings)
v.invokeGetContext()
node.visitMaxs(1, 1)
return node
}
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings: LanguageVersionSettings): MethodNode {
fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(): MethodNode {
val node =
MethodNode(
Opcodes.API_VERSION,
Opcodes.ACC_STATIC,
"fake",
Type.getMethodDescriptor(OBJECT_TYPE, AsmTypes.FUNCTION1, languageVersionSettings.continuationAsmType()),
Type.getMethodDescriptor(OBJECT_TYPE, AsmTypes.FUNCTION1, CONTINUATION_ASM_TYPE),
null, null
)
@@ -405,25 +331,22 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSett
"($OBJECT_TYPE)$OBJECT_TYPE"
)
if (languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)) {
val elseLabel = Label()
// if (result === COROUTINE_SUSPENDED) {
dup()
loadCoroutineSuspendedMarker(languageVersionSettings)
ifacmpne(elseLabel)
// DebugProbesKt.probeCoroutineSuspended(continuation)
load(1, OBJECT_TYPE) // continuation
checkcast(languageVersionSettings.continuationAsmType())
invokestatic(
languageVersionSettings.coroutinesJvmInternalPackageFqName().child(Name.identifier("DebugProbesKt"))
.topLevelClassAsmType().internalName,
"probeCoroutineSuspended",
"(${languageVersionSettings.continuationAsmType()})V",
false
)
// }
mark(elseLabel)
}
val elseLabel = Label()
// if (result === COROUTINE_SUSPENDED) {
dup()
loadCoroutineSuspendedMarker()
ifacmpne(elseLabel)
// DebugProbesKt.probeCoroutineSuspended(continuation)
load(1, OBJECT_TYPE) // continuation
checkcast(CONTINUATION_ASM_TYPE)
invokestatic(
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("DebugProbesKt")).topLevelClassAsmType().internalName,
"probeCoroutineSuspended",
"($CONTINUATION_ASM_TYPE)V",
false
)
// }
mark(elseLabel)
}
node.visitInsn(Opcodes.ARETURN)
@@ -433,13 +356,13 @@ fun createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSett
}
private fun InstructionAdapter.invokeGetContext(languageVersionSettings: LanguageVersionSettings) {
private fun InstructionAdapter.invokeGetContext() {
invokeinterface(
languageVersionSettings.continuationAsmType().internalName,
CONTINUATION_ASM_TYPE.internalName,
GET_CONTEXT_METHOD_NAME,
Type.getMethodDescriptor(languageVersionSettings.coroutineContextAsmType())
Type.getMethodDescriptor(coroutineContextAsmType())
)
areturn(languageVersionSettings.coroutineContextAsmType())
areturn(coroutineContextAsmType())
}
@Suppress("UNCHECKED_CAST")
@@ -447,15 +370,12 @@ fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, isReleaseCoroutines: Boolean): FunctionDescriptor =
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext): FunctionDescriptor =
if (isSuspend)
getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, isReleaseCoroutines, bindingContext)
getOrCreateJvmSuspendFunctionView(unwrapInitialDescriptorForSuspendFunction().original, bindingContext)
else
this
fun FunctionDescriptor.getOriginalSuspendFunctionView(bindingContext: BindingContext, state: GenerationState) =
getOriginalSuspendFunctionView(bindingContext, state.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
// For each suspend function, we have a corresponding JVM view function that has an extra continuation parameter,
// and, more importantly, returns 'kotlin.Any' (so that it can return as a reference value or a special COROUTINE_SUSPENDED object).
// This also causes boxing of primitives and inline class values.
@@ -482,38 +402,24 @@ fun FunctionDescriptor.originalReturnTypeOfSuspendFunctionReturningUnboxedInline
return originalReturnType
}
fun InstructionAdapter.loadCoroutineSuspendedMarker(languageVersionSettings: LanguageVersionSettings) {
fun InstructionAdapter.loadCoroutineSuspendedMarker() {
invokestatic(
languageVersionSettings.coroutinesIntrinsicsFileFacadeInternalName().internalName,
coroutinesIntrinsicsFileFacadeInternalName.internalName,
"get$COROUTINE_SUSPENDED_NAME",
Type.getMethodDescriptor(OBJECT_TYPE),
false
)
}
fun InstructionAdapter.generateCoroutineSuspendedCheck(languageVersionSettings: LanguageVersionSettings) {
fun InstructionAdapter.generateCoroutineSuspendedCheck() {
dup()
loadCoroutineSuspendedMarker(languageVersionSettings)
loadCoroutineSuspendedMarker()
val elseLabel = Label()
ifacmpne(elseLabel)
areturn(OBJECT_TYPE)
mark(elseLabel)
}
fun InstructionAdapter.invokeDoResumeWithUnit(thisName: String) {
// .doResume(Unit, null)
StackValue.putUnitInstance(this)
aconst(null)
invokevirtual(
thisName,
DO_RESUME_METHOD_NAME,
Type.getMethodDescriptor(OBJECT_TYPE, OBJECT_TYPE, AsmTypes.JAVA_THROWABLE_TYPE),
false
)
}
fun InstructionAdapter.invokeInvokeSuspendWithUnit(thisName: String) {
StackValue.putUnitInstance(this)
@@ -537,18 +443,14 @@ fun FunctionDescriptor.isSuspendLambdaOrLocalFunction() = this.isSuspend && when
}
fun FunctionDescriptor.isLocalSuspendFunctionNotSuspendLambda() = isSuspendLambdaOrLocalFunction() && this !is AnonymousFunctionDescriptor
@JvmField
val EXPERIMENTAL_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_EXPERIMENTAL.topLevelClassAsmType()
@JvmField
val RELEASE_CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME_RELEASE.topLevelClassAsmType()
val CONTINUATION_ASM_TYPE = StandardNames.CONTINUATION_INTERFACE_FQ_NAME.topLevelClassAsmType()
fun FunctionDescriptor.isInvokeSuspendOfLambda(): Boolean {
if (this !is SimpleFunctionDescriptor) return false
if (valueParameters.size != 1 ||
valueParameters[0].name.asString() != SUSPEND_CALL_RESULT_NAME ||
name.asString() != "invokeSuspend"
name.asString() != INVOKE_SUSPEND_METHOD_NAME
) return false
return containingDeclaration is SyntheticClassDescriptorForLambda
}

View File

@@ -62,7 +62,7 @@ class AnonymousObjectTransformer(
createClassReader().accept(object : ClassVisitor(Opcodes.API_VERSION, classBuilder.visitor) {
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String, interfaces: Array<String>) {
classBuilder.defineClass(null, maxOf(version, state.classFileVersion), access, name, signature, superName, interfaces)
if (languageVersionSettings.isCoroutineSuperClass(superName)) {
if (superName.isCoroutineSuperClass()) {
inliningContext.isContinuation = true
}
superClassName = superName

View File

@@ -0,0 +1,386 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.optimization.boxing.isMethodInsnWith
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
import org.jetbrains.kotlin.codegen.optimization.common.updateMaxStack
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.*
class InplaceArgumentsMethodTransformer : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) {
val methodContext = parseMethodOrNull(methodNode)
if (methodContext != null) {
if (methodContext.calls.isEmpty()) return
collectStartToEnd(methodContext)
collectLvtEntryInstructions(methodContext)
collectSuspensionPoints(methodContext)
transformMethod(methodContext)
updateLvtEntriesForMovedInstructions(methodContext)
methodNode.removeUnusedLocalVariables()
methodNode.updateMaxStack()
}
stripMarkers(methodNode)
}
private class MethodContext(
val methodNode: MethodNode,
val calls: List<CallContext>
) {
val startArgToEndArg = HashMap<AbstractInsnNode, AbstractInsnNode>()
val lvtEntryForInstruction = HashMap<AbstractInsnNode, LocalVariableNode>()
val varInstructionMoved = HashMap<AbstractInsnNode, CallContext>()
val suspensionJumpLabels = HashSet<LabelNode>()
}
private class CallContext(
val callStartMarker: AbstractInsnNode,
val callEndMarker: AbstractInsnNode,
val args: List<ArgContext>,
val calls: List<CallContext>,
val endLabel: LabelNode
)
private class ArgContext(
val argStartMarker: AbstractInsnNode,
val argEndMarker: AbstractInsnNode,
val calls: List<CallContext>,
val storeInsn: VarInsnNode
) {
val loadOpcode = storeInsn.opcode - Opcodes.ISTORE + Opcodes.ILOAD
val varIndex = storeInsn.`var`
}
private fun parseMethodOrNull(methodNode: MethodNode): MethodContext? {
// We assume that the method body structure follows this grammar:
// METHOD ::= insn* (CALL insn*)*
// CALL ::= callStartMarker insn* (ARG insn*)* (CALL insn*)* callEndMarker
// ARG ::= argStartMarker insn* (CALL insn*)* argEndMarker storeInsn
val iter = methodNode.instructions.iterator()
val calls = ArrayList<CallContext>()
try {
while (iter.hasNext()) {
val insn = iter.next()
when {
insn.isInplaceCallStartMarker() ->
calls.add(parseCall(methodNode, insn, iter))
insn.isInplaceCallEndMarker() || insn.isInplaceArgumentStartMarker() || insn.isInplaceArgumentEndMarker() ->
throw ParseErrorException()
}
}
} catch (e: ParseErrorException) {
return null
}
return MethodContext(methodNode, calls)
}
private fun parseCall(methodNode: MethodNode, start: AbstractInsnNode, iter: ListIterator<AbstractInsnNode>): CallContext {
// CALL ::= callStartMarker insn* (ARG insn*)* (CALL insn*)* callEndMarker
val args = ArrayList<ArgContext>()
val calls = ArrayList<CallContext>()
while (iter.hasNext()) {
val insn = iter.next()
when {
insn.isInplaceCallStartMarker() ->
calls.add(parseCall(methodNode, insn, iter))
insn.isInplaceCallEndMarker() -> {
val previous = insn.previous
val endLabel =
if (previous.type == AbstractInsnNode.LABEL)
previous as LabelNode
else
LabelNode(Label()).also {
// Make sure each call with inplace arguments has an endLabel
// (we need it to update LVT after transformation).
methodNode.instructions.insertBefore(insn, it)
}
return CallContext(start, insn, args, calls, endLabel)
}
insn.isInplaceArgumentStartMarker() ->
args.add(parseArg(methodNode, insn, iter))
insn.isInplaceArgumentEndMarker() ->
throw ParseErrorException()
}
}
// Reached instruction list end, didn't find inplace-call-end marker
throw ParseErrorException()
}
private fun parseArg(methodNode: MethodNode, start: AbstractInsnNode, iter: ListIterator<AbstractInsnNode>): ArgContext {
// ARG ::= argStartMarker insn* (CALL insn*)* argEndMarker storeInsn
val calls = ArrayList<CallContext>()
while (iter.hasNext()) {
val insn = iter.next()
when {
insn.isInplaceCallStartMarker() ->
calls.add(parseCall(methodNode, insn, iter))
insn.isInplaceArgumentEndMarker() -> {
val next = insn.next
if (next is VarInsnNode && next.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
iter.next()
return ArgContext(start, insn, calls, next)
} else {
throw ParseErrorException()
}
}
insn.isInplaceCallEndMarker() || insn.isInplaceArgumentStartMarker() ->
throw ParseErrorException()
}
}
// Reached instruction list end, didn't find inplace-argument-end marker
throw ParseErrorException()
}
private class ParseErrorException : RuntimeException() {
override fun fillInStackTrace(): Throwable = this
}
private fun collectStartToEnd(methodContext: MethodContext) {
for (call in methodContext.calls) {
collectStartToEnd(methodContext, call)
}
}
private fun collectStartToEnd(methodContext: MethodContext, callContext: CallContext) {
for (arg in callContext.args) {
collectStartToEnd(methodContext, arg)
}
for (call in callContext.calls) {
collectStartToEnd(methodContext, call)
}
}
private fun collectStartToEnd(methodContext: MethodContext, argContext: ArgContext) {
methodContext.startArgToEndArg[argContext.argStartMarker] = argContext.argEndMarker
for (call in argContext.calls) {
collectStartToEnd(methodContext, call)
}
}
private fun collectLvtEntryInstructions(methodContext: MethodContext) {
val insnList = methodContext.methodNode.instructions
val insnArray = insnList.toArray()
for (lv in methodContext.methodNode.localVariables) {
val lvStartIndex = insnList.indexOf(lv.start)
val lvEndIndex = insnList.indexOf(lv.end)
for (i in lvStartIndex until lvEndIndex) {
val insn = insnArray[i]
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD || insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
if ((insn as VarInsnNode).`var` == lv.index) {
methodContext.lvtEntryForInstruction[insn] = lv
}
} else if (insn.opcode == Opcodes.IINC) {
if ((insn as IincInsnNode).`var` == lv.index) {
methodContext.lvtEntryForInstruction[insn] = lv
}
}
}
}
}
private fun collectSuspensionPoints(methodContext: MethodContext) {
val insnList = methodContext.methodNode.instructions
var insn = insnList.first
while (
!insn.isMethodInsnWith(Opcodes.INVOKESTATIC) {
owner == "kotlin/coroutines/intrinsics/IntrinsicsKt" &&
name == "getCOROUTINE_SUSPENDED" &&
desc == "()Ljava/lang/Object;"
}
) {
insn = insn.next ?: return
}
// Find a first TABLESWITCH and record its jump destinations
while (insn != null) {
if (insn.opcode != Opcodes.TABLESWITCH || insn.previous.opcode != Opcodes.GETFIELD) {
insn = insn.next
continue
}
val getFiendInsn = insn.previous as FieldInsnNode
if (getFiendInsn.name != "label" || getFiendInsn.desc != "I") {
insn = insn.next
continue
}
val tableSwitchInsn = insn as TableSwitchInsnNode
methodContext.suspensionJumpLabels.addAll(tableSwitchInsn.labels)
methodContext.suspensionJumpLabels.add(tableSwitchInsn.dflt)
return
}
}
private fun transformMethod(methodContext: MethodContext) {
for (call in methodContext.calls) {
transformCall(methodContext, call)
}
}
private fun transformCall(methodContext: MethodContext, callContext: CallContext) {
// Transform nested calls
for (arg in callContext.args) {
for (nestedCall in arg.calls) {
transformCall(methodContext, nestedCall)
}
}
for (call in callContext.calls) {
transformCall(methodContext, call)
}
// If an inplace argument contains a non-local jump,
// moving such argument inside inline function body can interfere with stack normalization.
// TODO investigate complex cases
if (callContext.args.any { it.isUnsafeToMove(methodContext) }) {
// Do not transform such call, just strip call and argument markers.
val insnList = methodContext.methodNode.instructions
for (arg in callContext.args) {
insnList.remove(arg.argStartMarker)
insnList.remove(arg.argEndMarker)
}
insnList.remove(callContext.callStartMarker)
insnList.remove(callContext.callEndMarker)
return
}
moveInplaceArgumentsFromStoresToLoads(methodContext, callContext)
}
private fun ArgContext.isUnsafeToMove(methodContext: MethodContext): Boolean {
val argInsns = InsnSequence(this.argStartMarker, this.argEndMarker)
val localLabels = argInsns.filterTo(HashSet()) { it is LabelNode }
return argInsns.any { insn ->
insn in methodContext.suspensionJumpLabels ||
insn.opcode == Opcodes.GOTO && (insn as JumpInsnNode).label !in localLabels
}
}
private fun moveInplaceArgumentsFromStoresToLoads(methodContext: MethodContext, callContext: CallContext) {
// Transform call
val insnList = methodContext.methodNode.instructions
val args = callContext.args.associateBy { it.varIndex }
var argsProcessed = 0
var insn: AbstractInsnNode = callContext.callStartMarker
while (insn != callContext.callEndMarker) {
when {
insn.isInplaceArgumentStartMarker() -> {
// Skip argument body
insn = methodContext.startArgToEndArg[insn]!!
}
insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD -> {
// Load instruction
val loadInsn = insn as VarInsnNode
val varIndex = loadInsn.`var`
val arg = args[varIndex]
if (arg == null || arg.loadOpcode != insn.opcode) {
// Not an argument load
insn = insn.next
} else {
// For each argument within this call we have
// <inplaceArgStartMarker>
// <argumentBody>
// <inplaceArgEndMarker>
// store [arg]
// ...
// load [arg]
// Replace 'load [arg]' with '<argumentBody>', drop 'store [arg]' and argument markers.
var argInsn = arg.argStartMarker.next
while (argInsn != arg.argEndMarker) {
// If a LOAD/STORE/IINC instruction was moved,
// record it so that we can update corresponding LVT entry if needed.
// NB it's better to do so after all transformations, so that we don't recalculate node indices.
if (argInsn.opcode in Opcodes.ILOAD..Opcodes.ALOAD ||
argInsn.opcode in Opcodes.ISTORE..Opcodes.ASTORE ||
argInsn.opcode == Opcodes.IINC
) {
methodContext.varInstructionMoved[argInsn] = callContext
}
val argInsnNext = argInsn.next
insnList.remove(argInsn)
insnList.insertBefore(loadInsn, argInsn)
argInsn = argInsnNext
}
// Remove argument load and corresponding argument store instructions
insnList.remove(arg.storeInsn)
insn = loadInsn.next
insnList.remove(loadInsn)
// Replace subsequent argument loads with DUP instructions of appropriate size
while (insn.opcode == loadInsn.opcode && (insn as VarInsnNode).`var` == varIndex) {
if (insn.opcode == Opcodes.LLOAD || insn.opcode == Opcodes.DLOAD) {
insnList.insertBefore(insn, InsnNode(Opcodes.DUP2))
} else {
insnList.insertBefore(insn, InsnNode(Opcodes.DUP))
}
val next = insn.next
insnList.remove(insn)
insn = next
}
// Remove argument markers
insnList.remove(arg.argStartMarker)
insnList.remove(arg.argEndMarker)
// If there are no more inplace arguments left to process, we are done
++argsProcessed
if (argsProcessed >= callContext.args.size)
break
}
}
else ->
insn = insn.next
}
}
// Remove call start and call end markers
insnList.remove(callContext.callStartMarker)
insnList.remove(callContext.callEndMarker)
}
private fun updateLvtEntriesForMovedInstructions(methodContext: MethodContext) {
val insnList = methodContext.methodNode.instructions
for ((insn, callContext) in methodContext.varInstructionMoved.entries) {
// Extend local variable interval to call end label if needed
val lv = methodContext.lvtEntryForInstruction[insn] ?: continue
val lvEndIndex = insnList.indexOf(lv.end)
val endLabelIndex = insnList.indexOf(callContext.endLabel)
if (endLabelIndex > lvEndIndex) {
lv.end = callContext.endLabel
}
}
}
private fun stripMarkers(methodNode: MethodNode) {
var insn = methodNode.instructions.first
while (insn != null) {
if (insn.isInplaceCallStartMarker() ||
insn.isInplaceCallEndMarker() ||
insn.isInplaceArgumentStartMarker() ||
insn.isInplaceArgumentEndMarker()
) {
val next = insn.next
methodNode.instructions.remove(insn)
insn = next
continue
}
insn = insn.next
}
}
}

View File

@@ -104,7 +104,7 @@ class DefaultLambda(info: ExtractedDefaultLambda, sourceCompiler: SourceCompiler
// TODO: suspend lambdas are their own continuations, so the body is pre-inlined into `invokeSuspend`
// and thus can't be detangled from the state machine. To make them inlinable, this needs to be redesigned.
// See `SuspendLambdaLowering`.
require(!sourceCompiler.state.languageVersionSettings.isCoroutineSuperClass(superName)) {
require(!superName.isCoroutineSuperClass()) {
"suspend default lambda ${lambdaClassType.internalName} cannot be inlined; use a function reference instead"
}

View File

@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.coroutines.continuationAsmType
import org.jetbrains.kotlin.codegen.coroutines.CONTINUATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.inline.FieldRemapper.Companion.foldName
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspend
@@ -688,7 +688,7 @@ class MethodInliner(
}
for ((index, param) in paramTypes.reversed().withIndex()) {
if (param != languageVersionSettings.continuationAsmType() && param != OBJECT_TYPE) continue
if (param != CONTINUATION_ASM_TYPE && param != OBJECT_TYPE) continue
val sourceIndices = (frame.getStack(frame.stackSize - index - 1) as? Aload0BasicValue)?.indices ?: continue
for (sourceIndex in sourceIndices) {
val src = processingNode.instructions[sourceIndex]
@@ -733,6 +733,7 @@ class MethodInliner(
private fun preprocessNodeBeforeInline(node: MethodNode, returnLabels: Map<String, Label?>) {
try {
InplaceArgumentsMethodTransformer().transform("fake", node)
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
} catch (e: Throwable) {
throw wrapException(e, node, "couldn't inline method call")

View File

@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.psi.*
@@ -158,8 +157,7 @@ class PsiSourceCompilerForInline(
}
FunctionCodegen.generateMethodBody(
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode,
state.languageVersionSettings.isReleaseCoroutines()
adapter, descriptor, context, jvmMethodSignature, strategy, parentCodegen, state.jvmDefaultMode
)
if (isLambda) {
@@ -235,7 +233,7 @@ class PsiSourceCompilerForInline(
}
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
generateInlineIntrinsic(state.languageVersionSettings, functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
generateInlineIntrinsic(functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
return it
}

View File

@@ -22,8 +22,6 @@ import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.KotlinType
@@ -233,7 +231,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
if (stubCheckcast !is TypeInsnNode) return false
val newMethodNode = MethodNode(Opcodes.API_VERSION)
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, languageVersionSettings, unifiedNullChecks)
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, unifiedNullChecks)
instructions.insert(insn, newMethodNode.instructions)
// Keep stubCheckcast to avoid VerifyErrors on 1.8+ bytecode,
@@ -257,7 +255,7 @@ class ReifiedTypeInliner<KT : KotlinTypeMarker>(
if (stubInstanceOf !is TypeInsnNode) return false
val newMethodNode = MethodNode(Opcodes.API_VERSION)
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType)
instructions.insert(insn, newMethodNode.instructions)
instructions.remove(stubInstanceOf)

View File

@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.org.objectweb.asm.MethodVisitor
@@ -49,18 +48,16 @@ class CoroutineTransformer(
fun suspendLambdaWithGeneratedStateMachine(node: MethodNode): Boolean =
!isContinuationNotLambda() && isSuspendLambda(node) && isStateMachine(node)
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation &&
if (state.languageVersionSettings.isReleaseCoroutines()) superClassName.endsWith("ContinuationImpl")
else methods.any { it.name == "getLabel" }
private fun isContinuationNotLambda(): Boolean = inliningContext.isContinuation && superClassName.endsWith("ContinuationImpl")
private fun isStateMachine(node: MethodNode): Boolean =
node.instructions.asSequence().any { insn -> insn is LdcInsnNode && insn.cst == ILLEGAL_STATE_ERROR_MESSAGE }
private fun isSuspendLambda(node: MethodNode) = isResumeImpl(node)
private fun isSuspendLambda(node: MethodNode) = isInvokeSuspend(node)
fun newMethod(node: MethodNode): DeferredMethodVisitor {
return when {
isResumeImpl(node) -> {
isInvokeSuspend(node) -> {
assert(!isStateMachine(node)) {
"Inlining/transforming state-machine"
}
@@ -71,9 +68,8 @@ class CoroutineTransformer(
}
}
private fun isResumeImpl(node: MethodNode): Boolean =
state.languageVersionSettings.isResumeImplMethodName(node.name.removeSuffix(FOR_INLINE_SUFFIX)) &&
inliningContext.isContinuation
private fun isInvokeSuspend(node: MethodNode): Boolean =
node.name.removeSuffix(FOR_INLINE_SUFFIX) == INVOKE_SUSPEND_METHOD_NAME && inliningContext.isContinuation
private fun isSuspendFunctionWithFakeConstructorCall(node: MethodNode): Boolean = findFakeContinuationConstructorClassName(node) != null
@@ -88,16 +84,15 @@ class CoroutineTransformer(
val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
containingClassInternalName = classBuilder.thisName,
obtainClassBuilderForCoroutineState = { classBuilder },
isForNamedFunction = false,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = false,
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
// TODO: this linenumbers might not be correct and since they are used only for step-over, check them.
lineNumber = inliningContext.callSiteInfo.lineNumber,
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = false,
disableTailCallOptimizationForFunctionReturningUnit = false,
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
)
@@ -123,17 +118,16 @@ class CoroutineTransformer(
val sourceCompilerForInline = inliningContext.root.sourceCompilerForInline
val stateMachineBuilder = CoroutineTransformerMethodVisitor(
createNewMethodFrom(node, name), node.access, name, node.desc, null, null,
containingClassInternalName = classBuilder.thisName,
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
isForNamedFunction = true,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization,
reportSuspensionPointInsideMonitor = { sourceCompilerForInline.reportSuspensionPointInsideMonitor(it) },
lineNumber = inliningContext.callSiteInfo.lineNumber,
sourceFile = inliningContext.callSiteInfo.file?.name ?: "",
languageVersionSettings = state.languageVersionSettings,
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
containingClassInternalName = classBuilder.thisName,
isForNamedFunction = true,
needDispatchReceiver = true,
internalNameForDispatchReceiver = classBuilder.thisName,
disableTailCallOptimizationForFunctionReturningUnit = disableTailCallOptimization,
putContinuationParameterToLvt = !state.isIrBackend,
useOldSpilledVarTypeAnalysis = state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_SPILLED_VAR_TYPE_ANALYSIS)
)

View File

@@ -0,0 +1,223 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isParameterCheckedForNull
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.*
fun canInlineArgumentsInPlace(methodNode: MethodNode): Boolean {
// Usual inline functions are inlined in the following way:
// <evaluate argument #1>
// <store argument to an argument variable V1>
// ...
// <evaluate argument #N>
// <store argument to an argument variable VN>
// <inline function method body with parameter variables Pi remapped to argument variables Vi>
// If an argument #k is already stored in a local variable W, this variable W is reused.
// When inlining arguments in-place, we instead replace corresponding variable load instructions in the inline function method body
// with bytecode for evaluating a given argument.
// We can do so if such transformation keeps the evaluation order intact, possibly disregarding class initialization.
//
// This is true for many simple @InlineOnly functions from Kotlin standard library.
// For example, bytecode for 'inline fun println(message: Any?)' is:
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
// ALOAD 0
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
// Basic inlining for 'println("Hello, world!")' would produce (skipping labels and line numbers):
// // evaluate arguments, storing them to local variables
// LDC "Hello, world!"
// ASTORE 0
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
// ALOAD 0
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
// With argument "Hello, world!" inlined in-place it would be:
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
// LDC "Hello, world!"
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
// Such inlining is possible because we consider it OK to reorder 'GETSTATIC java/lang/System.out : Ljava/io/PrintStream;' instruction
// with any argument evaluation instructions ('LDC "Hello, world!"' in this case).
val tcbStartLabels = methodNode.tryCatchBlocks.mapTo(HashSet()) { it.start }
val methodParameterTypes = Type.getArgumentTypes(methodNode.desc)
val jvmArgumentTypes = ArrayList<Type>(methodParameterTypes.size + 1)
if (methodNode.access and Opcodes.ACC_STATIC == 0) {
// Here we don't care much about the exact 'this' type,
// it's only important to remember that variable slot #0 holds an object reference.
jvmArgumentTypes.add(AsmTypes.OBJECT_TYPE)
}
jvmArgumentTypes.addAll(methodParameterTypes)
val argumentVarEnd = jvmArgumentTypes.sumOf { it.size }
var expectedArgumentVar = 0
var lastArgIndex = 0
var insn = methodNode.instructions.first
// During arguments evaluation, make sure that all arguments are loaded in expected order
// and there are no unexpected side effects in-between.
while (insn != null && expectedArgumentVar < argumentVarEnd) {
// Entering a try-catch block before all arguments are loaded breaks evaluation order.
if (insn in tcbStartLabels)
return false
// Some instructions break evaluation order.
if (insn.isProhibitedDuringArgumentsEvaluation())
return false
// Allow a limited list of 'GETSTATIC <owner> <name> <desc>' instructions.
if (insn.opcode == Opcodes.GETSTATIC) {
val fieldInsn = insn as FieldInsnNode
val fieldSignature = FieldSignature(fieldInsn.owner, fieldInsn.name, fieldInsn.desc)
if (fieldSignature !in whitelistedStaticFields)
return false
}
// Writing to or incrementing an argument variable forbids in-place argument inlining.
if (insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE && (insn as VarInsnNode).`var` < argumentVarEnd)
return false
if (insn.opcode == Opcodes.IINC && (insn as IincInsnNode).`var` < argumentVarEnd)
return false
// Analyze variable loads.
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD) {
// Skip parameter null check: 'aload x; ldc "..."; invokestatic <check>'
if (insn.opcode == Opcodes.ALOAD && insn.isParameterCheckedForNull()) {
// Go directly to the instruction after 'invokestatic <check>'
insn = insn.next.next.next
continue
}
val varInsn = insn as VarInsnNode
val varIndex = (varInsn).`var`
if (varIndex == expectedArgumentVar) {
// Expected argument variable loaded.
expectedArgumentVar += jvmArgumentTypes[lastArgIndex].size
++lastArgIndex
// Skip a sequence of load instructions referring to the same argument variable
// (such sequence is present in functions like 'Array.copyOf' and can be replaced with DUP instructions).
do {
insn = insn.next
} while (insn != null && insn.opcode == varInsn.opcode && (insn as VarInsnNode).`var` == varIndex)
continue
} else if (varIndex < argumentVarEnd) {
// Loaded an argument variable, but not an expected one => broken evaluation order
return false
} else {
// It's OK to load any non-argument variable during argument evaluation.
insn = insn.next
continue
}
}
// Anything else is fine.
insn = insn.next
}
// Method body is over, but not all arguments were loaded on stack.
if (expectedArgumentVar < argumentVarEnd)
return false
// After arguments evaluation make sure that argument variables are no longer accessed
// (we are not going to store anything to those variables anyway).
while (insn != null) {
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD || insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
if ((insn as VarInsnNode).`var` < argumentVarEnd)
return false
} else if (insn.opcode == Opcodes.IINC) {
if ((insn as IincInsnNode).`var` < argumentVarEnd)
return false
}
insn = insn.next
}
// Didn't encounter anything suspicious.
return true
}
internal data class FieldSignature(
val owner: String,
val name: String,
val desc: String
)
private val whitelistedStaticFields: Set<FieldSignature> =
hashSetOf(
FieldSignature("java/lang/System", "out", "Ljava/io/PrintStream;"),
FieldSignature("kotlin/Result", "Companion", "Lkotlin/Result\$Companion;"),
FieldSignature("kotlin/_Assertions", "ENABLED", "Z")
)
private fun AbstractInsnNode.isProhibitedDuringArgumentsEvaluation() =
opcode in opcodeProhibitedDuringArgumentsEvaluation.indices &&
opcodeProhibitedDuringArgumentsEvaluation[opcode]
private val opcodeProhibitedDuringArgumentsEvaluation = BooleanArray(256).also { a ->
// Any kind of jump during arguments evaluation is a hazard.
// This includes all conditional jump instructions, switch instructions, return and throw instructions.
// Very conservative, but enough for practical cases.
for (i in Opcodes.IFEQ..Opcodes.RETURN) a[i] = true
a[Opcodes.IFNULL] = true
a[Opcodes.IFNONNULL] = true
a[Opcodes.ATHROW] = true
// Instruction with non-trivial side effects is a hazard.
// NB GETSTATIC is taken care of separately.
a[Opcodes.PUTSTATIC] = true
a[Opcodes.PUTFIELD] = true
a[Opcodes.INVOKEVIRTUAL] = true
a[Opcodes.INVOKESPECIAL] = true
a[Opcodes.INVOKESTATIC] = true
a[Opcodes.INVOKEINTERFACE] = true
a[Opcodes.INVOKEDYNAMIC] = true
a[Opcodes.MONITORENTER] = true
a[Opcodes.MONITOREXIT] = true
// Integer division instructions can throw exception
a[Opcodes.IDIV] = true
a[Opcodes.LDIV] = true
a[Opcodes.IREM] = true
a[Opcodes.LREM] = true
// CHECKCAST can throw exception
a[Opcodes.CHECKCAST] = true
// Array creation can throw exception (in case of negative array size)
a[Opcodes.NEWARRAY] = true
a[Opcodes.ANEWARRAY] = true
a[Opcodes.MULTIANEWARRAY] = true
// Array access instructions can throw exception
for (i in Opcodes.IALOAD..Opcodes.SALOAD) a[i] = true
for (i in Opcodes.IASTORE..Opcodes.SASTORE) a[i] = true
}
private const val MARKER_INPLACE_CALL_START = "<INPLACE-CALL-START>"
private const val MARKER_INPLACE_ARGUMENT_START = "<INPLACE-ARGUMENT-START>"
private const val MARKER_INPLACE_ARGUMENT_END = "<INPLACE-ARGUMENT-END>"
private const val MARKER_INPLACE_CALL_END = "<INPLACE-CALL-END>"
private fun InstructionAdapter.addMarker(name: String) {
visitMethodInsn(Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME, name, "()V", false)
}
fun InstructionAdapter.addInplaceCallStartMarker() = addMarker(MARKER_INPLACE_CALL_START)
fun InstructionAdapter.addInplaceCallEndMarker() = addMarker(MARKER_INPLACE_CALL_END)
fun InstructionAdapter.addInplaceArgumentStartMarker() = addMarker(MARKER_INPLACE_ARGUMENT_START)
fun InstructionAdapter.addInplaceArgumentEndMarker() = addMarker(MARKER_INPLACE_ARGUMENT_END)
internal fun AbstractInsnNode.isInplaceCallStartMarker() = isInlineMarker(this, MARKER_INPLACE_CALL_START)
internal fun AbstractInsnNode.isInplaceCallEndMarker() = isInlineMarker(this, MARKER_INPLACE_CALL_END)
internal fun AbstractInsnNode.isInplaceArgumentStartMarker() = isInlineMarker(this, MARKER_INPLACE_ARGUMENT_START)
internal fun AbstractInsnNode.isInplaceArgumentEndMarker() = isInlineMarker(this, MARKER_INPLACE_ARGUMENT_END)

View File

@@ -60,7 +60,7 @@ const val INLINE_FUN_VAR_SUFFIX = "\$iv"
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$$INLINE_TRANSFORMATION_SUFFIX"
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
@@ -68,11 +68,10 @@ internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
const val CAPTURED_FIELD_PREFIX = "$"
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
private const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
internal const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
private const val INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"
private const val INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"
private const val INLINE_MARKER_FINALLY_START = "finallyStart"
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0
private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1
@@ -302,7 +301,7 @@ internal fun firstLabelInChain(node: LabelNode): LabelNode {
internal fun areLabelsBeforeSameInsn(first: LabelNode, second: LabelNode): Boolean =
firstLabelInChain(first) == firstLabelInChain(second)
internal val MethodNode?.nodeText: String
val MethodNode?.nodeText: String
get() {
if (this == null) {
return "Not generated"
@@ -535,17 +534,15 @@ internal fun isInlineMarker(insn: AbstractInsnNode): Boolean {
return isInlineMarker(insn, null)
}
private fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
if (insn !is MethodInsnNode) {
return false
}
internal fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
if (insn.opcode != Opcodes.INVOKESTATIC) return false
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
insn.owner == INLINE_MARKER_CLASS_NAME &&
val methodInsn = insn as MethodInsnNode
return methodInsn.owner == INLINE_MARKER_CLASS_NAME &&
if (name != null)
insn.name == name
methodInsn.name == name
else
insn.name == INLINE_MARKER_BEFORE_METHOD_NAME || insn.name == INLINE_MARKER_AFTER_METHOD_NAME
methodInsn.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsn.name == INLINE_MARKER_AFTER_METHOD_NAME
}
internal fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {

View File

@@ -5,13 +5,11 @@
package org.jetbrains.kotlin.codegen.inline
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineContext
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
@@ -30,25 +28,22 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode
fun generateInlineIntrinsicForIr(languageVersionSettings: LanguageVersionSettings, descriptor: FunctionDescriptor): SMAPAndMethodNode? =
fun generateInlineIntrinsicForIr(descriptor: FunctionDescriptor): SMAPAndMethodNode? =
when {
// TODO: implement these as codegen intrinsics (see IrIntrinsicMethods)
descriptor.isBuiltInIntercepted(languageVersionSettings) ->
createMethodNodeForIntercepted(languageVersionSettings)
descriptor.isBuiltInCoroutineContext(languageVersionSettings) ->
createMethodNodeForCoroutineContext(descriptor, languageVersionSettings)
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings)
descriptor.isBuiltInCoroutineContext() ->
createMethodNodeForCoroutineContext(descriptor)
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn() ->
createMethodNodeForSuspendCoroutineUninterceptedOrReturn()
else -> null
}?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
internal fun generateInlineIntrinsic(
languageVersionSettings: LanguageVersionSettings,
descriptor: FunctionDescriptor,
asmMethod: Method,
typeSystem: TypeSystemCommonBackendContext
): SMAPAndMethodNode? {
return generateInlineIntrinsicForIr(languageVersionSettings, descriptor) ?: when {
return generateInlineIntrinsicForIr(descriptor) ?: when {
isSpecialEnumMethod(descriptor) ->
createSpecialEnumMethodBody(descriptor.name.asString(), descriptor.original.typeParameters.single(), typeSystem)
TypeOfChecker.isTypeOf(descriptor) ->

View File

@@ -19,7 +19,7 @@ import org.jetbrains.org.objectweb.asm.tree.*
object TypeIntrinsics {
@JvmStatic
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type, isReleaseCoroutines: Boolean) {
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type) {
val functionTypeArity = getFunctionTypeArity(jetType)
if (functionTypeArity >= 0) {
v.iconst(functionTypeArity)
@@ -27,28 +27,26 @@ object TypeIntrinsics {
return
}
if (isReleaseCoroutines) {
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
if (suspendFunctionTypeArity >= 0) {
val notSuspendLambda = Label()
val end = Label()
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
if (suspendFunctionTypeArity >= 0) {
val notSuspendLambda = Label()
val end = Label()
with(v) {
dup()
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
ifeq(notSuspendLambda)
iconst(suspendFunctionTypeArity + 1)
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
goTo(end)
with(v) {
dup()
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
ifeq(notSuspendLambda)
iconst(suspendFunctionTypeArity + 1)
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
goTo(end)
mark(notSuspendLambda)
pop()
iconst(0)
mark(notSuspendLambda)
pop()
iconst(0)
mark(end)
}
return
mark(end)
}
return
}
val isMutableCollectionMethodName = getIsMutableCollectionMethodName(jetType)

View File

@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.codegen.optimization
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
import org.jetbrains.kotlin.codegen.inline.InplaceArgumentsMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.boxing.PopBackwardPropagationTransformer
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer
import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer
@@ -40,6 +41,7 @@ class OptimizationMethodVisitor(
UninitializedStoresMethodTransformer(generationState.constructorCallNormalizationMode)
val normalizationMethodTransformer = CompositeMethodTransformer(
InplaceArgumentsMethodTransformer(),
FixStackWithLabelNormalizationMethodTransformer(),
MethodVerifier("AFTER mandatory stack transformations", generationState)
)

View File

@@ -17,9 +17,8 @@
package org.jetbrains.kotlin.codegen.optimization.boxing
import com.google.common.collect.ImmutableSet
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.coroutines.RELEASE_COROUTINES_VERSION_SETTINGS
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
@@ -216,7 +215,7 @@ fun AbstractInsnNode.isPrimitiveBoxing() =
}
private val BOXING_CLASS_INTERNAL_NAME =
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
StandardNames.COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("Boxing")).topLevelClassInternalName()
private fun isJvmPrimitiveName(name: String) = JvmPrimitiveType.values().any { it.javaKeywordName == name }

View File

@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
@@ -36,7 +35,7 @@ val AbstractInsnNode.isMeaningful: Boolean
val AbstractInsnNode.isBranchOrCall: Boolean
get() =
when(this.type) {
when (this.type) {
AbstractInsnNode.JUMP_INSN,
AbstractInsnNode.TABLESWITCH_INSN,
AbstractInsnNode.LOOKUPSWITCH_INSN,
@@ -85,13 +84,17 @@ fun MethodNode.prepareForEmitting() {
current = prev
}
updateMaxStack()
}
fun MethodNode.updateMaxStack() {
maxStack = -1
accept(
MaxStackFrameSizeAndLocalsCalculator(
Opcodes.API_VERSION, access, desc,
object : MethodVisitor(Opcodes.API_VERSION) {
API_VERSION, access, desc,
object : MethodVisitor(API_VERSION) {
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
this@prepareForEmitting.maxStack = maxStack
this@updateMaxStack.maxStack = maxStack
}
})
)
@@ -100,10 +103,10 @@ fun MethodNode.prepareForEmitting() {
fun MethodNode.stripOptimizationMarkers() {
var insn = instructions.first
while (insn != null) {
if (isOptimizationMarker(insn)) {
insn = instructions.removeNodeGetNext(insn)
insn = if (isOptimizationMarker(insn)) {
instructions.removeNodeGetNext(insn)
} else {
insn = insn.next
insn.next
}
}
}
@@ -123,7 +126,7 @@ fun MethodNode.removeUnusedLocalVariables() {
// Arguments are always used whether or not they are in the local variable table
// or used by instructions.
var argumentIndex = 0
val isStatic = (access and Opcodes.ACC_STATIC) != 0
val isStatic = (access and ACC_STATIC) != 0
if (!isStatic) {
used[argumentIndex++] = true
}
@@ -230,8 +233,8 @@ val AbstractInsnNode.intConstant: Int?
fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEach { add(it) } }
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in ISTORE..ASTORE
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in ILOAD..ALOAD
val AbstractInsnNode?.debugText
get() =

View File

@@ -441,7 +441,7 @@ fun MethodNode.usesLocalExceptParameterNullCheck(index: Int): Boolean =
it is VarInsnNode && it.opcode == Opcodes.ALOAD && it.`var` == index && !it.isParameterCheckedForNull()
}
internal fun AbstractInsnNode.isParameterCheckedForNull(): Boolean =
fun AbstractInsnNode.isParameterCheckedForNull(): Boolean =
next?.takeIf { it.opcode == Opcodes.LDC }?.next?.isCheckParameterIsNotNull() == true
internal fun AbstractInsnNode.isCheckParameterIsNotNull() =

View File

@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.diagnostics.PrecomputedSuppressCache
@@ -158,8 +157,7 @@ class GenerationState private constructor(
CompilerDeserializationConfiguration(languageVersionSettings)
val deprecationProvider = DeprecationResolver(
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, CoroutineCompatibilitySupport.ENABLED,
JavaDeprecationSettings
LockBasedStorageManager.NO_LOCKS, languageVersionSettings, JavaDeprecationSettings
)
init {

View File

@@ -193,7 +193,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
if (descriptor.isSuspendFunctionNotSuspensionView()) {
return mapReturnType(getOrCreateJvmSuspendFunctionView(descriptor as SimpleFunctionDescriptor, isReleaseCoroutines), sw)
return mapReturnType(getOrCreateJvmSuspendFunctionView(descriptor as SimpleFunctionDescriptor), sw)
}
if (hasVoidReturnType(descriptor)) {
@@ -804,7 +804,7 @@ class KotlinTypeMapper @JvmOverloads constructor(
}
if (f.isSuspendFunctionNotSuspensionView()) {
return mapSignature(getOrCreateJvmSuspendFunctionView(f, isReleaseCoroutines), kind, skipGenericSignature)
return mapSignature(getOrCreateJvmSuspendFunctionView(f), kind, skipGenericSignature)
}
if (isDeclarationOfBigArityFunctionInvoke(f) || isDeclarationOfBigArityCreateCoroutineMethod(f)) {

View File

@@ -1,4 +1,3 @@
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.ideaExt.idea
import java.io.File
@@ -10,8 +9,6 @@ plugins {
val compilerModules: Array<String> by rootProject.extra
val otherCompilerModules = compilerModules.filter { it != path }
val tasksWithWarnings: List<String> by rootProject.extra
val antLauncherJar by configurations.creating
dependencies {
@@ -68,18 +65,6 @@ if (kotlinBuildProperties.isInJpsBuildIdeaSync) {
}
}
if (!kotlinBuildProperties.disableWerror) {
allprojects {
tasks.withType<KotlinCompile<*>> {
if (path !in tasksWithWarnings) {
kotlinOptions {
allWarningsAsErrors = true
}
}
}
}
}
projectTest(parallel = true) {
dependsOn(":dist")

View File

@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.ir.backend.js.ic.buildCache
import org.jetbrains.kotlin.ir.backend.js.ic.checkCaches
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
import org.jetbrains.kotlin.js.config.*
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
@@ -205,7 +206,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
cachePath = outputFilePath,
project = projectJs,
mainModule = mainModule,
analyzer = AnalyzerWithCompilerReport(config.configuration),
configuration = config.configuration,
dependencies = libraries,
friendDependencies = friendLibraries,
@@ -219,18 +219,37 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
return OK
}
// Run analysis if main module is sources
lateinit var sourceModule: ModulesStructure
if (arguments.includes == null) {
do {
sourceModule = prepareAnalyzedSourceModule(
projectJs,
environmentForJS.getSourceFiles(),
configurationJs,
libraries,
friendLibraries,
AnalyzerWithCompilerReport(config.configuration),
icUseGlobalSignatures = icCaches.isNotEmpty(),
icUseStdlibCache = icCaches.isNotEmpty(),
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = arguments.includes).data else emptyMap()
)
val result = sourceModule.jsFrontEndResult.jsAnalysisResult
if (result is JsAnalysisResult.RetryWithAdditionalRoots) {
environmentForJS.addKotlinSourceRoots(result.additionalKotlinRoots)
}
} while (result is JsAnalysisResult.RetryWithAdditionalRoots)
if (!sourceModule.jsFrontEndResult.jsAnalysisResult.shouldGenerateCode)
return OK
}
if (arguments.irProduceKlibDir || arguments.irProduceKlibFile) {
if (arguments.irProduceKlibFile) {
require(outputFile.extension == KLIB_FILE_EXTENSION) { "Please set up .klib file as output" }
}
generateKLib(
project = config.project,
files = sourcesFiles,
analyzer = AnalyzerWithCompilerReport(config.configuration),
configuration = config.configuration,
dependencies = libraries,
friendDependencies = friendLibraries,
sourceModule,
irFactory = PersistentIrFactory(), // TODO IrFactoryImpl?
outputKlibPath = outputFile.path,
nopack = arguments.irProduceKlibDir,
@@ -246,28 +265,33 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
val includes = arguments.includes
val mainModule = if (includes != null) {
val module = if (includes != null) {
if (sourcesFiles.isNotEmpty()) {
messageCollector.report(ERROR, "Source files are not supported when -Xinclude is present")
}
val includesPath = File(includes).canonicalPath
val mainLibPath = libraries.find { File(it).canonicalPath == includesPath }
?: error("No library with name $includes ($includesPath) found")
MainModule.Klib(mainLibPath)
val kLib = MainModule.Klib(mainLibPath)
ModulesStructure(
projectJs,
kLib,
configurationJs,
libraries,
friendLibraries,
icUseGlobalSignatures = icCaches.isNotEmpty(),
icUseStdlibCache = icCaches.isNotEmpty(),
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).data else emptyMap()
)
} else {
MainModule.SourceFiles(sourcesFiles)
sourceModule
}
if (arguments.wasm) {
val res = compileWasm(
projectJs,
mainModule,
AnalyzerWithCompilerReport(config.configuration),
config.configuration,
module,
PhaseConfig(wasmPhases),
IrFactoryImpl,
dependencies = libraries,
friendDependencies = friendLibraries,
exportedDeclarations = setOf(FqName("main"))
)
val outputWasmFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "wasm")!!
@@ -289,14 +313,9 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
val start = System.currentTimeMillis()
val compiledModule = compile(
projectJs,
mainModule,
AnalyzerWithCompilerReport(config.configuration),
config.configuration,
module,
phaseConfig,
if (arguments.irDceDriven) PersistentIrFactory() else IrFactoryImpl,
dependencies = libraries,
friendDependencies = friendLibraries,
mainArguments = mainCallArguments,
generateFullJs = !arguments.irDce,
generateDceJs = arguments.irDce,
@@ -316,8 +335,6 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
messageCollector
),
lowerPerModule = icCaches.isNotEmpty(),
useStdlibCache = icCaches.isNotEmpty(),
icCache = if (icCaches.isNotEmpty()) checkCaches(libraries, icCaches, skipLib = includes).data else emptyMap(),
)
messageCollector.report(INFO, "Executable production duration: ${System.currentTimeMillis() - start}ms")

View File

@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.load.java.components.JavaDeprecationSettings
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.deprecation.CoroutineCompatibilitySupport
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.KotlinType
@@ -84,7 +83,6 @@ class CliLightClassGenerationSupport(
get() = DeprecationResolver(
LockBasedStorageManager.NO_LOCKS,
languageVersionSettings,
CoroutineCompatibilitySupport.ENABLED,
JavaDeprecationSettings
)

View File

@@ -1,39 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.config
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
fun LanguageVersionSettings.coroutinesPackageFqName(): FqName {
return coroutinesPackageFqName(isReleaseCoroutines())
}
fun LanguageVersionSettings.isReleaseCoroutines() = supportsFeature(LanguageFeature.ReleaseCoroutines)
private fun coroutinesPackageFqName(isReleaseCoroutines: Boolean): FqName {
return if (isReleaseCoroutines)
StandardNames.COROUTINES_PACKAGE_FQ_NAME_RELEASE
else
StandardNames.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL
}
fun LanguageVersionSettings.coroutinesIntrinsicsPackageFqName() =
coroutinesPackageFqName().child(Name.identifier("intrinsics"))
fun LanguageVersionSettings.continuationInterfaceFqName() =
coroutinesPackageFqName().child(Name.identifier("Continuation"))
fun LanguageVersionSettings.restrictsSuspensionFqName() =
coroutinesPackageFqName().child(Name.identifier("RestrictsSuspension"))
fun FqName.isBuiltInCoroutineContext(languageVersionSettings: LanguageVersionSettings) =
if (languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines))
this == StandardNames.COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier("coroutineContext"))
else
this == StandardNames.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext")) ||
this == StandardNames.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext"))

View File

@@ -12,7 +12,7 @@ fun test() {
bar(1, z = true, y = *arrayOf("my", "yours"))
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
bar(0, "", true<!NO_VALUE_FOR_PARAMETER!>)<!>
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
}

View File

@@ -23,6 +23,16 @@ FILE: const.kt
public get(): R|kotlin/Int|
public final const val l: R|kotlin/Int| = R|/k|
public get(): R|kotlin/Int|
public final const val m: R|kotlin/String| = String(123).R|kotlin/Any.toString|()
public get(): R|kotlin/String|
public final const val n: R|kotlin/Int| = String(456).R|kotlin/String.length|
public get(): R|kotlin/Int|
public final val o: R|kotlin/String| = String(789)
public get(): R|kotlin/String|
public final const val p: R|kotlin/String| = R|/o|.R|kotlin/Any.toString|()
public get(): R|kotlin/String|
public final const val q: R|kotlin/Int| = R|/o|.R|kotlin/String.length|
public get(): R|kotlin/Int|
public final class ForConst : R|kotlin/Any| {
public constructor(): R|ForConst| {
super<R|kotlin/Any|>()

View File

@@ -18,6 +18,11 @@ const val i = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>ForConst.one() + "one"<!>
const val j = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>4 * ForConst.two()<!>
val k = 3 - ForConst.two()
const val l = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>k<!>
const val m = "123".toString()
const val n = "456".length
val o = "789"
const val p = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>o.toString()<!>
const val q = <!CONST_VAL_WITH_NON_CONST_INITIALIZER!>o.length<!>
class ForConst{
companion object {

View File

@@ -38,5 +38,5 @@ object F {
}
fun foo() {
const val a = "2"
<!WRONG_MODIFIER_TARGET!>const<!> val a = "2"
}

View File

@@ -8,17 +8,17 @@ fun test() {}
fun test(z: Int, c: Char) {}
<!REDECLARATION!>open class A {
open class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>A<!> {
open fun rest(s: String) {}
open val u = 20
}<!>
}
<!REDECLARATION!>class A {
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>A<!> {
}<!>
}
<!REDECLARATION!>class B : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
<!CONFLICTING_OVERLOADS!><!NOTHING_TO_OVERRIDE!>override<!> fun rest(s: String)<!> {}
<!CONFLICTING_OVERLOADS!>fun rest(s: String)<!> {}
@@ -26,17 +26,17 @@ fun test(z: Int, c: Char) {}
fun rest(l: Long) {}
<!NOTHING_TO_OVERRIDE!>override<!> val u = 310
}<!>
}
<!REDECLARATION!>interface B<!>
interface <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!>
<!REDECLARATION!>enum class B<!>
enum class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!>
<!REDECLARATION!>val u = 10<!>
<!REDECLARATION!>val u = 20<!>
val <!REDECLARATION!>u<!> = 10
val <!REDECLARATION!>u<!> = 20
<!REDECLARATION!>typealias TA = A<!>
<!REDECLARATION!>typealias TA = B<!>
typealias <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>TA<!> = A
typealias <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>TA<!> = B
typealias BA = A
@@ -52,7 +52,7 @@ fun lol(a: Array<Boolean>) {}
class M {
companion <!REDECLARATION!>object<!> {}
<!REDECLARATION!>val Companion = object : Any {}<!>
val <!REDECLARATION!>Companion<!> = object : Any {}
}
fun B.foo() {}

View File

@@ -1,5 +1,5 @@
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>public<!> class B
<!INCOMPATIBLE_MODIFIERS!>protected<!> <!INCOMPATIBLE_MODIFIERS!>internal<!> class C
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>protected<!> <!INCOMPATIBLE_MODIFIERS!>internal<!> class C
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> class D
<!INCOMPATIBLE_MODIFIERS!>final<!> <!INCOMPATIBLE_MODIFIERS!>open<!> class E

View File

@@ -6,11 +6,11 @@ infix fun Int.good(x: Int) {}
<!INAPPLICABLE_INFIX_MODIFIER!>infix fun baz(x: Int, y: Int) {}<!>
infix class A
<!WRONG_MODIFIER_TARGET!>infix<!> class A
infix typealias B = A
<!WRONG_MODIFIER_TARGET!>infix<!> typealias B = A
infix val x = 1
<!WRONG_MODIFIER_TARGET!>infix<!> val x = 1
class C {
infix fun good(x: Int) {}

View File

@@ -37,7 +37,7 @@ class F(var a: Int, b: Int, closure: () -> Unit, instance: F?) {
val a = 10
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>
test(<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>)
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>a<!> = 20
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.a = 20
}, <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>) {
this.a = 30
}

View File

@@ -13,13 +13,13 @@ interface B {
}
interface C {
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun toString(): String = "Rest"<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String = "Rest"<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun equals(other: Any?): Boolean = false<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun hashCode(): Int = 2<!>
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int = 2<!>
}
interface D {
override operator fun toString(): String
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String
override operator fun equals(other: Any?): Boolean
override operator fun hashCode(): Int
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int
}

View File

@@ -14,7 +14,7 @@ FILE: notASupertype.kt
}
public final fun g(): R|kotlin/Unit| {
this@R|/B|.super<R|kotlin/String|>.<Unresolved name: f>#()
this@R|/B|.super<<ERROR TYPE REF: Not a super type>>.<Unresolved name: f>#()
this@R|/B|.super<R|A|>.R|/A.f|()
}

View File

@@ -4,7 +4,7 @@ open class A {
class B : <!SUPERTYPE_NOT_INITIALIZED!>A<!> {
fun g() {
<!NOT_A_SUPERTYPE!>super<String><!>.<!UNRESOLVED_REFERENCE!>f<!>()
super<<!NOT_A_SUPERTYPE!>String<!>>.f()
super<A>.f()
}
}

View File

@@ -2,7 +2,7 @@
sealed class A
<!REDECLARATION!>class B : A()<!>
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> : A()
interface C : <!INTERFACE_WITH_SUPERCLASS!>A<!>
@@ -30,7 +30,7 @@ sealed class P {
class K : P()
<!REDECLARATION!>object B<!> {
object <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> {
class I : P()
}

View File

@@ -1,12 +1,12 @@
FILE: superNotAvailable.kt
public final fun R|kotlin/String|.f(): R|kotlin/Unit| {
super<<ERROR TYPE REF: No super type>>@f#.<Unresolved name: compareTo>#(String())
super<<ERROR TYPE REF: No super type>>.<Unresolved name: compareTo>#(String())
<Super not available>#.<Unresolved name: compareTo>#(String())
<Super not available>#.<Unresolved name: compareTo>#(String())
}
public final fun foo(): R|kotlin/Unit| {
super<<ERROR TYPE REF: No super type>>
super<<ERROR TYPE REF: No super type>>.<Unresolved name: foo>#()
super<R|kotlin/Nothing|>.<Unresolved name: foo>#()
<Super not allowed>#
<Super not available>#.<Unresolved name: foo>#()
<Super not available>#.<Unresolved name: foo>#()
}
public final class A : R|kotlin/Any| {
public constructor(): R|A| {

View File

@@ -1,12 +1,12 @@
fun String.f() {
<!SUPER_NOT_AVAILABLE!>super@f<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
<!SUPER_NOT_AVAILABLE!>super@f<!>.compareTo("")
<!SUPER_NOT_AVAILABLE!>super<!>.compareTo("")
}
fun foo() {
<!SUPER_NOT_AVAILABLE!>super<!>
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
<!SUPER_NOT_AVAILABLE!>super<!>.foo()
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.foo()
}
class A {

View File

@@ -16,7 +16,7 @@ FILE: test.kt
private final val DERIVED_FACTORY: R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|ft<DerivedElement, DerivedElement?>|>()
private get(): R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>|
public final fun createViaFactory(d: R|EmptyDiagnostic|): R|kotlin/Unit| {
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|@EnhancedNullability Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
lval element: R|DerivedElement| = R|<local>/casted|.R|/Diagnostic.element|
R|/Fix.Fix|(R|<local>/element|)
}

View File

@@ -2,7 +2,7 @@
fun x() {}
operator fun Int.invoke(): Foo = <!UNRESOLVED_LABEL!>this@Foo<!>
operator fun Int.invoke(): Foo = this<!UNRESOLVED_LABEL!>@Foo<!>
class Foo {

View File

@@ -1,6 +1,6 @@
<!REDECLARATION!>object A<!>
object <!REDECLARATION!>A<!>
<!REDECLARATION!>val A = 10<!>
val <!REDECLARATION!>A<!> = 10
fun foo() = A

View File

@@ -10,7 +10,7 @@ interface Interface {
// Redundant
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun foo()
// error
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> final fun bar()
<!PRIVATE_FUNCTION_WITH_NO_BODY!>private<!> <!WRONG_MODIFIER_CONTAINING_DECLARATION!>final<!> fun bar()
<!REDUNDANT_MODALITY_MODIFIER!>open<!> fun goo() {}
<!REDUNDANT_MODALITY_MODIFIER!>abstract<!> fun tar()
@@ -63,7 +63,7 @@ interface Derived : Interface {
// Redundant
override <!REDUNDANT_MODALITY_MODIFIER!>open<!> fun foo() {}
// error
final class Nested
<!WRONG_MODIFIER_CONTAINING_DECLARATION!>final<!> class Nested
}
// Derived abstract class
abstract class AbstractDerived1(override final val gav: Int) : Interface {
@@ -82,4 +82,4 @@ abstract interface AbstractInterface
// Redundant final object
<!REDUNDANT_MODALITY_MODIFIER!>final<!> object FinalObject
// Open interface
open interface OpenInterface
<!REDUNDANT_MODIFIER_FOR_TARGET!>open<!> interface OpenInterface

View File

@@ -2,15 +2,15 @@
@Target(AnnotationTarget.VALUE_PARAMETER)
annotation class Ann
<!REDECLARATION!>var x: Int
var <!REDECLARATION!>x<!>: Int
get() = 1
set(@Ann private x) { }<!>
set(@Ann <!WRONG_MODIFIER_TARGET!>private<!> x) { }
<!REDECLARATION!>var x: String = ""
var <!REDECLARATION!>x<!>: String = ""
set(param: <!REDUNDANT_SETTER_PARAMETER_TYPE!>String<!>) {
field = "$param "
}<!>
}
class My {
var y: Int = 1
@@ -25,4 +25,4 @@ class My {
set(param) {
field = !param
}
}
}

View File

@@ -1,5 +1,5 @@
fun f() {
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> <!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>baz<!> = 0
<!REDUNDANT_VISIBILITY_MODIFIER, WRONG_MODIFIER_TARGET!>public<!> <!CAN_BE_VAL!>var<!> <!UNUSED_VARIABLE!>baz<!> = 0
class LocalClass {
<!REDUNDANT_VISIBILITY_MODIFIER!>internal<!> var foo = 0
}
@@ -10,11 +10,11 @@ internal <!NOTHING_TO_INLINE!>inline<!> fun internal() {
f()
}
<!REDECLARATION!>class C {
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>C<!> {
internal val z = object {
fun foo() = 13
}
}<!>
}
class Foo2<
T1,
@@ -26,12 +26,12 @@ class Foo2<
internal inner class B<T,T2,>
}
<!REDECLARATION!><!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class C {
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>C<!> {
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> val foo: Int = 0
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> fun bar() {}
}<!>
}
open class D {
protected open fun willRemainProtected() {

View File

@@ -15,7 +15,7 @@ open class B {
override fun foo() {
super.foo()
super.<!UNRESOLVED_REFERENCE!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
<!AMBIGUOUS_SUPER!>super<!>.bar() // should be ambiguity (NB: really we should have overridden bar in C)
super.baz() // Ok
baz() // Ok

View File

@@ -1,7 +1,7 @@
class A {
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> inner class B(val x: Int)
fun foo() {
<!INLINE_CLASS_NOT_TOP_LEVEL!>inline<!> class C(val x: Int)
<!INLINE_CLASS_NOT_TOP_LEVEL, WRONG_MODIFIER_TARGET!>inline<!> class C(val x: Int)
}
inner <!INLINE_CLASS_NOT_TOP_LEVEL!>value<!> class D(val x: Int)
}

View File

@@ -25,7 +25,7 @@ abstract class NotRange4() {
}
abstract class ImproperIterator3 {
abstract operator fun hasNext() : Int
abstract <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hasNext() : Int
abstract operator fun next() : Int
}

View File

@@ -0,0 +1,28 @@
FILE: EnumWithToString.kt
public final enum class Some : R|kotlin/Enum<Some>| {
private constructor(): R|Some| {
super<R|kotlin/Enum<Some>|>()
}
public final static enum entry ENTRY: R|Some| = object : R|Some| {
private constructor(): R|<anonymous>| {
super<R|Some|>()
}
public final override fun toString(): R|kotlin/String| {
^toString String(Entry)
}
}
public open override fun toString(): R|kotlin/String| {
^toString String(Some)
}
public final static fun values(): R|kotlin/Array<Some>| {
}
public final static fun valueOf(value: R|kotlin/String|): R|Some| {
}
}

View File

@@ -0,0 +1,7 @@
enum class Some {
ENTRY {
override fun toString(): String = "Entry"
};
override fun toString(): String = "Some"
}

View File

@@ -0,0 +1,9 @@
FILE: IntersectionWithJavaString.kt
public final fun collapse(path: R|kotlin/String|): R|kotlin/Unit| {
lval result: R|ft<kotlin/String, kotlin/String?>| = (R|<local>/path| as R|java/lang/String|).R|java/lang/String.replace|(String(123), String(456))
when () {
!==(R|<local>/result|, R|<local>/path|) -> {
}
}
}

View File

@@ -0,0 +1,5 @@
// FULL_JDK
fun collapse(path: String) {
val result = (path as java.lang.String).replace("123", "456")
if (<!EQUALITY_NOT_APPLICABLE_WARNING!>result !== path<!>) {}
}

View File

@@ -0,0 +1,19 @@
FILE: use.kt
public final class BeforeRunTask<T> : R|kotlin/Any| {
public constructor<T>(): R|BeforeRunTask<T>| {
super<R|kotlin/Any|>()
}
}
public abstract interface PersistentStateComponent<T> : R|kotlin/Any| {
}
public final fun <T> deserializeAndLoadState(component: R|PersistentStateComponent<T>|, clazz: R|java/lang/Class<T>| = Q|ComponentSerializationUtil|.R|/ComponentSerializationUtil.getStateClass|<R|ft<T!!, T?>|>(<getClass>(R|<local>/component|).R|kotlin/jvm/java|<R|CapturedType(out PersistentStateComponent<T>)|>)): R|kotlin/Unit| {
}
public final fun use(beforeRunTask: R|BeforeRunTask<*>|): R|kotlin/Unit| {
when () {
(R|<local>/beforeRunTask| is R|PersistentStateComponent<*>|) -> {
R|/deserializeAndLoadState|<R|CapturedType(*)|>(R|<local>/beforeRunTask|)
}
}
}

View File

@@ -0,0 +1,27 @@
// FILE: ComponentSerializationUtil.java
import org.jetbrains.annotations.NotNull;
public final class ComponentSerializationUtil {
@NotNull
public static <S> Class<S> getStateClass(@NotNull Class<? extends PersistentStateComponent> aClass)
{}
}
// FILE: use.kt
class BeforeRunTask<T>
interface PersistentStateComponent<T>
fun <T> deserializeAndLoadState(
component: PersistentStateComponent<T>,
clazz: Class<T> = ComponentSerializationUtil.getStateClass(component::class.java)
) {}
fun use(beforeRunTask: BeforeRunTask<*>) {
if (beforeRunTask is PersistentStateComponent<*>) {
deserializeAndLoadState(beforeRunTask)
}
}

View File

@@ -0,0 +1,42 @@
FILE: UastPatterns.kt
public abstract interface UElement : R|kotlin/Any| {
}
public abstract interface UExpression : R|UElement| {
}
public abstract interface UReferenceExpression : R|UExpression| {
}
public final fun injectionHostOrReferenceExpression(): R|UExpressionPattern.Capture<UExpression>| {
^injectionHostOrReferenceExpression R|/uExpression|().R|SubstitutionOverride</UExpressionPattern.Capture.filter: R|UExpressionPattern.Capture<UExpression>|>|(<L> = filter@fun <anonymous>(it: R|UExpression|): R|kotlin/Boolean| <inline=NoInline> {
^ (R|<local>/it| is R|UReferenceExpression|)
}
)
}
public final fun uExpression(): R|UExpressionPattern.Capture<UExpression>| {
^uExpression R|/expressionCapture|<R|UExpression|>(<getClass>(Q|UExpression|).R|kotlin/jvm/java|<R|UExpression|>)
}
public final fun <T : R|UExpression|> expressionCapture(clazz: R|java/lang/Class<T>|): R|UExpressionPattern.Capture<T>| {
^expressionCapture Q|UExpressionPattern|.R|SubstitutionOverride</UExpressionPattern.Capture.Capture>|<R|T|>(R|<local>/clazz|)
}
public open class UElementPattern<T : R|UElement|, Self : R|UElementPattern<T, Self>|> : R|ObjectPattern<T, Self>| {
public constructor<T : R|UElement|, Self : R|UElementPattern<T, Self>|>(clazz: R|java/lang/Class<T>|): R|UElementPattern<T, Self>| {
super<R|ObjectPattern<T, Self>|>(R|<local>/clazz|)
}
public final fun filter(filter: R|(T) -> kotlin/Boolean|): R|Self| {
^filter (this@R|/UElementPattern| as R|Self|)
}
}
public open class UExpressionPattern<T : R|UExpression|, Self : R|UExpressionPattern<T, Self>|> : R|UElementPattern<T, Self>| {
public constructor<T : R|UExpression|, Self : R|UExpressionPattern<T, Self>|>(clazz: R|java/lang/Class<T>|): R|UExpressionPattern<T, Self>| {
super<R|UElementPattern<T, Self>|>(R|<local>/clazz|)
}
public open class Capture<T : R|UExpression|> : R|UExpressionPattern<T, UExpressionPattern.Capture<T>>| {
public constructor<T : R|UExpression|>(clazz: R|java/lang/Class<T>|): R|UExpressionPattern.Capture<T>| {
super<R|UExpressionPattern<T, UExpressionPattern.Capture<T>>|>(R|<local>/clazz|)
}
}
}

View File

@@ -0,0 +1,38 @@
// FILE: ObjectPattern.java
import org.jetbrains.annotations.NotNull;
public abstract class ObjectPattern<T, Self extends ObjectPattern<T, Self>> {
protected ObjectPattern(@NotNull Class<T> aClass) {
}
public static class Capture<T> extends ObjectPattern<T,Capture<T>> {
public Capture(@NotNull Class<T> aClass) {
super(aClass);
}
}
}
// FILE: UastPatterns.kt
interface UElement
interface UExpression : UElement
interface UReferenceExpression : UExpression
fun injectionHostOrReferenceExpression(): UExpressionPattern.Capture<UExpression> =
uExpression().filter { it is UReferenceExpression }
fun uExpression(): UExpressionPattern.Capture<UExpression> = expressionCapture(UExpression::class.java)
fun <T : UExpression> expressionCapture(clazz: Class<T>): UExpressionPattern.Capture<T> = UExpressionPattern.Capture(clazz)
open class UElementPattern<T : UElement, Self : UElementPattern<T, Self>>(clazz: Class<T>) : ObjectPattern<T, Self>(clazz) {
fun filter(filter: (T) -> Boolean): Self = this as Self
}
open class UExpressionPattern<T : UExpression, Self : UExpressionPattern<T, Self>>(clazz: Class<T>) : UElementPattern<T, Self>(clazz) {
open class Capture<T : UExpression>(clazz: Class<T>) : UExpressionPattern<T, Capture<T>>(clazz)
}

View File

@@ -0,0 +1,24 @@
FILE: WithSpeedSearch.kt
public final class JList<E> : R|kotlin/Any| {
public constructor<E>(): R|JList<E>| {
super<R|kotlin/Any|>()
}
}
public final class ListSpeedSearch<T> : R|kotlin/Any| {
public constructor<T>(list: R|JList<T>|): R|ListSpeedSearch<T>| {
super<R|kotlin/Any|>()
}
}
public final class XThreadsFramesView : R|kotlin/Any| {
public constructor(): R|XThreadsFramesView| {
super<R|kotlin/Any|>()
}
private final fun <J : R|JList<*>|> R|J|.withSpeedSearch(): R|J| {
lval search: R|ListSpeedSearch<out kotlin/Any?>| = R|/ListSpeedSearch.ListSpeedSearch|<R|CapturedType(*)|>(this@R|/XThreadsFramesView.withSpeedSearch|)
^withSpeedSearch this@R|/XThreadsFramesView.withSpeedSearch|
}
}

View File

@@ -0,0 +1,10 @@
class JList<E>
class ListSpeedSearch<T>(list: JList<T>)
class XThreadsFramesView {
private fun <J> J.withSpeedSearch(): J where J : JList<*> {
val search = ListSpeedSearch(this)
return this
}
}

View File

@@ -13,7 +13,7 @@ fun test() {
val Any.bar get() = "456"
val String.bar get() = "987"
<!REDECLARATION!>val t = "".bar<!>
val <!REDECLARATION!>t<!> = "".bar
val p = Pair(0, "")
@@ -21,4 +21,4 @@ open class Base<T>(val x: T)
class Derived : Base<Int>(10)
val xx = Derived().x + 1
<!REDECLARATION!>val t = throw AssertionError("")<!>
val <!REDECLARATION!>t<!> = throw AssertionError("")

View File

@@ -5038,6 +5038,36 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
public void testDailyAggregatedDoubleFactor() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/DailyAggregatedDoubleFactor.kt");
}
@Test
@TestMetadata("EnumWithToString.kt")
public void testEnumWithToString() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.kt");
}
@Test
@TestMetadata("IntersectionWithJavaString.kt")
public void testIntersectionWithJavaString() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/IntersectionWithJavaString.kt");
}
@Test
@TestMetadata("PersistentStateComponent.kt")
public void testPersistentStateComponent() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.kt");
}
@Test
@TestMetadata("UastPatterns.kt")
public void testUastPatterns() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.kt");
}
@Test
@TestMetadata("WithSpeedSearch.kt")
public void testWithSpeedSearch() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.kt");
}
}
@Nested

View File

@@ -5038,6 +5038,36 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
public void testDailyAggregatedDoubleFactor() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/DailyAggregatedDoubleFactor.kt");
}
@Test
@TestMetadata("EnumWithToString.kt")
public void testEnumWithToString() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/EnumWithToString.kt");
}
@Test
@TestMetadata("IntersectionWithJavaString.kt")
public void testIntersectionWithJavaString() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/IntersectionWithJavaString.kt");
}
@Test
@TestMetadata("PersistentStateComponent.kt")
public void testPersistentStateComponent() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/PersistentStateComponent.kt");
}
@Test
@TestMetadata("UastPatterns.kt")
public void testUastPatterns() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/UastPatterns.kt");
}
@Test
@TestMetadata("WithSpeedSearch.kt")
public void testWithSpeedSearch() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/WithSpeedSearch.kt");
}
}
@Nested

View File

@@ -5908,6 +5908,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
}
@Test
@TestMetadata("lambdaInTryFalsePositive.kt")
public void testLambdaInTryFalsePositive() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/lambdaInTryFalsePositive.kt");
}
@Test
@TestMetadata("ReturnFromFunctionInObject.kt")
public void testReturnFromFunctionInObject() throws Exception {
@@ -6013,6 +6019,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("breakToLabel.kt")
public void testBreakToLabel() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlStructures/breakToLabel.kt");
}
@Test
@TestMetadata("catchGenerics.kt")
public void testCatchGenerics() throws Exception {
@@ -16843,6 +16855,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
}
@Test
@TestMetadata("integerNotNullable.kt")
public void testIntegerNotNullable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
}
@Test
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
@@ -21688,6 +21706,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
}
@Test
@TestMetadata("kotlinStarProjection.kt")
public void testKotlinStarProjection() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
}
@Test
@TestMetadata("listSuperType.kt")
public void testListSuperType() throws Exception {
@@ -22366,6 +22390,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
@TestMetadata("compiler/testData/diagnostics/tests/properties")
@TestDataPath("$PROJECT_ROOT")
public class Properties {
@Test
@TestMetadata("abstarctPropertyInPrimaryConstructor.kt")
public void testAbstarctPropertyInPrimaryConstructor() throws Exception {
runTest("compiler/testData/diagnostics/tests/properties/abstarctPropertyInPrimaryConstructor.kt");
}
@Test
public void testAllFilesPresentInProperties() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
@@ -22799,6 +22829,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
}
@Test
@TestMetadata("RedeclaredValueParameters.kt")
public void testRedeclaredValueParameters() throws Exception {
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValueParameters.kt");
}
@Test
@TestMetadata("RedeclaringPrivateToFile.kt")
public void testRedeclaringPrivateToFile() throws Exception {
@@ -28022,6 +28058,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
}
@Test
@TestMetadata("otherModuleInheritance.kt")
public void testOtherModuleInheritance() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
}
@Test
@TestMetadata("protected.kt")
public void testProtected() throws Exception {

View File

@@ -5908,6 +5908,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
}
@Test
@TestMetadata("lambdaInTryFalsePositive.kt")
public void testLambdaInTryFalsePositive() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/lambdaInTryFalsePositive.kt");
}
@Test
@TestMetadata("ReturnFromFunctionInObject.kt")
public void testReturnFromFunctionInObject() throws Exception {
@@ -6013,6 +6019,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("breakToLabel.kt")
public void testBreakToLabel() throws Exception {
runTest("compiler/testData/diagnostics/tests/controlStructures/breakToLabel.kt");
}
@Test
@TestMetadata("catchGenerics.kt")
public void testCatchGenerics() throws Exception {
@@ -16843,6 +16855,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
}
@Test
@TestMetadata("integerNotNullable.kt")
public void testIntegerNotNullable() throws Exception {
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
}
@Test
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
@@ -21688,6 +21706,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
}
@Test
@TestMetadata("kotlinStarProjection.kt")
public void testKotlinStarProjection() throws Exception {
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
}
@Test
@TestMetadata("listSuperType.kt")
public void testListSuperType() throws Exception {
@@ -22366,6 +22390,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
@TestMetadata("compiler/testData/diagnostics/tests/properties")
@TestDataPath("$PROJECT_ROOT")
public class Properties {
@Test
@TestMetadata("abstarctPropertyInPrimaryConstructor.kt")
public void testAbstarctPropertyInPrimaryConstructor() throws Exception {
runTest("compiler/testData/diagnostics/tests/properties/abstarctPropertyInPrimaryConstructor.kt");
}
@Test
public void testAllFilesPresentInProperties() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
@@ -22799,6 +22829,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
}
@Test
@TestMetadata("RedeclaredValueParameters.kt")
public void testRedeclaredValueParameters() throws Exception {
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValueParameters.kt");
}
@Test
@TestMetadata("RedeclaringPrivateToFile.kt")
public void testRedeclaringPrivateToFile() throws Exception {
@@ -28022,6 +28058,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
}
@Test
@TestMetadata("otherModuleInheritance.kt")
public void testOtherModuleInheritance() throws Exception {
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
}
@Test
@TestMetadata("protected.kt")
public void testProtected() throws Exception {

View File

@@ -5,6 +5,7 @@ plugins {
}
dependencies {
implementation(project(":generators"))
implementation(project(":compiler:fir:tree"))
implementation(project(":compiler:fir:tree:tree-generator"))
implementation(project(":compiler:resolution.common"))

View File

@@ -29,6 +29,7 @@ fun main(args: Array<String>) {
alias<FirStatement>("BasicExpressionChecker")
alias<FirQualifiedAccess>("QualifiedAccessChecker")
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
alias<FirCall>("CallChecker")
alias<FirFunctionCall>("FunctionCallChecker")
alias<FirVariableAssignment>("VariableAssignmentChecker")
alias<FirTryExpression>("TryExpressionChecker")

View File

@@ -96,7 +96,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val UNRESOLVED_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<String>("reference")
}
val UNRESOLVED_LABEL by error<PsiElement>()
val UNRESOLVED_LABEL by error<PsiElement>(PositioningStrategy.LABEL)
val DESERIALIZATION_ERROR by error<PsiElement>()
val ERROR_FROM_JAVA_RESOLUTION by error<PsiElement>()
val MISSING_STDLIB_CLASS by error<PsiElement>()
@@ -141,6 +141,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val SUPERTYPES by object : DiagnosticGroup("Supertypes") {
val NOT_A_SUPERTYPE by error<PsiElement>()
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning<KtElement>()
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error<PsiElement>()
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error<KtTypeReference> {
parameter<Symbol>("otherSuperType")
@@ -177,6 +178,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirRegularClassSymbol>("type")
parameter<Collection<ConeKotlinType>>("bounds")
}
val AMBIGUOUS_SUPER by error<KtSuperExpression>()
}
val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
@@ -305,10 +307,22 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<KtModifierKeywordToken>("redundantModifier")
parameter<KtModifierKeywordToken>("conflictingModifier")
}
val DEPRECATED_MODIFIER by warning<PsiElement> {
parameter<KtModifierKeywordToken>("deprecatedModifier")
parameter<KtModifierKeywordToken>("actualModifier")
}
val DEPRECATED_MODIFIER_PAIR by error<PsiElement> {
parameter<KtModifierKeywordToken>("deprecatedModifier")
parameter<KtModifierKeywordToken>("conflictingModifier")
}
val DEPRECATED_MODIFIER_FOR_TARGET by warning<PsiElement> {
parameter<KtModifierKeywordToken>("deprecatedModifier")
parameter<String>("target")
}
val REDUNDANT_MODIFIER_FOR_TARGET by warning<PsiElement> {
parameter<KtModifierKeywordToken>("redundantModifier")
parameter<String>("target")
}
val INCOMPATIBLE_MODIFIERS by error<PsiElement> {
parameter<KtModifierKeywordToken>("modifier1")
parameter<KtModifierKeywordToken>("modifier2")
@@ -325,6 +339,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val INFIX_MODIFIER_REQUIRED by error<PsiElement> {
parameter<FirNamedFunctionSymbol>("functionSymbol")
}
val WRONG_MODIFIER_CONTAINING_DECLARATION by error<PsiElement> {
parameter<KtModifierKeywordToken>("modifier")
parameter<String>("target")
}
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning<PsiElement> {
parameter<KtModifierKeywordToken>("modifier")
parameter<String>("target")
}
val INAPPLICABLE_OPERATOR_MODIFIER by error<PsiElement>(PositioningStrategy.OPERATOR_MODIFIER) {
parameter<String>("message")
}
}
val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") {
@@ -420,6 +445,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val SPREAD_OF_NULLABLE by error<PsiElement>(PositioningStrategy.SPREAD_OPERATOR)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
}
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
@@ -444,7 +472,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val RECURSION_IN_IMPLICIT_TYPES by error<PsiElement>()
val INFERENCE_ERROR by error<PsiElement>()
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error<PsiElement>()
val UPPER_BOUND_VIOLATED by warning<PsiElement> {
val UPPER_BOUND_VIOLATED by error<PsiElement> {
parameter<ConeKotlinType>("expectedUpperBound")
parameter<ConeKotlinType>("actualUpperBound")
}
@@ -553,7 +581,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<ConeKotlinType>("typeB")
}
val TYPE_VARIANCE_CONFLICT by warning<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
val TYPE_VARIANCE_CONFLICT by error<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
parameter<FirTypeParameterSymbol>("typeParameter")
parameter<Variance>("typeParameterVariance")
parameter<Variance>("variance")
@@ -714,7 +742,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val CONFLICTING_OVERLOADS by error<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
parameter<Collection<Symbol>>("conflictingOverloads")
}
val REDECLARATION by error<PsiElement> {
val REDECLARATION by error<KtNamedDeclaration>(PositioningStrategy.NAME_IDENTIFIER) {
parameter<Collection<Symbol>>("conflictingDeclarations")
}
val PACKAGE_OR_CLASSIFIER_REDECLARATION by error<KtNamedDeclaration>(PositioningStrategy.ACTUAL_DECLARATION_NAME) {
parameter<Collection<Symbol>>("conflictingDeclarations")
}
val METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE by error<PsiElement>()
@@ -826,6 +857,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<ConeKotlinType>("actualType")
}
val ACCESSOR_FOR_DELEGATED_PROPERTY by error<KtPropertyAccessor>()
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error<KtModifierListOwner>(PositioningStrategy.ABSTRACT_MODIFIER)
}
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
@@ -1012,6 +1044,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error<KtElement> {
parameter<String>("illegalReason")
}
val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error<PsiElement>(PositioningStrategy.COMMAS)
}
val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") {
@@ -1088,6 +1121,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<ConeKotlinType>("leftType")
parameter<ConeKotlinType>("rightType")
}
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR)
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR) {
parameter<FirNamedFunctionSymbol>("functionSymbol")
parameter<String>("operator")
}
}
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
@@ -1179,11 +1217,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
}
val DECLARATION_CANT_BE_INLINED by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
val OVERRIDE_BY_INLINE by warning<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
val NON_INTERNAL_PUBLISHED_API by error<KtElement>()
val INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE by error<KtElement>() {
parameter<FirExpression>("defaultValue")
parameter<FirValueParameterSymbol>("parameter")
@@ -1231,13 +1269,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
}
val JVM by object : DiagnosticGroup("jvm") {
val JAVA_TYPE_MISMATCH by error<KtExpression> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
}
}
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {

View File

@@ -7,7 +7,9 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.PrivateForInline
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.psi.KtExpression
@Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused")
@OptIn(PrivateForInline::class)
@@ -15,4 +17,11 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val DECLARATIONS by object : DiagnosticGroup("Declarations") {
val CONFLICTING_JVM_DECLARATIONS by error<PsiElement>()
}
val TYPES by object : DiagnosticGroup("Types") {
val JAVA_TYPE_MISMATCH by error<KtExpression> {
parameter<ConeKotlinType>("expectedType")
parameter<ConeKotlinType>("actualType")
}
}
}

View File

@@ -100,6 +100,10 @@ enum class PositioningStrategy(private val strategy: String? = null) {
ACTUAL_DECLARATION_NAME,
UNREACHABLE_CODE,
INLINE_PARAMETER_MODIFIER,
ABSTRACT_MODIFIER,
LABEL,
COMMAS,
OPERATOR_MODIFIER,
;

View File

@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.psi.KtExpression
/*
* This file was generated automatically
@@ -17,4 +19,7 @@ object FirJvmErrors {
// Declarations
val CONFLICTING_JVM_DECLARATIONS by error0<PsiElement>()
// Types
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
}

View File

@@ -5,10 +5,11 @@
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression
import org.jetbrains.kotlin.fir.StandardTypes
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
@@ -109,7 +110,7 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
// actually created because of type projection from `get`. Hence, to workaround this problem, we simply remove all the out
// projection and type capturing and compare the types after such erasure. This way, we won't incorrectly reject any valid code
// though we may accept some invalid code. But in presence of the unsound flexible types, we are allowing invalid code already.
val argTypeWithoutOutProjection = argType.removeOutProjection(true)
val argTypeWithoutOutProjection = argType.removeOutProjection(isCovariant = true)
val lowerBoundWithoutCapturing = context.session.inferenceComponents.approximator.approximateToSuperType(
lowerBound,
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
@@ -121,36 +122,39 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
lowerBoundWithoutCapturing.withNullability(ConeNullability.NULLABLE, typeCtx)
)
) {
reporter.reportOn(arg.source, FirErrors.JAVA_TYPE_MISMATCH, argType, expectedType, context)
reporter.reportOn(arg.source, FirJvmErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
}
}
}
private fun ConeKotlinType.removeOutProjection(positive: Boolean): ConeKotlinType {
private fun ConeKotlinType.removeOutProjection(isCovariant: Boolean): ConeKotlinType {
return when (this) {
is ConeFlexibleType -> ConeFlexibleType(lowerBound.removeOutProjection(positive), upperBound.removeOutProjection(positive))
is ConeFlexibleType -> ConeFlexibleType(
lowerBound.removeOutProjection(isCovariant),
upperBound.removeOutProjection(isCovariant)
)
is ConeCapturedType -> ConeCapturedType(
captureStatus,
lowerType?.removeOutProjection(positive),
lowerType?.removeOutProjection(isCovariant),
nullability,
constructor.apply {
ConeCapturedTypeConstructor(
projection.removeOutProjection(positive),
supertypes?.map { it.removeOutProjection(positive) },
projection.removeOutProjection(isCovariant),
supertypes?.map { it.removeOutProjection(isCovariant) },
typeParameterMarker
)
},
attributes,
isProjectionNotNull
)
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(positive))
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(isCovariant))
is ConeIntersectionType -> ConeIntersectionType(
intersectedTypes.map { it.removeOutProjection(positive) },
alternativeType?.removeOutProjection(positive)
intersectedTypes.map { it.removeOutProjection(isCovariant) },
alternativeType?.removeOutProjection(isCovariant)
)
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
lookupTag,
typeArguments.map { it.removeOutProjection(positive) }.toTypedArray(),
typeArguments.map { it.removeOutProjection(isCovariant) }.toTypedArray(),
isNullable,
attributes
)
@@ -158,13 +162,20 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
}
}
private fun ConeTypeProjection.removeOutProjection(positive: Boolean): ConeTypeProjection {
/**
* @param isCovariant true if the current context is covariant and false if contravariant.
*
* This function only remove out projections in covariant context.
* 'in' projections are never removed, nor would an out projection in a contravariant context.
*/
private fun ConeTypeProjection.removeOutProjection(isCovariant: Boolean): ConeTypeProjection {
return when (this) {
is ConeKotlinTypeProjectionOut -> if (positive) type else this
is ConeKotlinType -> this.removeOutProjection(true)
is ConeKotlinTypeConflictingProjection -> ConeKotlinTypeConflictingProjection(type.removeOutProjection(true))
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!positive))
is ConeStarProjection -> this
is ConeKotlinTypeProjectionOut -> if (isCovariant) type else this
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!isCovariant))
is ConeStarProjection -> if (isCovariant) StandardTypes.Any else this
// Don't remove nested projections for types at invariant position.
is ConeKotlinTypeConflictingProjection,
is ConeKotlinType -> this
}
}
@@ -180,7 +191,10 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
for (immediateSuperType in subTypeConstructor.supertypes()) {
val immediateSuperTypeConstructor = immediateSuperType.typeConstructor()
if (superTypeConstructor == immediateSuperTypeConstructor) return true
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(immediateSuperTypeConstructor, superTypeConstructor)) return true
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(
immediateSuperTypeConstructor, superTypeConstructor
)
) return true
}
return false
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.jvm.diagnostics
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTING_JVM_DECLARATIONS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_TYPE_MISMATCH
object FirJvmDefaultErrorMessages {
fun installJvmErrorMessages() {
FirDefaultErrorMessages.Companion.MAP.also { map ->
map.put(CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash")
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
}
}
}

View File

@@ -19,6 +19,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
get() = _qualifiedAccessCheckers
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = _qualifiedAccessExpressionCheckers
override val callCheckers: Set<FirCallChecker>
get() = _callCheckers
override val functionCallCheckers: Set<FirFunctionCallChecker>
get() = _functionCallCheckers
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
@@ -73,6 +75,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
private val _callCheckers: MutableSet<FirCallChecker> = mutableSetOf()
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
@@ -104,6 +107,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
_basicExpressionCheckers += checkers.basicExpressionCheckers
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
_qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers
_callCheckers += checkers.callCheckers
_functionCallCheckers += checkers.functionCallCheckers
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
_tryExpressionCheckers += checkers.tryExpressionCheckers

View File

@@ -20,6 +20,7 @@ abstract class ExpressionCheckers {
open val basicExpressionCheckers: Set<FirBasicExpressionChecker> = emptySet()
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
open val callCheckers: Set<FirCallChecker> = emptySet()
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
@@ -49,7 +50,8 @@ abstract class ExpressionCheckers {
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> by lazy { basicExpressionCheckers }
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> by lazy { qualifiedAccessCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allCallCheckers: Set<FirCallChecker> by lazy { callCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> by lazy { whenExpressionCheckers + basicExpressionCheckers }
@@ -58,20 +60,20 @@ abstract class ExpressionCheckers {
@CheckersComponentInternal internal val allLogicExpressionCheckers: Set<FirLogicExpressionChecker> by lazy { logicExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allReturnExpressionCheckers: Set<FirReturnExpressionChecker> by lazy { returnExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allBlockCheckers: Set<FirBlockChecker> by lazy { blockCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allElvisExpressionCheckers: Set<FirElvisExpressionChecker> by lazy { elvisExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allSafeCallExpressionCheckers: Set<FirSafeCallExpressionChecker> by lazy { safeCallExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + callCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> by lazy { resolvedQualifierCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allConstExpressionCheckers: Set<FirConstExpressionChecker> by lazy { constExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allCallableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker> by lazy { callableReferenceAccessCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allThisReceiverExpressionCheckers: Set<FirThisReceiverExpressionChecker> by lazy { thisReceiverExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
@CheckersComponentInternal internal val allWhileLoopCheckers: Set<FirWhileLoopChecker> by lazy { whileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allDoWhileLoopCheckers: Set<FirDoWhileLoopChecker> by lazy { doWhileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers }
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers + callCheckers }
@CheckersComponentInternal internal val allClassReferenceExpressionCheckers: Set<FirClassReferenceExpressionChecker> by lazy { classReferenceExpressionCheckers + basicExpressionCheckers }
}

View File

@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirCall
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
typealias FirBasicExpressionChecker = FirExpressionChecker<FirStatement>
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccess>
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
typealias FirCallChecker = FirExpressionChecker<FirCall>
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>

View File

@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
@@ -71,6 +72,7 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection
@@ -127,7 +129,7 @@ object FirErrors {
// Unresolved
val INVISIBLE_REFERENCE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNRESOLVED_REFERENCE by error1<PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val UNRESOLVED_LABEL by error0<PsiElement>()
val UNRESOLVED_LABEL by error0<PsiElement>(SourceElementPositioningStrategies.LABEL)
val DESERIALIZATION_ERROR by error0<PsiElement>()
val ERROR_FROM_JAVA_RESOLUTION by error0<PsiElement>()
val MISSING_STDLIB_CLASS by error0<PsiElement>()
@@ -151,6 +153,7 @@ object FirErrors {
// Supertypes
val NOT_A_SUPERTYPE by error0<PsiElement>()
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning0<KtElement>()
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error0<PsiElement>()
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error1<KtTypeReference, FirBasedSymbol<*>>()
val SUPERTYPE_INITIALIZED_IN_INTERFACE by error0<KtTypeReference>()
@@ -171,6 +174,7 @@ object FirErrors {
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
val INCONSISTENT_TYPE_PARAMETER_VALUES by error3<KtClass, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>(SourceElementPositioningStrategies.SUPERTYPES_LIST)
val INCONSISTENT_TYPE_PARAMETER_BOUNDS by error3<PsiElement, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>()
val AMBIGUOUS_SUPER by error0<KtSuperExpression>()
// Constructor problems
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -253,12 +257,18 @@ object FirErrors {
val INAPPLICABLE_INFIX_MODIFIER by error0<PsiElement>()
val REPEATED_MODIFIER by error1<PsiElement, KtModifierKeywordToken>()
val REDUNDANT_MODIFIER by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER by warning2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_PAIR by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
val REDUNDANT_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
val INCOMPATIBLE_MODIFIERS by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val REDUNDANT_OPEN_IN_INTERFACE by warning0<KtModifierListOwner>(SourceElementPositioningStrategies.OPEN_MODIFIER)
val WRONG_MODIFIER_TARGET by error2<PsiElement, KtModifierKeywordToken, String>()
val OPERATOR_MODIFIER_REQUIRED by error2<PsiElement, FirNamedFunctionSymbol, String>()
val INFIX_MODIFIER_REQUIRED by error1<PsiElement, FirNamedFunctionSymbol>()
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, KtModifierKeywordToken, String>()
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, KtModifierKeywordToken, String>()
val INAPPLICABLE_OPERATOR_MODIFIER by error1<PsiElement, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
// Inline classes
val INLINE_CLASS_NOT_TOP_LEVEL by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
@@ -298,6 +308,8 @@ object FirErrors {
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
val SPREAD_OF_NULLABLE by error0<PsiElement>(SourceElementPositioningStrategies.SPREAD_OPERATOR)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
// Ambiguity
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -310,7 +322,7 @@ object FirErrors {
val RECURSION_IN_IMPLICIT_TYPES by error0<PsiElement>()
val INFERENCE_ERROR by error0<PsiElement>()
val PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT by error0<PsiElement>()
val UPPER_BOUND_VIOLATED by warning2<PsiElement, ConeKotlinType, ConeKotlinType>()
val UPPER_BOUND_VIOLATED by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION by error2<PsiElement, ConeKotlinType, ConeKotlinType>()
val TYPE_ARGUMENTS_NOT_ALLOWED by error0<PsiElement>()
val WRONG_NUMBER_OF_TYPE_ARGUMENTS by error2<PsiElement, Int, FirRegularClassSymbol>()
@@ -350,7 +362,7 @@ object FirErrors {
val DYNAMIC_UPPER_BOUND by error0<KtTypeReference>()
val INCOMPATIBLE_TYPES by error2<KtElement, ConeKotlinType, ConeKotlinType>()
val INCOMPATIBLE_TYPES_WARNING by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
val TYPE_VARIANCE_CONFLICT by warning4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
val TYPE_VARIANCE_CONFLICT by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
val TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
val SMARTCAST_IMPOSSIBLE by error3<KtExpression, ConeKotlinType, FirExpression, String>()
@@ -394,7 +406,8 @@ object FirErrors {
// Redeclarations
val MANY_COMPANION_OBJECTS by error0<KtObjectDeclaration>(SourceElementPositioningStrategies.COMPANION_OBJECT)
val CONFLICTING_OVERLOADS by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
val REDECLARATION by error1<PsiElement, Collection<FirBasedSymbol<*>>>()
val REDECLARATION by error1<KtNamedDeclaration, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
val PACKAGE_OR_CLASSIFIER_REDECLARATION by error1<KtNamedDeclaration, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME)
val METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE by error0<PsiElement>()
// Invalid local declarations
@@ -457,6 +470,7 @@ object FirErrors {
val WRONG_SETTER_RETURN_TYPE by error0<KtTypeReference>()
val WRONG_GETTER_RETURN_TYPE by error2<KtTypeReference, ConeKotlinType, ConeKotlinType>()
val ACCESSOR_FOR_DELEGATED_PROPERTY by error0<KtPropertyAccessor>()
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0<KtModifierListOwner>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
// Multi-platform projects
val EXPECTED_DECLARATION_WITH_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
@@ -537,6 +551,7 @@ object FirErrors {
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
val ELSE_MISPLACED_IN_WHEN by error0<KtWhenEntry>(SourceElementPositioningStrategies.ELSE_ENTRY)
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error0<PsiElement>(SourceElementPositioningStrategies.COMMAS)
// Context tracking
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
@@ -567,6 +582,8 @@ object FirErrors {
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR)
// Type alias
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
@@ -636,7 +653,4 @@ object FirErrors {
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
// jvm
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
}

View File

@@ -45,6 +45,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
get() = setOf(
FirFunctionNameChecker,
FirFunctionTypeParametersSyntaxChecker,
FirOperatorModifierChecker,
)
override val propertyCheckers: Set<FirPropertyChecker>
@@ -57,6 +58,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirInitializerTypeMismatchChecker,
FirDelegatedPropertyChecker,
FirInlinePropertyChecker,
FirPropertyFromParameterChecker,
)
override val classCheckers: Set<FirClassChecker>

View File

@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker
object CommonExpressionCheckers : ExpressionCheckers() {
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
@@ -29,8 +30,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
get() = setOf(
FirCallableReferenceChecker,
FirSuperNotAvailableChecker,
FirNotASupertypeChecker,
FirSuperReferenceChecker,
FirSuperclassNotAccessibleFromInterfaceChecker,
FirAbstractSuperCallChecker,
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
@@ -45,12 +45,19 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirSuspendCallChecker,
)
override val callCheckers: Set<FirCallChecker>
get() = setOf(
FirNamedVarargChecker,
)
override val functionCallCheckers: Set<FirFunctionCallChecker>
get() = setOf(
FirConventionFunctionCallChecker,
FirDivisionByZeroChecker,
FirConstructorCallChecker,
FirSpreadOfNullableChecker
FirSpreadOfNullableChecker,
FirAssignmentOperatorCallChecker,
FirNamedVarargChecker,
)
override val tryExpressionCheckers: Set<FirTryExpressionChecker>
@@ -69,6 +76,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirExhaustiveWhenChecker,
FirWhenConditionChecker,
FirWhenSubjectChecker,
FirCommaInWhenConditionChecker,
)
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>

View File

@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.types.Variance
@@ -212,10 +213,10 @@ internal object ConeTypeCompatibilityChecker {
val classes = classesOrInterfaces.filter { !it.isInterface }
// Java force single inheritance, so any pair of unrelated classes are incompatible.
if (classes.size >= 2) {
return if (classes.any { it.getHasPredefinedEqualityContract(this) }) {
compatibilityUpperBound
} else {
Compatibility.SOFT_INCOMPATIBLE
return when {
classes.any { it.firClass.classId.packageFqName.startsWith(Name.identifier("java")) } -> Compatibility.SOFT_INCOMPATIBLE
classes.any { it.getHasPredefinedEqualityContract(this) } -> compatibilityUpperBound
else -> Compatibility.SOFT_INCOMPATIBLE
}
}
val finalClass = classes.firstOrNull { it.isFinal } ?: return null

View File

@@ -24,6 +24,8 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.util.OperatorNameConventions
private val compileTimeExtensionFunctions = setOf(Name.identifier("floorDiv"), Name.identifier("mod"))
fun ConeKotlinType.canBeUsedForConstVal(): Boolean = with(lowerBoundIfFlexible()) { isPrimitive || isString || isUnsignedType }
internal fun checkConstantArguments(
@@ -145,6 +147,15 @@ internal fun checkConstantArguments(
checkConstantArguments(exp, session)?.let { return it }
}
}
in compileTimeExtensionFunctions -> {
if (calleeReference !is FirResolvedNamedReference) return ConstantArgumentKind.NOT_CONST
val symbol = calleeReference.resolvedSymbol as? FirCallableSymbol
if (symbol?.callableId?.packageName?.asString() != "kotlin") return ConstantArgumentKind.NOT_CONST
for (exp in (expression as FirCall).arguments.plus(expression.extensionReceiver)) {
checkConstantArguments(exp, session)?.let { return it }
}
}
else -> {
if (expression.arguments.isNotEmpty() || calleeReference !is FirResolvedNamedReference) {
return ConstantArgumentKind.NOT_CONST
@@ -160,8 +171,20 @@ internal fun checkConstantArguments(
}
}
expression is FirQualifiedAccessExpression -> {
val propertySymbol = expressionSymbol as? FirPropertySymbol ?: return ConstantArgumentKind.NOT_CONST
@OptIn(SymbolInternals::class)
val property = propertySymbol.fir
when {
(expressionSymbol as FirPropertySymbol).isLocal || expressionSymbol.callableId.className?.isRoot == false ->
property.name.asString() == "length" -> {
val coneType =
expression.dispatchReceiver.typeRef.coneTypeSafe<ConeKotlinType>() ?: return ConstantArgumentKind.NOT_CONST
val receiverClassId = coneType.lowerBoundIfFlexible().classId
if (receiverClassId == StandardClassIds.String) {
return checkConstantArguments(expression.dispatchReceiver, session)
}
}
propertySymbol.isLocal || propertySymbol.callableId.className?.isRoot == false ->
return ConstantArgumentKind.NOT_CONST
expression.typeRef.coneType.classId == StandardClassIds.KClass ->
return ConstantArgumentKind.NOT_KCLASS_LITERAL
@@ -170,9 +193,7 @@ internal fun checkConstantArguments(
expression.dispatchReceiver is FirThisReceiverExpression ->
return null
}
@OptIn(SymbolInternals::class)
val property = expressionSymbol.fir as? FirProperty
return when (property?.initializer) {
return when (property.initializer) {
is FirConstExpression<*> -> {
if (property.isVal)
ConstantArgumentKind.NOT_CONST_VAL_IN_CONST_EXPRESSION

View File

@@ -142,7 +142,7 @@ interface FirDeclarationPresenter {
appendRepresentation(it.returnTypeRef)
}
fun represent(it: FirProperty) = buildString {
fun represent(it: FirVariable) = buildString {
append('[')
it.receiverTypeRef?.let {
appendRepresentation(it)
@@ -241,7 +241,7 @@ open class FirDeclarationInspector(
declaration is FirSimpleFunction -> collectFunction(presenter.represent(declaration), declaration)
declaration is FirRegularClass -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
declaration is FirTypeAlias -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
declaration is FirProperty -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
declaration is FirVariable -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
}
}

View File

@@ -9,14 +9,18 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.getChild
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
@@ -33,13 +37,12 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.psi.KtModifierList
import org.jetbrains.kotlin.psi.KtParameter.VAL_VAR_TOKEN_SET
import org.jetbrains.kotlin.psi.psiUtil.visibilityModifierType
import org.jetbrains.kotlin.resolve.AnnotationTargetList
import org.jetbrains.kotlin.resolve.AnnotationTargetLists
import org.jetbrains.kotlin.types.AbstractTypeChecker
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
@@ -578,7 +581,11 @@ fun checkTypeMismatch(
rValueType = lValueType
lValueType = tempType
}
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
if (rValueType.isUnit) {
reporter.reportOn(source, FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT, context)
} else {
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
}
}
else -> {
reporter.reportOn(source, FirErrors.ASSIGNMENT_TYPE_MISMATCH, lValueType, rValueType, context)
@@ -671,3 +678,80 @@ fun FirFunctionSymbol<*>.isFunctionForExpectTypeFromCastFeature(): Boolean {
return true
}
fun getActualTargetList(annotated: FirDeclaration): AnnotationTargetList {
fun CallableId.isMember(): Boolean {
return classId != null || isLocal // TODO: Replace with .containingClass (after fixing)
}
return when (annotated) {
is FirRegularClass -> {
AnnotationTargetList(
KotlinTarget.classActualTargets(annotated.classKind, annotated.isInner, annotated.isCompanion, annotated.isLocal)
)
}
is FirEnumEntry -> AnnotationTargetList(
KotlinTarget.classActualTargets(ClassKind.ENUM_ENTRY, annotated.isInner, isCompanionObject = false, isLocalClass = false)
)
is FirProperty -> {
when {
annotated.isLocal ->
if (annotated.source?.kind == FirFakeSourceElementKind.DesugaredComponentFunctionCall) {
TargetLists.T_DESTRUCTURING_DECLARATION
} else {
TargetLists.T_LOCAL_VARIABLE
}
annotated.symbol.callableId.isMember() ->
if (annotated.source?.kind == FirFakeSourceElementKind.PropertyFromParameter) {
TargetLists.T_VALUE_PARAMETER_WITH_VAL
} else {
TargetLists.T_MEMBER_PROPERTY(annotated.hasBackingField, annotated.delegate != null)
}
else ->
TargetLists.T_TOP_LEVEL_PROPERTY(annotated.hasBackingField, annotated.delegate != null)
}
}
is FirValueParameter -> {
when {
annotated.hasValOrVar -> TargetLists.T_VALUE_PARAMETER_WITH_VAL
else -> TargetLists.T_VALUE_PARAMETER_WITHOUT_VAL
}
}
is FirConstructor -> TargetLists.T_CONSTRUCTOR
is FirAnonymousFunction -> {
TargetLists.T_FUNCTION_EXPRESSION
}
is FirSimpleFunction -> {
when {
annotated.isLocal -> TargetLists.T_LOCAL_FUNCTION
annotated.symbol.callableId.isMember() -> TargetLists.T_MEMBER_FUNCTION
else -> TargetLists.T_TOP_LEVEL_FUNCTION
}
}
is FirTypeAlias -> TargetLists.T_TYPEALIAS
is FirPropertyAccessor -> if (annotated.isGetter) TargetLists.T_PROPERTY_GETTER else TargetLists.T_PROPERTY_SETTER
is FirFile -> TargetLists.T_FILE
is FirTypeParameter -> TargetLists.T_TYPE_PARAMETER
is FirAnonymousInitializer -> TargetLists.T_INITIALIZER
is FirAnonymousObject ->
if (annotated.source?.kind == FirFakeSourceElementKind.EnumInitializer) {
AnnotationTargetList(
KotlinTarget.classActualTargets(
ClassKind.ENUM_ENTRY,
isInnerClass = false,
isCompanionObject = false,
isLocalClass = false
)
)
} else {
TargetLists.T_OBJECT_LITERAL
}
// TODO: properly implement those cases
// is KtDestructuringDeclarationEntry -> TargetLists.T_LOCAL_VARIABLE
// is KtDestructuringDeclaration -> TargetLists.T_DESTRUCTURING_DECLARATION
// is KtLambdaExpression -> TargetLists.T_FUNCTION_LITERAL
else -> TargetLists.EMPTY
}
}
private typealias TargetLists = AnnotationTargetLists

Some files were not shown because too many files have changed in this diff Show More