Compare commits

...

143 Commits

Author SHA1 Message Date
Natalia Selezneva
5eefd5ea52 gradle.kts: do not return ErrorScriptDefinition into GradleBuildRootManager
In this case script definition is saved into script info,
but only real script definitions should be cached
In case of null script configurations will be reloaded into cache when scriptdefinitions will be ready
2020-07-07 15:12:42 +03:00
Natalia Selezneva
338d8b8f95 Mark importing as complete in case of some unexpected behavior
For example in case when script contains some errors gradleHome might be null
Then build root should be marked as updated
Also notification should be updated
2020-07-07 14:11:32 +03:00
Igor Yakovlev
12014a33fa Possibly fix flacky test of light classes for decompiled declarations
Tests:
JavaAgainstKotlinBinariesCheckerTestGenerated.testInferenceReturnType_1_8JavaAgainstKotlinBinariesCheckerTestGenerated.testReturnInnerClasses
2020-07-07 14:04:41 +03:00
Roman Golyshev
def33a3b94 KT-39869 Remove redundant performDelayedRefactoringRequests call
- In `ObsoleteExperimentalCoroutinesInspection` it is redundant because
it is performed immediately after the single `bindToFqName` call,
so there is no reason to postpone the refactoring and then immediately
invoke it
- In `ObsoleteKotlinJsPackagesInspection` there are no reason to call
it at all (no refactorings are postponed)
2020-07-07 14:04:41 +03:00
Roman Golyshev
2f9a6b5563 KT-39869 Add inspection for FQN usages of kotlin.browser package
- `kotlin.dom` does not need this because it contains only extensions
- Add test for launching whole project fix; mute it because currently it
does not pass
  - The test fails because in tests `RefJavaManager` tries to create
  `RefJavaFileImpl` for .kt files. It will try to use UAST, but it
  does not work for JS files. In production this is disabled, so no
  problems occur
2020-07-07 14:04:41 +03:00
Roman Golyshev
ce4d3dfee4 KT-39869 Fix review suggestions
- Review: https://jetbrains.team/p/kt/review/1349
2020-07-07 14:04:41 +03:00
Roman Golyshev
7bcad671e8 KT-39869 Add ObsoleteKotlinJsPackagesInspection inspection
- This inspection allows to migrate from `kotlin.dom|kotlin.browser`
to `kotlinx.dom|kotlinx.browser` packages respectively
- This inspection is available from the import statements, and also
from the `Run migrations` action
- ^KT-39869 Fixed
2020-07-07 14:04:40 +03:00
Roman Golyshev
7749d5ed49 KT-39869 Move base classes to separate file 2020-07-07 14:04:40 +03:00
Roman Golyshev
3383b72024 KT-39869 Refactor ObsoleteExperimentalCoroutinesInspection.kt
- We need this to reuse the logic for migration inspections
2020-07-07 14:04:40 +03:00
Toshiaki Kameyama
bfb0b66fcf Move statement up: do not apply to @file annotation
#KT-10790 Fixed
2020-07-07 14:04:40 +03:00
Yaroslav Chernyshev
3989003590 KT-36801 Added forgotten changes for 192 platform
#KT-39989 Fixed
2020-07-07 14:04:40 +03:00
Ivan Kylchik
46ec4a215d [FIR] Fix synthetic property is not var due to Nullable on parameter
Synthetic property is var when it have setter. The latter is set up
in property when its parameter type is equal to getter return type. In
case of using @Nullable, parameter type of setter is not equal to
return type of getter, because the latter is flexible type. So to fix
this verification should occur using not null types

#KT-39076 Fixed
2020-07-07 14:04:40 +03:00
Pavel Punegov
3c7b4c35de Ignore test in Native, see #KT-38859 2020-07-07 14:04:40 +03:00
Ilya Goncharov
0e7744290b [Gradle, JS] Deprecation of frontend plugin
^KT-40048 fixed
2020-07-07 14:04:39 +03:00
Natalia Selezneva
4ecb1e332b Minor: add debug log messages 2020-07-07 14:04:39 +03:00
Natalia Selezneva
c2af77ba69 Load file attributes for last modified files under try-catch
This should avoid exceptions from initialization of GradleBuildRootsManager.EP

EA-232521 Fixed
2020-07-07 14:04:39 +03:00
Ilya Goncharov
024d08e681 [Gradle, JS] Add test on public package json inside archives (jar and klib) 2020-07-07 14:04:39 +03:00
Ilya Goncharov
adace7d684 [Gradle, JS] jsJar dependsOn PublicPackageJsonTask
But package.json included into jar only if public npm dependencies exists
2020-07-07 14:04:38 +03:00
Ilya Goncharov
dd681bf75d [Gradle, JS] Simplify creation of public package json task 2020-07-07 14:04:38 +03:00
Ilya Goncharov
f81e8ebce7 [Gradle, JS] Output file of public package json as var for changing it 2020-07-07 14:04:38 +03:00
Ilya Goncharov
b7071ce5cd [Gradle, JS] Remove duplicate of reporting js compiler statistic 2020-07-07 14:04:38 +03:00
Vladimir Dolzhenko
7016670445 Advance bootstrap to 1.4.20-dev-1680 2020-07-07 14:04:37 +03:00
Vladimir Ilmov
fa260f2ed5 Body elements resolution in KotlinDebuggerCache added / analyzeWithContentAndGetResult
While we trying to find an inlined SourcePosition, the body should be
resolved KotlinPositionManager.getLambdaOrFunIfInside / InlineUtil.isInlinedArgument
to make shure the lambda is an argument for a call.

 #KT-39309 fixed
 #KT-39435 fixed
2020-07-07 14:04:37 +03:00
Dmitriy Novozhilov
1afcf1979e [FIR-TEST] Unmute failing diagnostic tests 2020-07-07 14:04:37 +03:00
Igor Yakovlev
b887b8f717 Change signature does not make doubled refactoring for java usages
Fixed #KT-22170
2020-07-07 14:04:37 +03:00
Dmitry Gridin
b51e7475a8 Rename KotlinLikeLangLineIndentProvider to KotlinLangLineIndentProvider
Relates to #KT-22211
2020-07-07 14:04:37 +03:00
Dmitry Petrov
17689efcd3 Minor: mute failing test 2020-07-07 14:04:37 +03:00
Mikhail Zarechenskiy
cb65fc32d3 Add test for obsolete issue
#KT-39588 Obsolete
2020-07-07 14:04:36 +03:00
Vladimir Dolzhenko
4535420994 Add dispatchAllInvocationEvents to editor actions in perf tests 2020-07-07 14:04:36 +03:00
Vladimir Dolzhenko
91620d3479 Regenerate TypingIndentationTestBaseGenerated 2020-07-07 14:04:36 +03:00
Vladimir Krivosheev
154daf58e6 Explicitly specify id of KotlinNonJvmSourceRootConverterProvider
IDEA 2020.3 uses `id` from extension definition to avoid creating instance of converter without need.
2020-07-07 14:04:36 +03:00
Vyacheslav Karpukhin
c581deea5a Created bunch 203 2020-07-07 14:04:36 +03:00
Vladimir Dolzhenko
5f5dbb24eb Do not force FULL analysis for PARTIAL_FOR_COMPLETION for the current open file
Relates to #KT-38687
2020-07-07 14:04:36 +03:00
Vladimir Dolzhenko
d6ad089df1 PluginStartupListener clean up
Relates to #KT-39968
2020-07-07 14:04:35 +03:00
Vladimir Dolzhenko
e8444fbc98 PluginStartupListener clean up
Relates to #KT-39968
2020-07-07 14:04:35 +03:00
Mikhail Zarechenskiy
a1fd539263 Fix test data about JsExport
It allows only for top-level declarations, plus JsName is needed to
 avoid error about method redeclaration
2020-07-07 14:04:35 +03:00
Mikhail Zarechenskiy
1b083df976 Fix redundant semicolon inspection before soft keywords
Fixes few tests:
 - RedundantSemicolon.testBetweenSoftModifierKeywordAndDeclaration
 - RedundantSemicolon.testBetweenSoftModifierKeywordAndDeclaration2
 - RedundantSemicolon.testBetweenSoftModifierKeywordAndDeclaration3

 This bug was introduced in 741ebeb7b8
2020-07-07 14:04:35 +03:00
Mikhail Zarechenskiy
1a9e9d7913 Update test data: add correct error 2020-07-07 14:04:35 +03:00
Nikolay Krasko
1f9075d654 202: Overcome failure in PathManager.getHomePath() because of the wrong dir
Stacktrace:

java.lang.RuntimeException: Could not find installation home path. Please reinstall the software.
  at com.intellij.openapi.application.PathManager.getHomePath(PathManager.java:106)
  at com.intellij.openapi.application.PathManager.getHomePath(PathManager.java:76)
  at com.intellij.openapi.application.PathManager.getPreInstalledPluginsPath(PathManager.java:248)
  at com.intellij.ide.plugins.DescriptorListLoadingContext.<init>(DescriptorListLoadingContext.java:57)
  at com.intellij.ide.plugins.DescriptorListLoadingContext.createSingleDescriptorContext(DescriptorListLoadingContext.java:61)
  at com.intellij.ide.plugins.PluginManagerCore.registerExtensionPointAndExtensions(PluginManagerCore.java:1397)
  at com.intellij.core.CoreApplicationEnvironment.registerExtensionPointAndExtensions(CoreApplicationEnvironment.java:266)
  at org.jetbrains.kotlin.cli.jvm.compiler.CoreApplicationEnvironmentCompatKt.registerExtensionPointAndExtensionsEx(coreApplicationEnvironmentCompat.kt:17)
  at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.registerApplicationExtensionPointsAndExtensionsFrom(KotlinCoreEnvironment.kt:534)
  at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.createApplicationEnvironment(KotlinCoreEnvironment.kt:505)
  at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.getOrCreateApplicationEnvironmentForProduction(KotlinCoreEnvironment.kt:465)
  at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:92)
  at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:52)
  at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:88)
  at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44)
  at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98)
  at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:76)
  at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:45)
  at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit(CLITool.kt:227)
  at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit$default(CLITool.kt:225)
  at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMain(CLITool.kt:214)
  at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler$Companion.main(K2JVMCompiler.kt:262)
  at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.main(K2JVMCompiler.kt)
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:498)
  at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:63)
2020-07-07 14:04:35 +03:00
Dmitriy Dolovov
a742923485 [Commonizer] Use 'index:Int' instead of Name for addressing type parameters 2020-07-07 14:04:35 +03:00
Mikhail Zarechenskiy
7d93243ff6 Fix coercion to Unit when variable already have other constraints
Don't add `Unit` if variable has an upper constraint T <: A.

 It's impossible to coerce variable T to Unit as constraint system will
 be always contradictory: T := Unit => Unit should be subtype of A

 #KT-39900 Fixed
2020-07-07 14:04:34 +03:00
Dmitry Petrov
680477ef64 Fix Kapt3 tests
Nullability annotations are no longer generated on private fields,
so line numbers in generated java sources changed.
2020-07-07 14:04:34 +03:00
Dmitry Petrov
286539dafa JVM_IR: fix property reference generation for inline class primary val 2020-07-07 14:04:34 +03:00
Vladimir Dolzhenko
515c10aa08 Fix KOTLIN_BUNDLED registration
#KT-39968 Fixed
2020-07-07 14:04:34 +03:00
Dmitry Gridin
53bb6705d8 KotlinOptimizeImportsRefactoringHelper: should remove unused directives by pointer
#KT-39899 Fixed
#EA-209827 Fixed
2020-07-07 14:04:34 +03:00
Dmitry Gridin
d1846e1930 Inline refactoring: should support set/get operator
#KT-17378 Fixed
2020-07-07 14:04:34 +03:00
Toshiaki Kameyama
2babd326d7 ReplaceWith: suggest to replace for 'get/set' operator functions
#KT-15944 Fixed
2020-07-07 14:04:33 +03:00
Dmitriy Novozhilov
4692fd97e4 [FIR-TEST] Add test for KT-39075 2020-07-07 14:04:33 +03:00
Dmitriy Novozhilov
0accf4d99f [FIR] Rename FirElvisCall to FirElvisExpression
FirElvisCall is not a FirCall, so FirElvisExpression is more
  convenient name
2020-07-07 14:04:32 +03:00
Dmitriy Novozhilov
c197029ded [FIR] Don't pass flow from inplace lambdas throw when and elvis expressions
#KT-39080 Fixed
2020-07-07 14:04:32 +03:00
Dmitriy Novozhilov
70f525efe3 [FIR] Fix CCE in postponed lambda resolution 2020-07-07 14:04:32 +03:00
Dmitriy Novozhilov
fafff874de [FIR] Fix projection of Comparable supertype for ILT
#KT-39048 Fixed
2020-07-07 14:04:32 +03:00
Dmitriy Novozhilov
888a12e93f [FIR] Create scope for type parameter as scope for intersection of bounds
Before change we've created composite scope for all bounds, which
  is incorrect, because intersection of all bounds may be less than
  all bounds (see test in commit)

#KT-39032 Fixed
2020-07-07 14:04:32 +03:00
Jinseong Jeon
ff6d0f6060 FIR2IR: handle 'this' as reference to outer object 2020-07-07 14:04:32 +03:00
Ilya Muradyan
9363e0e821 Fix and enable embedded tests in scripting-ide-services 2020-07-07 14:04:31 +03:00
Ilya Muradyan
c80ef2fd25 Fix jar-dependent test in scripting-ide-services 2020-07-07 14:04:31 +03:00
Mikhail Zarechenskiy
1372eb4b4a Add compatibility resolve when variable has "bad" intersection type
#KT-39468 Fixed
2020-07-07 14:04:31 +03:00
Ivan Kylchik
eb2f70448e [FIR] Add illegal underscore check in BaseFirBuilder 2020-07-07 14:04:31 +03:00
Ivan Kylchik
ef75a16c9c [FIR] Add illegal underscore diagnostic 2020-07-07 14:04:31 +03:00
Ivan Kylchik
134c51995a Extract illegal underscore check function to ParseUtils 2020-07-07 14:04:31 +03:00
Ivan Kylchik
93fde7a9da [FIR] Fix some of fir spec tests for real-literals
#KT-38336 Fixed
2020-07-07 14:04:30 +03:00
Dmitry Petrov
96dc674891 JVM, JVM_IR: update bytecode listing testData for inline classes 2020-07-07 14:04:30 +03:00
Dmitry Petrov
433f52d547 JVM: no nullability annotations for inline class '-impl' methods
Specialized generated methods for inline classes (toString-impl,
hashCode-impl, equals-impl, etc) are inaccessible from Java, and thus
don't require nullability annotations.
2020-07-07 14:04:30 +03:00
Dmitry Petrov
16f4eed8b5 JVM_IR: no nullability annotations for inline class '-impl' methods
Specialized generated methods for inline classes (toString-impl,
hashCode-impl, equals-impl, etc) are inaccessible from Java, and thus
don't require nullability annotations.
2020-07-07 14:04:30 +03:00
Dmitry Petrov
c2a1023ceb JVM_IR: no annotations on parameters of 'property$annotations' methods 2020-07-07 14:04:30 +03:00
Dmitry Petrov
85b144b812 JVM_IR: Mangle primary val getter of inline class if required
TODO fix reflection
2020-07-07 14:04:30 +03:00
Dmitry Petrov
287b7f654c JVM_IR: Don't generate annotations on generated inline class members 2020-07-07 14:04:30 +03:00
Dmitry Petrov
3c23ab8698 JVM_IR: Don't mangle internal constructor-impl for inline classes 2020-07-07 14:04:29 +03:00
Ilya Kirillov
a8fb925712 FIR IDE: introduce symbol pointers for restoring symbols in another read action
fix pointer
2020-07-07 14:04:29 +03:00
Ilya Kirillov
aaf6d939ec FIR IDE: move types to its own package 2020-07-07 14:04:29 +03:00
Ilya Kirillov
d520fe6c79 FIR IDE: add creating stdlib symbols by fqName tests 2020-07-07 14:04:29 +03:00
Ilya Kirillov
d5c9197021 FIR IDE: introduce symbol modality 2020-07-07 14:04:29 +03:00
Ilya Kirillov
b3949ee309 FIR IDE: add info about varargs to parmater symbol 2020-07-07 14:04:29 +03:00
Ilya Kirillov
d9dad3c7ee FIR IDE: introduce package symbol 2020-07-07 14:04:29 +03:00
Ilya Kirillov
ca9983d813 FIR IDE: add identity weak map based cache for KtSymbolByFirBuilder 2020-07-07 14:04:28 +03:00
Ilya Kirillov
45007a3e27 FIR IDE: rename Invalidatable -> ValidityOwner 2020-07-07 14:04:28 +03:00
Ilya Kirillov
75f41f2afa FIR IDE: rename reference classes to KtFir*Reference for consistency 2020-07-07 14:04:28 +03:00
Ilya Kirillov
25ba0b26d7 FIR IDE: use withValidityAssertion instead of explicit check in FirAnalysisSession 2020-07-07 14:04:28 +03:00
Ilya Kirillov
aebc787f27 FIR IDE: introduce KtType 2020-07-07 14:04:27 +03:00
Ilya Kirillov
d3b1f81e70 FIR IDE: add tests for building kt symbols by PSI 2020-07-07 14:04:27 +03:00
Ilya Kirillov
6381261693 FIR IDE: introduce symbol provider 2020-07-07 14:04:27 +03:00
Ilya Kirillov
e4f76cbdec FIR IDE: use symbols for reference resolve 2020-07-07 14:04:26 +03:00
Ilya Kirillov
72bddeeca0 FIR IDE: use symbols for call resolve 2020-07-07 14:04:26 +03:00
Ilya Kirillov
0f7b5a05e9 FIR IDE: introduce symbol API 2020-07-07 14:04:26 +03:00
Alexander Udalov
26a5066958 Report warning on characters which can cause problems on Windows
As soon as we fix KT-17438, this warning will be turned into an error.
2020-07-07 14:04:26 +03:00
Alexander Udalov
0bc92b31fc IR: inline namedIrModulePhase and namedIrFilePhase phase builders
Construct NamedCompilerPhase directly instead. Only use phase builders
where the code becomes easier to read.
2020-07-07 14:04:26 +03:00
Alexander Udalov
f22d478094 IR: refactor performByIrFile a little
Take a list of phases instead of the CompositePhase, to make stacktraces
nicer and avoid quadratic time of phase construction.
2020-07-07 14:04:26 +03:00
Alexander Udalov
aaba87e962 IR: refactor PhaseBuilders a little
- use named classes to improve stacktraces
- reorder parameters to make the code shorter
- use explicit types to improve IDE resolve in usages
2020-07-07 14:04:26 +03:00
Alexander Udalov
4858c152e7 IR: do not use AnyNamedPhase where there is Context parameter 2020-07-07 14:04:25 +03:00
Alexander Udalov
83c014856b IR: simplify phaser code a little
- merge NamedCompilerPhase, SameTypeNamedPhaseWrapper,
  AbstractNamedPhaseWrapper and inherit it from SameTypeCompilerPhase
- inline some functions to simplify stacktraces
- reformat and fix inspections
2020-07-07 14:04:25 +03:00
Stanislav Erokhin
ffb2736566 Fix 1.4-M2 ChangeLog.md 2020-07-07 14:04:25 +03:00
Vyacheslav Gerasimov
a79fa49b04 Build: Encode build number in teamcity build url 2020-07-07 14:04:25 +03:00
Vyacheslav Gerasimov
e603889244 Build: Add hacky workaround for retrying PublishToMavenRepository tasks
It's supposed to help with `Caused by: org.apache.http.NoHttpResponseException: api.bintray.com:443 failed to respond`
2020-07-07 14:04:25 +03:00
Dmitriy Dolovov
65a307628f [Commonizer] Clean-up CirTypeSignature usages 2020-07-07 14:04:25 +03:00
Dmitriy Dolovov
37a0799bf1 [Commonizer] Use ClassId instead of FqName for addressing classes and TAs 2020-07-07 14:04:25 +03:00
Ilya Kirillov
730478a717 FIR IDE: migrate to 201 2020-07-07 14:04:24 +03:00
Mads Ager
64b6a8feef [JVM_IR] Fix stepping behavior for assignments to local variables. 2020-07-07 14:04:24 +03:00
Vladimir Dolzhenko
bd5171ad07 Turn off stability check for PerformanceTypingIndentationTest 2020-07-07 14:04:24 +03:00
Igor Yakovlev
6f1ad9910a Improve incremental analisys for nested blocks 2020-07-07 14:04:24 +03:00
Toshiaki Kameyama
73dc4d7e3a Introduce "Add '== true'" quick fix for TYPE_MISMATCH
#KT-39930 Fixed
2020-07-07 14:04:24 +03:00
Dmitriy Novozhilov
a30fd7c38c Advance bootstrap to 1.4.20-dev-1530 2020-07-07 14:04:24 +03:00
Natalia Selezneva
e1f3ea9431 Optimize KotlinScriptDependenciesClassFinder
Do not call processDirectories for all package prefixes checking inner classes

^KT-39796 Fixed
2020-07-07 14:04:24 +03:00
Mikhail Glukhikh
ca82618caa [FIR2IR] Simplify elvis conversion 2020-07-07 14:04:23 +03:00
Mikhail Glukhikh
b9de6f4b99 [FIR2IR] Simplify generateWhen 2020-07-07 14:04:23 +03:00
Mikhail Glukhikh
166b934ac1 [FIR2IR] Don't build stub FirWhen for converting elvis expression 2020-07-07 14:04:23 +03:00
Mikhail Glukhikh
03f9fda68c [FIR2IR] Extract generateWhen & toIrWhenBranch 2020-07-07 14:04:23 +03:00
Mikhail Glukhikh
00e4f37051 [FIR2IR] Move visitElvis & visitWhen close to one another 2020-07-07 14:04:23 +03:00
Dmitriy Novozhilov
b8b65a3eb0 [FIR-TEST] Mute BB test due to KT-39659 2020-07-07 14:04:23 +03:00
Dmitriy Novozhilov
61318dfbd7 [FIR] Add conversion of FirElvisCall to backend IR 2020-07-07 14:04:23 +03:00
Dmitriy Novozhilov
fded49cddc [FIR] Resolve elvis call as special synthetic call
Before that commit we desugared `a ?: b` as

when (val elvis = a) {
    null -> b
    else -> elvis
}

It was incorrect, because `a` should be resolved in dependent mode,
  but when it was `elvis` initializer it was resolved in independent
  mode, so we can't infer type for `a` in some complex cases
2020-07-07 14:04:22 +03:00
Dmitriy Novozhilov
79d4473d6a [FIR] Add special node for elvis call
#KT-39074
2020-07-07 14:04:22 +03:00
Dmitriy Novozhilov
5bc8fdd0fe [FIR] Replace kotlin/Throwable with java/lang/Throwable in JvmMappedScope
#KT-39044 Fixed
2020-07-07 14:04:22 +03:00
Dmitriy Novozhilov
4fde411585 [FIR] Resolve LHS of type operator call in independent context
#KT-39046 Fixed
2020-07-07 14:04:22 +03:00
Jinseong Jeon
b5c5e84fe9 FIR deserializer: fix parameter shift for constructor of inner classes and enums
#KT-39837 Fixed
2020-07-07 14:04:22 +03:00
Georgy Bronnikov
ecf93b5b4d JVM_IR: avoid descriptors when tracking inline properties
Preparing to use wrapped properties in InlineCodegen.
2020-07-07 14:04:22 +03:00
Georgy Bronnikov
b6774aa033 JVM_IR: do not use descriptor in isCompiledToJvmDefault 2020-07-07 14:04:22 +03:00
Vsevolod Tolstopyatov
812cbc0837 Introduce CancellationException
#KT-39126 Fixed
2020-07-07 14:04:21 +03:00
Natalia Selezneva
71a38c2438 *.gradle.kts: catch exceptions during GradleBuildRootManager initialization
^KT-39317 Fixed
2020-07-07 14:04:21 +03:00
Natalia Selezneva
af2a860976 *.gradle.kts: get java home from build environment instead of execution settings
Note that getting GradleExecutionSettings may lead to write action
because it link javaHome with existing sdks

^KT-39317
2020-07-07 14:04:21 +03:00
Steven Schäfer
d9bf0c1824 Coroutines: Fix RedundantLocalsEliminationMethodTransformer
- Take control flow into account when collecting usage information
- Don't remove stores to local variables
2020-07-07 14:04:21 +03:00
Alexander Gorshenev
36adc4692f Adapted fake override checker to inheritance from friend module internal interfaces 2020-07-07 14:04:21 +03:00
Mikhail Glukhikh
0927bde340 Fix exception in FirExposedVisibilityChecker 2020-07-07 14:04:20 +03:00
Ilmir Usmanov
f7afae7642 For all int-like typed variables, use int as field type and coerce
it during spill-unspill.
Coerce int to boolean, otherwise, VerifyError is thrown on android
Completely rewrite SpilledVariableFieldTypesAnalysis... again,
but this time use BasicInterpreter
This way, the analysis both does not use SourceInterpreter and
is in line with the rest on analyses.
2020-07-07 14:04:20 +03:00
Alexander Udalov
45f7d8a98a IR: do not inherit IrFunctionReference from IrFunctionAccessExpression
To avoid the diamond hierarchy and to allow refactoring the IR element
hierarchy from interfaces to classes, improving performance of visitors
and transformers.
2020-07-07 14:04:20 +03:00
Alexander Udalov
d2a7589aec IR: add type parameter to IrMemberAccessExpression and some subclasses
This is needed to get rid of the diamond hierarchy:

                 IrMemberAccessExpression
                 /                       \
                /                         \
IrFunctionAccessExpression     IrCallableReference
                \                      /
                 \                    /
                   IrFunctionReference

In the subsequent commit, IrFunctionReference no longer inherits from
IrFunctionAccessExpression; the more precise type of `val symbol:
IrFunctionSymbol` is now carried via the generic type argument.

This will help to refactor IR element hierarchy from interfaces to
classes, improving performance of visitors and transformers.
2020-07-07 14:04:20 +03:00
Alexander Udalov
9ecf80ee00 IR: remove non-supertype usages of abstract impl classes
Work with the corresponding base interfaces instead. This change will
help in moving the IR element hierarchy from interfaces to classes,
should the need arise.

There's a possible change in behavior in
`CallAndReferenceGenerator.applyCallArguments`, which however doesn't
seem to break anything: IrPropertyReferenceImpl can now also be handled
by this method.
2020-07-07 14:04:19 +03:00
Alexander Udalov
2bebc59e4e IR: make mapOptimized non-inline, rename to transformIfNeeded
This seems to have no effect on performance, however it clearly shows
that this method is a hotspot now with regard to own CPU samples.
Furthermore, it somewhat decreases the bytecode size at call sites and
might actually allow the HotSpot to inline those methods earlier and
hopefully deoptimize less frequently.
2020-07-07 14:04:19 +03:00
Alexander Udalov
d1e9f1d8f2 IR: minor, remove accept from some interfaces 2020-07-07 14:04:19 +03:00
Jinseong Jeon
62e4f8f45f FIR2IR: discard fake overrides for property accessors according to base visibility 2020-07-07 14:04:19 +03:00
Nikita Bobko
fff1d42df1 202: Fix KotlinJpsBuildTest tests
Test failure was caused by "replace custom source root types to a special
'unknown' type and back on plugin unload/load (IDEA-235292)" in intellij.

We override `getModuleSourceRootPropertiesSerializers` in `KotlinModelSerializerService`
by inheriting from `KotlinCommonJpsModelSerializerExtension`
2020-07-07 14:04:19 +03:00
Nikita Bobko
63f2ad20b4 Refactoring: mark const strings with const keyword 2020-07-07 14:04:19 +03:00
Nikita Bobko
b62e4676ff 202: Fix some ParameterInfoTestGenerated
Speaking strictly:
* `ParameterInfoTestGenerated$WithLib1.testUseJavaFromLib`
* `ParameterInfoTestGenerated$WithLib2.testUseJavaSAMFromLib`
* `ParameterInfoTestGenerated$WithLib3.testUseJavaSAMFromLib`
2020-07-07 14:04:19 +03:00
Nikita Bobko
f73a5b439d 202: Fix SlicerLeafGroupingTestGenerated tests 2020-07-07 14:04:18 +03:00
Nikolay Krasko
07eab06997 202: Add fastutil jar to tests dependencies 2020-07-07 14:04:18 +03:00
Nikolay Krasko
b37b7f96b7 202: Disable ignored plugins check in compiler environment
Stacktrace:

java.lang.NullPointerException
  	at java.io.Reader.<init>(Reader.java:78)
  	at java.io.InputStreamReader.<init>(InputStreamReader.java:113)
  	at com.intellij.ide.plugins.PluginManagerCore.getBrokenPluginVersions(PluginManagerCore.java:207)
  	at com.intellij.ide.plugins.PluginManagerCore.createLoadingResult(PluginManagerCore.java:825)
  	at com.intellij.ide.plugins.DescriptorListLoadingContext.createSingleDescriptorContext(DescriptorListLoadingContext.java:61)
  	at com.intellij.ide.plugins.PluginManagerCore.registerExtensionPointAndExtensions(PluginManagerCore.java:1397)
  	at com.intellij.core.CoreApplicationEnvironment.registerExtensionPointAndExtensions(CoreApplicationEnvironment.java:266)
  	at org.jetbrains.kotlin.cli.jvm.compiler.CoreApplicationEnvironmentCompatKt.registerExtensionPointAndExtensionsEx(coreApplicationEnvironmentCompat.kt:17)
  	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.registerApplicationExtensionPointsAndExtensionsFrom(KotlinCoreEnvironment.kt:534)
  	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.createApplicationEnvironment(KotlinCoreEnvironment.kt:505)
  	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.getOrCreateApplicationEnvironmentForProduction(KotlinCoreEnvironment.kt:465)
  	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:92)
  	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:52)
  	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:88)
  	at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44)
  	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98)
  	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:76)
  	at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:45)
  	at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit(CLITool.kt:227)
  	at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMainNoExit$default(CLITool.kt:225)
  	at org.jetbrains.kotlin.cli.common.CLITool$Companion.doMain(CLITool.kt:214)
  	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler$Companion.main(K2JVMCompiler.kt:262)
  	at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.main(K2JVMCompiler.kt)
2020-07-07 14:04:18 +03:00
Nikita Bobko
c343aa77e6 202: Fix MultiFileJvmBasicCompletionTestGenerated
It was broken by 4bef803e1b5994e9ea9731acfb5095a94b1b1383 in intellij
2020-07-07 14:04:18 +03:00
Nikita Bobko
14275ebb02 202: Fix KotlinMavenImporterTest#testJDKImport test
Test failure was caused by 8e1ab882641db695e3b70085d14a59e1e8e9f579 +
b79ca6e3a855b9d74dba129583d7ed25ecd2f552 in intellij
2020-07-07 14:04:18 +03:00
Nikita Bobko
860331c65b 202: Fix GradleFacetImportTest#testJDKImport test
Test failure was caused by 8e1ab882641db695e3b70085d14a59e1e8e9f579 +
b79ca6e3a855b9d74dba129583d7ed25ecd2f552 in intellij
2020-07-07 14:04:18 +03:00
Nikita Bobko
ce6e34ab32 202: Fix KotlinEvaluateExpressionTestGenerated.SingleBreakpoint
Now `getTreeEvaluation` returns `CompletableFuture<PsiElement>` not `PsiElement` as it was in 201
2020-07-07 14:04:18 +03:00
Nikita Bobko
4ac9131589 202: Fix "Module 'foo': No SDK defined" in tests
Fixes several tests in 202:
* NewMultiplatformProjectImportingTest
* KaptImportingTest
* ...

This failure was caused by b79ca6e3a855b9d74dba129583d7ed25ecd2f552 in intellij
2020-07-07 14:04:17 +03:00
Nikita Bobko
fa2c319f1e 202: Fix missing formatting in nJ2K tests
Formatting in nJ2K tests (actually it still works in IDE) was broken by
dee00ac38946b8a8a5165dffd083e67c85935723 in intellij
2020-07-07 14:04:17 +03:00
Nikita Bobko
166903dbe6 202: Fix null passed to @NotNull in PomModelImpl
Fixes `AdditionalResolveDescriptorRendererTestGenerated#testAnonymousObjectInClassParameterInitializer`
and others
2020-07-07 14:04:17 +03:00
Vladimir Dolzhenko
223e40eee8 Fixed locking granularity in ScriptDefinitionsManager
#KT-34552 Fixed
#KT-39547 Fixed
2020-07-02 15:39:43 +02:00
637 changed files with 9652 additions and 5431 deletions

1
.bunch
View File

@@ -1,5 +1,6 @@
201
202
203_202
193
192_193
as36_192_193

View File

@@ -100,6 +100,8 @@
- [`KT-38668`](https://youtrack.jetbrains.com/issue/KT-38668) Project with module dependency in KN, build fails with Kotlin 1.3.71 and associated libs but passes with 1.3.61.
- [`KT-38857`](https://youtrack.jetbrains.com/issue/KT-38857) Class versions V1_5 or less must use F_NEW frames.
- [`KT-39113`](https://youtrack.jetbrains.com/issue/KT-39113) "AssertionError: Uninitialized value on stack" with EXACTLY_ONCE contract in non-inline function and lambda destructuring
- [`KT-28483`](https://youtrack.jetbrains.com/issue/KT-28483) Override of generic-return-typed function with inline class should lead to a boxing
- [`KT-37963`](https://youtrack.jetbrains.com/issue/KT-37963) ClassCastException: Value of inline class represented as 'java.lang.Object' is not boxed properly on return from lambda
### Docs & Examples
@@ -325,6 +327,7 @@
- [`KT-38579`](https://youtrack.jetbrains.com/issue/KT-38579) New Project wizard 1.4+: multiplatform mobile application: build fails on lint task: Configuration with name 'compileClasspath' not found
- [`KT-38929`](https://youtrack.jetbrains.com/issue/KT-38929) New project wizard: update libraries in project template according to kotlin IDE plugin version
- [`KT-38417`](https://youtrack.jetbrains.com/issue/KT-38417) Enable new project wizard by-default
- [`KT-38158`](https://youtrack.jetbrains.com/issue/KT-38158) java.lang.NullPointerException when try to create new project via standard wizard on Mac os
### JS. Tools
@@ -377,6 +380,7 @@
- [`KT-16529`](https://youtrack.jetbrains.com/issue/KT-16529) Names of KProperty's type parameters are inconsistent with ReadOnlyProperty/ReadWriteProperty
- [`KT-36356`](https://youtrack.jetbrains.com/issue/KT-36356) Specify which element Iterable.distinctBy(selector) retains
- [`KT-38060`](https://youtrack.jetbrains.com/issue/KT-38060) runningFold and runningReduce instead of scanReduce
- [`KT-38566`](https://youtrack.jetbrains.com/issue/KT-38566) Kotlin/JS IR: kx.serialization & ktor+JsonFeature: SerializationException: Can't locate argument-less serializer for class
### Reflection

View File

@@ -152,6 +152,7 @@ rootProject.apply {
from(rootProject.file("gradle/jps.gradle.kts"))
from(rootProject.file("gradle/checkArtifacts.gradle.kts"))
from(rootProject.file("gradle/checkCacheability.gradle.kts"))
from(rootProject.file("gradle/retryPublishing.gradle.kts"))
}
IdeVersionConfigurator.setCurrentIde(project)
@@ -650,6 +651,7 @@ tasks {
dependsOn(":kotlin-scripting-jsr223-test:embeddableTest")
dependsOn(":kotlin-main-kts-test:test")
dependsOn(":kotlin-scripting-ide-services-test:test")
dependsOn(":kotlin-scripting-ide-services-test:embeddableTest")
dependsOn(":kotlin-scripting-js-test:test")
}
@@ -1074,4 +1076,4 @@ if (disableVerificationTasks) {
}
}
}
}
}

View File

@@ -33,10 +33,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers;
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.constants.ArrayValue;
@@ -219,7 +216,9 @@ public class FunctionCodegen {
recordMethodForFunctionIfAppropriate(functionDescriptor, asmMethod);
boolean skipNullabilityAnnotations = (flags & ACC_PRIVATE) != 0 || (flags & ACC_SYNTHETIC) != 0;
boolean skipNullabilityAnnotations =
(flags & ACC_PRIVATE) != 0 || (flags & ACC_SYNTHETIC) != 0 ||
InlineClassDescriptorResolver.isSpecializedEqualsMethod(functionDescriptor);
generateMethodAnnotationsIfRequired(
functionDescriptor, asmMethod, jvmSignature, mv,
isCompatibilityStubInDefaultImpls ? Collections.singletonList(Deprecated.class) : Collections.emptyList(),
@@ -533,14 +532,18 @@ public class FunctionCodegen {
? iterator.next()
: kind == JvmMethodParameterKind.RECEIVER
? JvmCodegenUtil.getDirectMember(functionDescriptor).getExtensionReceiverParameter()
: isDefaultImpl && kind == JvmMethodParameterKind.THIS ? JvmCodegenUtil.getDirectMember(functionDescriptor)
.getDispatchReceiverParameter() : null;
: kind == JvmMethodParameterKind.THIS && isDefaultImpl
? JvmCodegenUtil.getDirectMember(functionDescriptor).getDispatchReceiverParameter()
: null;
if (annotated != null) {
//noinspection ConstantConditions
int parameterIndex = i - syntheticParameterCount;
AnnotationCodegen.forParameter(parameterIndex, mv, memberCodegen, state, skipNullabilityAnnotations)
.genAnnotations(annotated, parameterSignature.getAsmType(), annotated.getReturnType(), functionDescriptor, Collections.emptyList());
AnnotationCodegen
.forParameter(parameterIndex, mv, memberCodegen, state, skipNullabilityAnnotations)
.genAnnotations(
annotated, parameterSignature.getAsmType(), annotated.getReturnType(), functionDescriptor,
Collections.emptyList()
);
}
}
}

View File

@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.KtClassOrObject;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
@@ -46,6 +45,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
private final GenerationState generationState;
private final KotlinTypeMapper typeMapper;
private final JvmKotlinType underlyingType;
private final boolean isInErasedInlineClass;
public FunctionsFromAnyGeneratorImpl(
@NotNull KtClassOrObject declaration,
@@ -67,23 +67,27 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
typeMapper.mapType(descriptor),
InlineClassesUtilsKt.substitutedUnderlyingType(descriptor.getDefaultType())
);
this.isInErasedInlineClass = fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS;
}
@Override
protected void generateToStringMethod(
@NotNull FunctionDescriptor function, @NotNull List<? extends PropertyDescriptor> properties
@NotNull FunctionDescriptor function,
@NotNull List<? extends PropertyDescriptor> properties
) {
MethodContext context = fieldOwnerContext.intoFunction(function);
JvmDeclarationOrigin methodOrigin = JvmDeclarationOriginKt.OtherOrigin(function);
String toStringMethodName = mapFunctionName(function);
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), toStringMethodName, getToStringDesc(), null, null);
if (fieldOwnerContext.getContextKind() != OwnerKind.ERASED_INLINE_CLASS && classDescriptor.isInline()) {
if (!isInErasedInlineClass && classDescriptor.isInline()) {
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
return;
}
visitEndForAnnotationVisitor(mv.visitAnnotation(Type.getDescriptor(NotNull.class), false));
if (!isInErasedInlineClass) {
visitEndForAnnotationVisitor(mv.visitAnnotation(Type.getDescriptor(NotNull.class), false));
}
if (!generationState.getClassBuilderMode().generateBodies) {
FunctionCodegen.endVisit(mv, toStringMethodName, getDeclaration());
@@ -144,7 +148,7 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
String hashCodeMethodName = mapFunctionName(function);
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), hashCodeMethodName, getHashCodeDesc(), null, null);
if (fieldOwnerContext.getContextKind() != OwnerKind.ERASED_INLINE_CLASS && classDescriptor.isInline()) {
if (!isInErasedInlineClass && classDescriptor.isInline()) {
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
return;
}
@@ -213,15 +217,14 @@ public class FunctionsFromAnyGeneratorImpl extends FunctionsFromAnyGenerator {
String equalsMethodName = mapFunctionName(function);
MethodVisitor mv = v.newMethod(methodOrigin, getAccess(), equalsMethodName, getEqualsDesc(), null, null);
boolean isErasedInlineClassKind = fieldOwnerContext.getContextKind() == OwnerKind.ERASED_INLINE_CLASS;
if (!isErasedInlineClassKind && classDescriptor.isInline()) {
if (!isInErasedInlineClass && classDescriptor.isInline()) {
FunctionCodegen.generateMethodInsideInlineClassWrapper(methodOrigin, function, classDescriptor, mv, typeMapper);
return;
}
visitEndForAnnotationVisitor(
mv.visitParameterAnnotation(isErasedInlineClassKind ? 1 : 0, Type.getDescriptor(Nullable.class), false)
);
if (!isInErasedInlineClass) {
visitEndForAnnotationVisitor(mv.visitParameterAnnotation(0, Type.getDescriptor(Nullable.class), false));
}
if (!generationState.getClassBuilderMode().generateBodies) {
FunctionCodegen.endVisit(mv, equalsMethodName, getDeclaration());

View File

@@ -647,7 +647,7 @@ class CoroutineTransformerMethodVisitor(
}
for ((index, basicValue) in variablesToSpill) {
if (basicValue.type == NULL_TYPE) {
if (basicValue == StrictBasicValue.NULL_VALUE) {
postponedActions.add {
with(instructions) {
insert(suspension.tryCatchBlockEndLabelAfterSuspensionCall, withInstructionAdapter {

View File

@@ -1,11 +1,10 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2020 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.coroutines
import org.jetbrains.kotlin.codegen.inline.nodeText
import org.jetbrains.kotlin.codegen.optimization.boxing.isUnitInstance
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
@@ -13,168 +12,136 @@ import org.jetbrains.kotlin.codegen.optimization.common.removeAll
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.tree.*
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
import org.jetbrains.org.objectweb.asm.tree.LabelNode
import org.jetbrains.org.objectweb.asm.tree.MethodNode
import org.jetbrains.org.objectweb.asm.tree.VarInsnNode
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import java.util.*
private class PossibleSpilledValue(val source: AbstractInsnNode, type: Type?) : BasicValue(type) {
val usages = mutableSetOf<AbstractInsnNode>()
override fun toString(): String = when {
source.opcode == Opcodes.ALOAD -> "" + (source as VarInsnNode).`var`
source.isUnitInstance() -> "U"
else -> error("unreachable")
}
override fun equals(other: Any?): Boolean =
other is PossibleSpilledValue && source == other.source
override fun hashCode(): Int = super.hashCode() xor source.hashCode()
}
private object NonSpillableValue : BasicValue(AsmTypes.OBJECT_TYPE) {
override fun equals(other: Any?): Boolean = other is NonSpillableValue
override fun toString(): String = "N"
}
private object ConstructedValue : BasicValue(AsmTypes.OBJECT_TYPE) {
override fun equals(other: Any?): Boolean = other is ConstructedValue
override fun toString(): String = "C"
}
fun BasicValue?.nonspillable(): BasicValue? = if (this?.type?.sort == Type.OBJECT) NonSpillableValue else this
private class RedundantSpillingInterpreter : BasicInterpreter(Opcodes.API_VERSION) {
val possibleSpilledValues = mutableSetOf<PossibleSpilledValue>()
override fun newOperation(insn: AbstractInsnNode): BasicValue? {
if (insn.opcode == Opcodes.NEW) return ConstructedValue
val basicValue = super.newOperation(insn)
return if (insn.isUnitInstance())
// Unit instances come from inlining suspend functions returning Unit.
// They can be spilled before they are eventually popped.
// Track them.
PossibleSpilledValue(insn, basicValue.type).also { possibleSpilledValues += it }
else basicValue.nonspillable()
}
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
when (value) {
is ConstructedValue -> value
is PossibleSpilledValue -> {
value.usages += insn
if (insn.opcode == Opcodes.ALOAD || insn.opcode == Opcodes.ASTORE) value
else value.nonspillable()
}
else -> value?.nonspillable()
}
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out BasicValue?>): BasicValue? {
for (value in values.filterIsInstance<PossibleSpilledValue>()) {
value.usages += insn
}
return super.naryOperation(insn, values)?.nonspillable()
}
override fun merge(v: BasicValue?, w: BasicValue?): BasicValue? =
if (v is PossibleSpilledValue && w is PossibleSpilledValue && v.source == w.source) v
else v?.nonspillable()
}
// Inliner emits a lot of locals during inlining.
// Remove all of them since these locals are
// 1) going to be spilled into continuation object
// 2) breaking tail-call elimination
/**
* This pass removes unused Unit values. These typically occur as a result of inlining and could end up spilling
* into the continuation object or break tail-call elimination.
*
* Concretely, we remove "GETSTATIC kotlin/Unit.INSTANCE" instructions if they are unused, or all uses are either
* POP instructions, or ASTORE instructions to locals which are never read and are not named local variables.
*
* This pass does not touch [suspensionPoints], as later passes rely on the bytecode patterns around suspension points.
*/
internal class RedundantLocalsEliminationMethodTransformer(private val suspensionPoints: List<SuspensionPoint>) : MethodTransformer() {
override fun transform(internalClassName: String, methodNode: MethodNode) {
val interpreter = RedundantSpillingInterpreter()
val frames = MethodAnalyzer<BasicValue>(internalClassName, methodNode, interpreter).analyze()
val interpreter = UnitSourceInterpreter(methodNode.localVariables?.mapTo(mutableSetOf()) { it.index } ?: setOf())
val frames = interpreter.run(internalClassName, methodNode)
// Mark all unused instructions for deletion (except for labels which may be used in debug information)
val toDelete = mutableSetOf<AbstractInsnNode>()
for (spilledValue in interpreter.possibleSpilledValues.filter { it.usages.isNotEmpty() }) {
@Suppress("UNCHECKED_CAST")
val aloads = spilledValue.usages.filter { it.opcode == Opcodes.ALOAD } as List<VarInsnNode>
if (aloads.isEmpty()) continue
val slot = aloads.first().`var`
if (aloads.any { it.`var` != slot }) continue
for (aload in aloads) {
methodNode.instructions.set(aload, spilledValue.source.clone())
}
toDelete.addAll(spilledValue.usages.filter { it.opcode == Opcodes.ASTORE })
toDelete.add(spilledValue.source)
methodNode.instructions.asSequence().zip(frames.asSequence()).mapNotNullTo(toDelete) { (insn, frame) ->
insn.takeIf { frame == null && insn !is LabelNode }
}
for (pop in methodNode.instructions.asSequence().filter { it.opcode == Opcodes.POP }) {
val value = (frames[methodNode.instructions.indexOf(pop)]?.top() as? PossibleSpilledValue) ?: continue
if (value.usages.isEmpty() && value.source !in suspensionPoints) {
toDelete.add(pop)
toDelete.add(value.source)
}
}
// Remove unreachable instructions to simplify further analyses
for (index in frames.indices) {
if (frames[index] == null) {
val insn = methodNode.instructions[index]
if (insn !is LabelNode) {
toDelete.add(insn)
}
// Mark all spillable "GETSTATIC kotlin/Unit.INSTANCE" instructions for deletion
for ((unit, uses) in interpreter.unitUsageInformation) {
if (unit !in interpreter.unspillableUnitValues && unit !in suspensionPoints) {
toDelete += unit
toDelete += uses
}
}
methodNode.instructions.removeAll(toDelete)
}
private fun AbstractInsnNode.clone() = when (this) {
is FieldInsnNode -> FieldInsnNode(opcode, owner, name, desc)
is VarInsnNode -> VarInsnNode(opcode, `var`)
is InsnNode -> InsnNode(opcode)
is TypeInsnNode -> TypeInsnNode(opcode, desc)
else -> error("clone of $this is not implemented yet")
}
}
// Handy debugging routing
@Suppress("unused")
fun MethodNode.nodeTextWithFrames(frames: Array<*>): String {
var insns = nodeText.split("\n")
val first = insns.indexOfLast { it.trim().startsWith("@") } + 1
var last = insns.indexOfFirst { it.trim().startsWith("LOCALVARIABLE") }
if (last < 0) last = insns.size
val prefix = insns.subList(0, first).joinToString(separator = "\n")
val postfix = insns.subList(last, insns.size).joinToString(separator = "\n")
insns = insns.subList(first, last)
if (insns.any { it.contains("TABLESWITCH") }) {
var insideTableSwitch = false
var buffer = ""
val res = arrayListOf<String>()
for (insn in insns) {
if (insn.contains("TABLESWITCH")) {
insideTableSwitch = true
}
if (insideTableSwitch) {
buffer += insn
if (insn.contains("default")) {
insideTableSwitch = false
res += buffer
buffer = ""
continue
}
} else {
res += insn
// A version of SourceValue which inherits from BasicValue and is only used for Unit values.
private class UnitValue(val insns: Set<AbstractInsnNode>) : BasicValue(AsmTypes.OBJECT_TYPE) {
constructor(insn: AbstractInsnNode) : this(Collections.singleton(insn))
override fun equals(other: Any?): Boolean = other is UnitValue && insns == other.insns
override fun hashCode() = Objects.hash(insns)
override fun toString() = "U"
}
// A specialized SourceInterpreter which only keeps track of the use sites for Unit values which are exclusively used as
// arguments to POP and unused ASTORE instructions.
private class UnitSourceInterpreter(private val localVariables: Set<Int>) : BasicInterpreter(Opcodes.API_VERSION) {
// All unit values with visible use-sites.
val unspillableUnitValues = mutableSetOf<AbstractInsnNode>()
// Map from unit values to ASTORE/POP use-sites.
val unitUsageInformation = mutableMapOf<AbstractInsnNode, MutableSet<AbstractInsnNode>>()
private fun markUnspillable(value: BasicValue?) =
value?.safeAs<UnitValue>()?.let { unspillableUnitValues += it.insns }
private fun collectUnitUsage(use: AbstractInsnNode, value: UnitValue) {
for (def in value.insns) {
if (def !in unspillableUnitValues) {
unitUsageInformation.getOrPut(def) { mutableSetOf() } += use
}
}
insns = res
}
return prefix + "\n" + insns.withIndex().joinToString(separator = "\n") { (index, insn) ->
if (index >= frames.size) "N/A\t$insn" else "${frames[index]}\t$insn"
} + "\n" + postfix
fun run(internalClassName: String, methodNode: MethodNode): Array<Frame<BasicValue>?> {
val frames = MethodAnalyzer<BasicValue>(internalClassName, methodNode, this).analyze()
// The ASM analyzer does not visit POP instructions, so we do so here.
for ((insn, frame) in methodNode.instructions.asSequence().zip(frames.asSequence())) {
if (frame != null && insn.opcode == Opcodes.POP) {
val value = frame.top()
value.safeAs<UnitValue>()?.let { collectUnitUsage(insn, it) }
}
}
return frames
}
override fun newOperation(insn: AbstractInsnNode?): BasicValue =
if (insn?.isUnitInstance() == true) UnitValue(insn) else super.newOperation(insn)
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
if (value is UnitValue) {
if (insn is VarInsnNode && insn.opcode == Opcodes.ASTORE && insn.`var` !in localVariables) {
collectUnitUsage(insn, value)
// We track the stored value in case it is subsequently read.
return value
}
unspillableUnitValues += value.insns
}
return super.copyOperation(insn, value)
}
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
markUnspillable(value)
return super.unaryOperation(insn, value)
}
override fun binaryOperation(insn: AbstractInsnNode, value1: BasicValue?, value2: BasicValue?): BasicValue? {
markUnspillable(value1)
markUnspillable(value2)
return super.binaryOperation(insn, value1, value2)
}
override fun ternaryOperation(insn: AbstractInsnNode, value1: BasicValue?, value2: BasicValue?, value3: BasicValue?): BasicValue? {
markUnspillable(value1)
markUnspillable(value2)
markUnspillable(value3)
return super.ternaryOperation(insn, value1, value2, value3)
}
override fun naryOperation(insn: AbstractInsnNode, values: List<BasicValue>?): BasicValue? {
values?.forEach(this::markUnspillable)
return super.naryOperation(insn, values)
}
override fun merge(value1: BasicValue?, value2: BasicValue?): BasicValue? =
if (value1 is UnitValue && value2 is UnitValue) {
UnitValue(value1.insns.union(value2.insns))
} else {
// Mark unit values as unspillable if we merge them with non-unit values here.
// This is conservative since the value could turn out to be unused.
markUnspillable(value1)
markUnspillable(value2)
super.merge(value1, value2)
}
}

View File

@@ -5,365 +5,156 @@
package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.codegen.inline.insnOpcodeText
import org.jetbrains.kotlin.codegen.inline.isFakeLocalVariableForInline
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.optimization.common.MethodAnalyzer
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Opcodes.*
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
import org.jetbrains.org.objectweb.asm.Label
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.*
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
// BasicValue interpreter from ASM does not distinct 'int' types from other int-like types like 'byte' or 'boolean',
// neither do HotSpot and JVM spec.
// But it seems like Dalvik does not follow it, and spilling boolean value into an 'int' field fails with VerifyError on Android 4,
// so this function calculates refined frames' markup.
// Note that type of some values is only possible to determine by their usages (e.g. ICONST_1, BALOAD both may push boolean or byte on stack)
// In this case, update the type of the value.
// In this case, coerce the type of the value.
// StrictBasicValue with mutable type
internal open class SpilledVariableFieldTypeValue(open var type: Type?, val insn: AbstractInsnNode?) : Value {
override fun getSize(): Int = type?.size ?: 1
internal class IloadedValue(val insns: Set<VarInsnNode>) : BasicValue(Type.INT_TYPE)
override fun equals(other: Any?): Boolean = other is SpilledVariableFieldTypeValue && type == other.type && insn == other.insn
private class IntLikeCoerceInterpreter : OptimizationBasicInterpreter() {
val needsToBeCoerced = mutableMapOf<VarInsnNode, Type>()
override fun hashCode(): Int = (type?.hashCode() ?: 0) xor insn.hashCode()
private fun coerce(value: IloadedValue, type: Type) {
for (insn in value.insns) {
needsToBeCoerced[insn] = type
}
}
override fun toString() = if (type == null) "." else "$type"
}
private class MergedSpilledVariableFieldTypeValue(
val values: Set<SpilledVariableFieldTypeValue>
) : SpilledVariableFieldTypeValue(null, null) {
override var type: Type?
get() = values.first().type
set(newType) {
for (value in values) {
value.type = newType
}
override fun copyOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? =
when {
insn.opcode == Opcodes.ILOAD -> IloadedValue(setOf(insn as VarInsnNode))
value == null -> null
else -> BasicValue(value.type)
}
override fun equals(other: Any?): Boolean = other is MergedSpilledVariableFieldTypeValue && other.values == values
override fun hashCode(): Int = values.hashCode()
override fun toString(): String = "M$values"
}
// $i$a and $i$f variables should be ignored in merge operation, since they are not used, but set only
private class FakeInlinerVariableValue(insn: AbstractInsnNode) : SpilledVariableFieldTypeValue(Type.INT_TYPE, insn) {
override fun toString(): String = "@"
}
private operator fun SpilledVariableFieldTypeValue?.plus(other: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? = when {
this == null -> other
other == null -> this
this == other -> this
this is MergedSpilledVariableFieldTypeValue -> {
if (other is MergedSpilledVariableFieldTypeValue) MergedSpilledVariableFieldTypeValue(values + other.values)
else MergedSpilledVariableFieldTypeValue(values + other)
override fun binaryOperation(insn: AbstractInsnNode, v: BasicValue, w: BasicValue): BasicValue? {
if (insn.opcode == Opcodes.PUTFIELD) {
val expectedType = Type.getType((insn as FieldInsnNode).desc)
if (w is IloadedValue && expectedType.isIntLike()) {
coerce(w, expectedType)
}
}
return super.binaryOperation(insn, v, w)
}
other is MergedSpilledVariableFieldTypeValue -> MergedSpilledVariableFieldTypeValue(other.values + this)
else -> MergedSpilledVariableFieldTypeValue(setOf(this, other))
}
internal val NULL_TYPE = Type.getObjectType("null")
override fun unaryOperation(insn: AbstractInsnNode, value: BasicValue?): BasicValue? {
if (insn.opcode == Opcodes.PUTSTATIC) {
val expectedType = Type.getType((insn as FieldInsnNode).desc)
if (value is IloadedValue && expectedType.isIntLike()) {
coerce(value, expectedType)
}
}
return super.unaryOperation(insn, value)
}
// Same as BasicInterpreter, but updates types based on usages
private class SpilledVariableFieldTypesInterpreter(
private val methodNode: MethodNode
) : Interpreter<SpilledVariableFieldTypeValue>(API_VERSION) {
override fun newValue(type: Type?): SpilledVariableFieldTypeValue? =
if (type == Type.VOID_TYPE) null else SpilledVariableFieldTypeValue(type, null)
// INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE,
// MULTIANEWARRAY and INVOKEDYNAMIC
override fun naryOperation(
insn: AbstractInsnNode,
values: MutableList<out SpilledVariableFieldTypeValue?>
): SpilledVariableFieldTypeValue? {
fun updateTypes(argTypes: Array<Type>, withReceiver: Boolean) {
override fun naryOperation(insn: AbstractInsnNode, values: MutableList<out BasicValue?>): BasicValue? {
fun checkTypes(argTypes: Array<Type>, withReceiver: Boolean) {
val offset = if (withReceiver) 1 else 0
for ((index, argType) in argTypes.withIndex()) {
val value = values[index + offset] ?: continue
if (argType.isIntType()) {
value.type = argType
} else if (
(value.type == AsmTypes.OBJECT_TYPE && argType != AsmTypes.OBJECT_TYPE) ||
value.type == NULL_TYPE || value.type == null
) {
value.type = argType
if (argType.isIntLike() && value is IloadedValue) {
coerce(value, argType)
}
}
}
return SpilledVariableFieldTypeValue(
when (insn.opcode) {
MULTIANEWARRAY -> {
Type.getType((insn as MultiANewArrayInsnNode).desc)
}
INVOKEDYNAMIC -> {
updateTypes(Type.getArgumentTypes((insn as InvokeDynamicInsnNode).desc), false)
Type.getReturnType(insn.desc)
}
INVOKESTATIC -> {
updateTypes(Type.getArgumentTypes((insn as MethodInsnNode).desc), false)
Type.getReturnType(insn.desc)
}
INVOKEVIRTUAL, INVOKEINTERFACE, INVOKESPECIAL -> {
updateTypes(Type.getArgumentTypes((insn as MethodInsnNode).desc), true)
Type.getReturnType(insn.desc)
}
else -> {
unreachable(insn)
}
}, insn
)
}
private fun Type.isIntType(): Boolean = when (sort) {
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT, Type.INT -> true
else -> false
}
private fun unreachable(insn: AbstractInsnNode): Nothing = error("Unreachable instruction ${insn.insnOpcodeText}")
// IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE
override fun ternaryOperation(
insn: AbstractInsnNode,
arrayref: SpilledVariableFieldTypeValue?,
index: SpilledVariableFieldTypeValue?,
value: SpilledVariableFieldTypeValue?
): SpilledVariableFieldTypeValue? {
when (insn.opcode) {
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE -> {
// nothing to do
Opcodes.INVOKEDYNAMIC -> {
checkTypes(Type.getArgumentTypes((insn as InvokeDynamicInsnNode).desc), false)
}
BASTORE -> {
value?.type = if (arrayref?.type?.descriptor == "[Z") Type.BOOLEAN_TYPE else Type.BYTE_TYPE
Opcodes.INVOKESTATIC -> {
checkTypes(Type.getArgumentTypes((insn as MethodInsnNode).desc), false)
}
CASTORE -> {
value?.type = Type.CHAR_TYPE
Opcodes.INVOKEVIRTUAL, Opcodes.INVOKEINTERFACE, Opcodes.INVOKESPECIAL -> {
checkTypes(Type.getArgumentTypes((insn as MethodInsnNode).desc), true)
}
SASTORE -> {
value?.type = Type.SHORT_TYPE
}
else -> unreachable(insn)
}
return null
return super.naryOperation(insn, values)
}
override fun merge(v: SpilledVariableFieldTypeValue?, w: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? =
override fun ternaryOperation(insn: AbstractInsnNode, arrayref: BasicValue?, index: BasicValue?, value: BasicValue?): BasicValue? {
when (insn.opcode) {
Opcodes.BASTORE -> {
if (value is IloadedValue) {
val type = if (arrayref?.type?.descriptor == "[Z") Type.BOOLEAN_TYPE else Type.BYTE_TYPE
coerce(value, type)
}
}
Opcodes.CASTORE -> {
if (value is IloadedValue) {
coerce(value, Type.CHAR_TYPE)
}
}
Opcodes.SASTORE -> {
if (value is IloadedValue) {
coerce(value, Type.SHORT_TYPE)
}
}
}
return super.ternaryOperation(insn, arrayref, index, value)
}
override fun merge(v: BasicValue, w: BasicValue): BasicValue =
when {
v is FakeInlinerVariableValue -> w
w is FakeInlinerVariableValue -> v
v?.type?.isIntType() == true && w?.type?.isIntType() == true -> v + w
v != null && v.type == null -> w
w != null && w.type == null -> v
v?.type == w?.type -> v
v?.type?.sort == Type.OBJECT && w?.type?.sort == Type.OBJECT -> {
when {
v.type == AsmTypes.OBJECT_TYPE -> v
w.type == AsmTypes.OBJECT_TYPE -> w
else -> SpilledVariableFieldTypeValue(AsmTypes.OBJECT_TYPE, v.insn)
v is IloadedValue && w is IloadedValue && v.type == w.type -> {
val insns = v.insns + w.insns
insns.find { it in needsToBeCoerced }?.let {
val type = needsToBeCoerced[it]!!
coerce(v, type)
coerce(w, type)
}
IloadedValue(insns)
}
else -> SpilledVariableFieldTypeValue(null, v?.insn ?: w?.insn)
v.type == w.type -> {
if (w is IloadedValue) w else v
}
else -> super.merge(v, w)
}
// IRETURN, LRETURN, FRETURN, DRETURN, ARETURN
override fun returnOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?, expected: SpilledVariableFieldTypeValue?) {
if (insn.opcode == IRETURN) {
value?.type = expected?.type
}
}
// INEG, LNEG, FNEG, DNEG, IINC, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L,
// F2D, D2I, D2L, D2F, I2B, I2C, I2S, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE,
// TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
// PUTSTATIC, GETFIELD, NEWARRAY, ANEWARRAY, ARRAYLENGTH, ATHROW, CHECKCAST,
// INSTANCEOF, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL
override fun unaryOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? =
when (insn.opcode) {
INEG, LNEG, FNEG, DNEG, IINC -> SpilledVariableFieldTypeValue(value?.type, insn)
I2L, F2L, D2L -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
I2F, L2F, D2F -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
L2D, I2D, F2D -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
L2I, F2I, D2I, ARRAYLENGTH -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
I2B -> SpilledVariableFieldTypeValue(Type.BYTE_TYPE, insn)
I2C -> SpilledVariableFieldTypeValue(Type.CHAR_TYPE, insn)
I2S -> SpilledVariableFieldTypeValue(Type.SHORT_TYPE, insn)
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN,
ATHROW, MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL -> null
PUTSTATIC -> {
val expectedType = Type.getType((insn as FieldInsnNode).desc)
if (expectedType.isIntType()) {
value?.type = expectedType
}
null
}
GETFIELD -> SpilledVariableFieldTypeValue(Type.getType((insn as FieldInsnNode).desc), insn)
NEWARRAY -> when ((insn as IntInsnNode).operand) {
T_BOOLEAN -> SpilledVariableFieldTypeValue(Type.getType("[Z"), insn)
T_CHAR -> SpilledVariableFieldTypeValue(Type.getType("[C"), insn)
T_BYTE -> SpilledVariableFieldTypeValue(Type.getType("[B"), insn)
T_SHORT -> SpilledVariableFieldTypeValue(Type.getType("[S"), insn)
T_INT -> SpilledVariableFieldTypeValue(Type.getType("[I"), insn)
T_FLOAT -> SpilledVariableFieldTypeValue(Type.getType("[F"), insn)
T_DOUBLE -> SpilledVariableFieldTypeValue(Type.getType("[D"), insn)
T_LONG -> SpilledVariableFieldTypeValue(Type.getType("[J"), insn)
else -> unreachable(insn)
}
ANEWARRAY -> SpilledVariableFieldTypeValue(Type.getType("[${Type.getObjectType((insn as TypeInsnNode).desc)}"), insn)
CHECKCAST -> SpilledVariableFieldTypeValue(Type.getObjectType((insn as TypeInsnNode).desc), insn)
INSTANCEOF -> SpilledVariableFieldTypeValue(Type.BOOLEAN_TYPE, insn)
else -> unreachable(insn)
}
// IALOAD, LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IADD,
// LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV,
// LDIV, FDIV, DDIV, IREM, LREM, FREM, DREM, ISHL, LSHL, ISHR, LSHR, IUSHR,
// LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, LCMP, FCMPL, FCMPG, DCMPL,
// DCMPG, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
// IF_ACMPEQ, IF_ACMPNE, PUTFIELD
override fun binaryOperation(
insn: AbstractInsnNode,
v: SpilledVariableFieldTypeValue?,
w: SpilledVariableFieldTypeValue?
): SpilledVariableFieldTypeValue? = when (insn.opcode) {
IALOAD, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IAND, IOR, IXOR, LCMP, FCMPL, FCMPG, DCMPL,
DCMPG -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
LALOAD, LADD, LSUB, LMUL, LDIV, LREM, LSHL, LSHR, LUSHR, LAND, LOR, LXOR -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
FALOAD, FADD, FSUB, FMUL, FDIV, FREM -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
DALOAD, DADD, DSUB, DMUL, DDIV, DREM -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
AALOAD -> SpilledVariableFieldTypeValue(AsmTypes.OBJECT_TYPE, insn)
BALOAD -> SpilledVariableFieldTypeValue(if (v?.type?.descriptor == "[Z") Type.BOOLEAN_TYPE else Type.BYTE_TYPE, insn)
CALOAD -> SpilledVariableFieldTypeValue(Type.CHAR_TYPE, insn)
SALOAD -> SpilledVariableFieldTypeValue(Type.SHORT_TYPE, insn)
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> null
PUTFIELD -> {
val expectedType = Type.getType((insn as FieldInsnNode).desc)
if (expectedType.isIntType()) {
w?.type = expectedType
}
null
}
else -> unreachable(insn)
}
// ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
// ASTORE, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2, SWAP
override fun copyOperation(insn: AbstractInsnNode, value: SpilledVariableFieldTypeValue?): SpilledVariableFieldTypeValue? {
return when (insn.opcode) {
// If same ICONST is stored into several slots, thay can have different types
// For example,
// val b: Byte = 1
// val i: Int = b.toInt()
// In this case, `b` and `i` have the same source, but different types.
// The example also shows, that the types should be `I`.
ISTORE -> {
if (value is FakeInlinerVariableValue && insn.previous.opcode == ICONST_0) return value
findLvtRecord((insn as VarInsnNode).`var`, insn)?.let {
if (Type.getType(it.desc) == value?.type) return value
}
var current: AbstractInsnNode? = insn
while (current != null && current !is LabelNode) {
current = current.next
}
while (current is LabelNode) {
findLvtRecord(insn.`var`, current)?.let {
if (Type.getType(it.desc) == value?.type) return value
}
current = current.next
}
if (value?.type == Type.INT_TYPE) return value
SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
}
// Sometimes we cannot get the type from the usage only
// For example,
// val c = '1'
// if (c == '2) ...
// In this case, update the type using information from LVT
ILOAD -> {
if (value is FakeInlinerVariableValue) return SpilledVariableFieldTypeValue(value.type, value.insn)
findLvtRecord((insn as VarInsnNode).`var`, insn)?.let { value?.type = Type.getType(it.desc) }
value
}
else -> value
}
}
private fun findLvtRecord(index: Int, insn: AbstractInsnNode): LocalVariableNode? = methodNode.localVariables.find { local ->
local.index == index &&
methodNode.instructions.indexOf(local.start) <= methodNode.instructions.indexOf(insn) &&
methodNode.instructions.indexOf(insn) < methodNode.instructions.indexOf(local.end)
}
// ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4,
// ICONST_5, LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0,
// DCONST_1, BIPUSH, SIPUSH, LDC, JSR, GETSTATIC, NEW
override fun newOperation(insn: AbstractInsnNode): SpilledVariableFieldTypeValue? {
return when (insn.opcode) {
ICONST_0 -> {
if (insn.next?.opcode == ISTORE) {
// Find out, whether this is fake inliner variable
// Unlike old JVM BE, JVM_IR does not generate them in a specific pattern,
// that we can just recognize.
// So, run instructions until LabelNode and check whether this is, in fact, fake inliner variable
if (findLvtRecord((insn.next as VarInsnNode).`var`, insn.next) != null) {
return SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
}
var current: AbstractInsnNode? = insn.next?.next
while (current != null && current !is LabelNode) {
current = current.next
}
while (current is LabelNode) {
val lvtRecord = findLvtRecord((insn.next as VarInsnNode).`var`, current)
// fake variables do not have LVT entry is they are inside `run` or `apply`
if (lvtRecord == null || isFakeLocalVariableForInline(lvtRecord.name)) {
return FakeInlinerVariableValue(insn)
}
current = current.next
}
}
SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
}
ACONST_NULL -> SpilledVariableFieldTypeValue(NULL_TYPE, insn)
ICONST_M1, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
LCONST_0, LCONST_1 -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
FCONST_0, FCONST_1, FCONST_2 -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
DCONST_0, DCONST_1 -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
BIPUSH -> SpilledVariableFieldTypeValue(Type.BYTE_TYPE, insn)
SIPUSH -> SpilledVariableFieldTypeValue(Type.SHORT_TYPE, insn)
LDC -> when ((insn as LdcInsnNode).cst) {
is Int -> SpilledVariableFieldTypeValue(Type.INT_TYPE, insn)
is Long -> SpilledVariableFieldTypeValue(Type.LONG_TYPE, insn)
is Float -> SpilledVariableFieldTypeValue(Type.FLOAT_TYPE, insn)
is Double -> SpilledVariableFieldTypeValue(Type.DOUBLE_TYPE, insn)
is String -> SpilledVariableFieldTypeValue(AsmTypes.JAVA_STRING_TYPE, insn)
is Type -> SpilledVariableFieldTypeValue(AsmTypes.JAVA_CLASS_TYPE, insn)
else -> SpilledVariableFieldTypeValue(AsmTypes.OBJECT_TYPE, insn)
}
JSR -> SpilledVariableFieldTypeValue(Type.VOID_TYPE, insn)
GETSTATIC -> SpilledVariableFieldTypeValue(Type.getType((insn as FieldInsnNode).desc), insn)
NEW -> SpilledVariableFieldTypeValue(Type.getObjectType((insn as TypeInsnNode).desc), insn)
else -> unreachable(insn)
}
}
}
internal fun performSpilledVariableFieldTypesAnalysis(
methodNode: MethodNode,
thisName: String
): Array<out Frame<SpilledVariableFieldTypeValue>?> =
MethodAnalyzer(thisName, methodNode, SpilledVariableFieldTypesInterpreter(methodNode)).analyze()
): Array<out Frame<BasicValue>?> {
val interpreter = IntLikeCoerceInterpreter()
MethodAnalyzer(thisName, methodNode, interpreter).analyze()
for ((insn, type) in interpreter.needsToBeCoerced) {
methodNode.instructions.insert(insn, withInstructionAdapter { coerceInt(type, this) })
}
return MethodAnalyzer(thisName, methodNode, OptimizationBasicInterpreter()).analyze()
}
internal val Value.type: Type?
get() = when (this) {
is BasicValue -> type
is SpilledVariableFieldTypeValue -> type
else -> error("Unexpected type of $this")
}
private fun coerceInt(to: Type, v: InstructionAdapter) {
if (to == Type.BOOLEAN_TYPE) {
with(v) {
val zeroLabel = Label()
val resLabel = Label()
ifeq(zeroLabel)
iconst(1)
goTo(resLabel)
mark(zeroLabel)
iconst(0)
mark(resLabel)
}
} else {
StackValue.coerce(Type.INT_TYPE, to, v)
}
}
private fun Type.isIntLike(): Boolean = when (sort) {
Type.BOOLEAN, Type.BYTE, Type.CHAR, Type.SHORT -> true
else -> false
}

View File

@@ -15,7 +15,10 @@ import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.DescriptorRenderer
@@ -87,12 +90,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
isSameModule = sourceCompiler.isCallInsideSameModuleAsDeclared(functionDescriptor)
if (functionDescriptor !is FictitiousArrayConstructor) {
val functionOrAccessorName = jvmSignature.asmMethod.name
//track changes for property accessor and @JvmName inline functions/property accessors
if (functionOrAccessorName != functionDescriptor.name.asString()) {
val scope = getMemberScope(functionDescriptor)
//Fake lookup to track track changes for property accessors and @JvmName functions/property accessors
scope?.getContributedFunctions(Name.identifier(functionOrAccessorName), sourceCompiler.lookupLocation)
if (jvmSignature.asmMethod.name != functionDescriptor.name.asString()) {
trackLookup(functionDescriptor)
}
}
}
@@ -500,19 +500,24 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return true
}
private fun trackLookup(functionOrAccessor: FunctionDescriptor) {
val functionOrAccessorName = jvmSignature.asmMethod.name
val lookupTracker = state.configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: return
val location = sourceCompiler.lookupLocation.location ?: return
val position = if (lookupTracker.requiresPosition) location.position else Position.NO_POSITION
val classOrPackageFragment = functionOrAccessor.containingDeclaration
lookupTracker.record(
location.filePath,
position,
DescriptorUtils.getFqName(classOrPackageFragment).asString(),
ScopeKind.CLASSIFIER,
functionOrAccessorName
)
}
companion object {
private fun getMemberScope(functionOrAccessor: FunctionDescriptor): MemberScope? {
val callableMemberDescriptor = JvmCodegenUtil.getDirectMember(functionOrAccessor)
val classOrPackageFragment = callableMemberDescriptor.containingDeclaration
return when (classOrPackageFragment) {
is ClassDescriptor -> classOrPackageFragment.unsubstitutedMemberScope
is PackageFragmentDescriptor -> classOrPackageFragment.getMemberScope()
else -> null
}
}
internal fun createInlineMethodNode(
functionDescriptor: FunctionDescriptor,
methodOwner: Type,

View File

@@ -242,6 +242,17 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
methodNode.removeUnusedLocalVariables()
}
// Be careful to not remove instructions that are the only instruction for a line number. That will
// break debugging. If the previous instruction is a line number and the following instruction is
// a label followed by a line number, insert a nop instead of deleting the instruction.
private fun InsnList.removeOrReplaceByNop(insn: AbstractInsnNode) {
if (insn.previous is LineNumberNode && insn.next is LabelNode && insn.next.next is LineNumberNode) {
set(insn, InsnNode(Opcodes.NOP))
} else {
remove(insn)
}
}
private fun rewriteRefValue(capturedVar: CapturedVarDescriptor) {
methodNode.instructions.run {
val localVar = capturedVar.localVar!!
@@ -259,9 +270,10 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
remove(capturedVar.newInsn)
remove(capturedVar.initCallInsn!!)
capturedVar.stackInsns.forEach { remove(it) }
capturedVar.aloadInsns.forEach { remove(it) }
capturedVar.astoreInsns.forEach { remove(it) }
capturedVar.stackInsns.forEach { removeOrReplaceByNop(it) }
capturedVar.aloadInsns.forEach { removeOrReplaceByNop(it) }
capturedVar.astoreInsns.forEach { removeOrReplaceByNop(it) }
capturedVar.getFieldInsns.forEach { set(it, VarInsnNode(loadOpcode, capturedVar.localVarIndex)) }
capturedVar.putFieldInsns.forEach { set(it, VarInsnNode(storeOpcode, capturedVar.localVarIndex)) }
@@ -273,6 +285,7 @@ class CapturedVarsOptimizationMethodTransformer : MethodTransformer() {
}
}
}
}
}

View File

@@ -0,0 +1,17 @@
/*
* 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.cli.jvm.compiler
fun setupIdeaStandaloneExecution() {
System.getProperties().setProperty("idea.plugins.compatible.build", "201.6668.13")
System.getProperties().setProperty("project.structure.add.tools.jar.to.new.jdk", "false")
System.getProperties().setProperty("psi.track.invalidation", "true")
System.getProperties().setProperty("psi.incremental.reparse.depth.limit", "1000")
System.getProperties().setProperty("ide.hide.excluded.files", "false")
System.getProperties().setProperty("ast.loading.filter", "false")
System.getProperties().setProperty("idea.ignore.disabled.plugins", "true")
System.getProperties().setProperty("idea.home.path", System.getProperty("java.io.tmpdir"))
}

View File

@@ -15,7 +15,7 @@ public final enum class E : R|kotlin/Enum<test/E>| {
public final val y: R|kotlin/Int|
public get(): R|kotlin/Int|
private constructor(x: R|kotlin/String|, y: R|kotlin/Int|): R|test/E|
private constructor(@R|test/A|() x: R|kotlin/String|, @R|test/B|() y: R|kotlin/Int|): R|test/E|
public final static fun values(): R|kotlin/Array<test/E>| {
}

View File

@@ -0,0 +1,13 @@
// ISSUE: KT-39032
interface A {
fun foo()
}
interface B : A {
override fun foo()
}
fun <E> bar(e: E) where E : A, E : B {
e.foo()
}

View File

@@ -0,0 +1,12 @@
FILE: uselessMultipleBounds.kt
public abstract interface A : R|kotlin/Any| {
public abstract fun foo(): R|kotlin/Unit|
}
public abstract interface B : R|A| {
public abstract override fun foo(): R|kotlin/Unit|
}
public final fun <E : R|A|, R|B|> bar(e: R|E|): R|kotlin/Unit| {
R|<local>/e|.R|/B.foo|()
}

View File

@@ -61,14 +61,14 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
23 [label="Postponed enter to lambda"];
subgraph cluster_9 {
color=blue
33 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
32 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_10 {
color=blue
34 [label="Enter block"];
35 [label="Function call: R|/materialize|<R|kotlin/String|>()"];
36 [label="Exit block"];
33 [label="Enter block"];
34 [label="Function call: R|/materialize|<R|kotlin/String|>()"];
35 [label="Exit block"];
}
37 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
36 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
24 [label="Postponed exit from lambda"];
25 [label="Function call: R|kotlin/run|<R|kotlin/String|>(...)"];
@@ -77,11 +77,10 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
27 [label="Exit when branch result"];
28 [label="Exit when"];
}
29 [label="Call arguments union" style="filled" fillcolor=yellow];
30 [label="Variable declaration: lval x: R|kotlin/String|"];
31 [label="Exit block"];
29 [label="Variable declaration: lval x: R|kotlin/String|"];
30 [label="Exit block"];
}
32 [label="Exit function test_1" style="filled" fillcolor=red];
31 [label="Exit function test_1" style="filled" fillcolor=red];
}
8 -> {9};
9 -> {10};
@@ -98,7 +97,7 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
20 -> {28};
21 -> {22};
22 -> {23};
23 -> {33};
23 -> {32};
23 -> {24} [color=red];
24 -> {25};
25 -> {26};
@@ -107,78 +106,77 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
28 -> {29};
29 -> {30};
30 -> {31};
31 -> {32};
32 -> {33};
33 -> {34};
34 -> {35};
35 -> {36};
36 -> {37};
37 -> {29} [color=red];
37 -> {24} [color=green];
36 -> {24} [color=green];
subgraph cluster_11 {
color=red
38 [label="Enter function test_2" style="filled" fillcolor=red];
37 [label="Enter function test_2" style="filled" fillcolor=red];
subgraph cluster_12 {
color=blue
39 [label="Enter block"];
38 [label="Enter block"];
subgraph cluster_13 {
color=blue
40 [label="Try expression enter"];
39 [label="Try expression enter"];
subgraph cluster_14 {
color=blue
41 [label="Try main block enter"];
40 [label="Try main block enter"];
subgraph cluster_15 {
color=blue
42 [label="Enter block"];
43 [label="Postponed enter to lambda"];
41 [label="Enter block"];
42 [label="Postponed enter to lambda"];
subgraph cluster_16 {
color=blue
58 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
57 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_17 {
color=blue
59 [label="Enter block"];
60 [label="Function call: R|/materialize|<R|kotlin/String|>()"];
61 [label="Exit block"];
58 [label="Enter block"];
59 [label="Function call: R|/materialize|<R|kotlin/String|>()"];
60 [label="Exit block"];
}
62 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
61 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
44 [label="Postponed exit from lambda"];
45 [label="Function call: R|kotlin/run|<R|kotlin/String|>(...)"];
46 [label="Exit block"];
43 [label="Postponed exit from lambda"];
44 [label="Function call: R|kotlin/run|<R|kotlin/String|>(...)"];
45 [label="Exit block"];
}
47 [label="Try main block exit"];
46 [label="Try main block exit"];
}
subgraph cluster_18 {
color=blue
48 [label="Catch enter"];
47 [label="Catch enter"];
subgraph cluster_19 {
color=blue
49 [label="Enter block"];
50 [label="Const: String()"];
51 [label="Exit block"];
48 [label="Enter block"];
49 [label="Const: String()"];
50 [label="Exit block"];
}
52 [label="Catch exit"];
51 [label="Catch exit"];
}
53 [label="Try expression exit"];
52 [label="Try expression exit"];
}
54 [label="Call arguments union" style="filled" fillcolor=yellow];
55 [label="Variable declaration: lval x: R|kotlin/String|"];
56 [label="Exit block"];
53 [label="Call arguments union" style="filled" fillcolor=yellow];
54 [label="Variable declaration: lval x: R|kotlin/String|"];
55 [label="Exit block"];
}
57 [label="Exit function test_2" style="filled" fillcolor=red];
56 [label="Exit function test_2" style="filled" fillcolor=red];
}
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {57 48 42};
42 -> {43};
43 -> {58};
43 -> {44} [color=red];
40 -> {56 47 41};
41 -> {42};
42 -> {57};
42 -> {43} [color=red];
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {53};
48 -> {57 49};
46 -> {52};
47 -> {56 48};
48 -> {49};
49 -> {50};
50 -> {51};
51 -> {52};
@@ -186,56 +184,55 @@ digraph inplaceLambdaInControlFlowExpressions_kt {
53 -> {54};
54 -> {55};
55 -> {56};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {60};
60 -> {61};
61 -> {62};
62 -> {54} [color=red];
62 -> {44} [color=green];
61 -> {53} [color=red];
61 -> {43} [color=green];
subgraph cluster_20 {
color=red
63 [label="Enter function test_3" style="filled" fillcolor=red];
62 [label="Enter function test_3" style="filled" fillcolor=red];
subgraph cluster_21 {
color=blue
64 [label="Enter block"];
65 [label="Postponed enter to lambda"];
63 [label="Enter block"];
64 [label="Postponed enter to lambda"];
subgraph cluster_22 {
color=blue
73 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
72 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_23 {
color=blue
74 [label="Enter block"];
75 [label="Function call: R|/materialize|<R|kotlin/String?|>()"];
76 [label="Exit block"];
73 [label="Enter block"];
74 [label="Function call: R|/materialize|<R|kotlin/String?|>()"];
75 [label="Exit block"];
}
77 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
76 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
66 [label="Postponed exit from lambda"];
67 [label="Function call: R|kotlin/run|<R|kotlin/String?|>(...)"];
68 [label="Check not null: R|kotlin/run|<R|kotlin/String?|>(...)!!"];
69 [label="Call arguments union" style="filled" fillcolor=yellow];
70 [label="Variable declaration: lval x: R|kotlin/String|"];
71 [label="Exit block"];
65 [label="Postponed exit from lambda"];
66 [label="Function call: R|kotlin/run|<R|kotlin/String?|>(...)"];
67 [label="Check not null: R|kotlin/run|<R|kotlin/String?|>(...)!!"];
68 [label="Call arguments union" style="filled" fillcolor=yellow];
69 [label="Variable declaration: lval x: R|kotlin/String|"];
70 [label="Exit block"];
}
72 [label="Exit function test_3" style="filled" fillcolor=red];
71 [label="Exit function test_3" style="filled" fillcolor=red];
}
62 -> {63};
63 -> {64};
64 -> {65};
65 -> {73};
65 -> {66} [color=red];
64 -> {72};
64 -> {65} [color=red];
65 -> {66};
66 -> {67};
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73};
73 -> {74};
74 -> {75};
75 -> {76};
76 -> {77};
77 -> {69} [color=red];
77 -> {66} [color=green];
76 -> {68} [color=red];
76 -> {65} [color=green];
}

View File

@@ -24,15 +24,7 @@ FILE: delegateWithLambda.kt
}
public final val x: R|kotlin/String|by R|/lazy|<R|kotlin/String|>(<L> = lazy@fun <anonymous>(): R|kotlin/String| {
lval y: R|kotlin/String| = when (lval <elvis>: R|kotlin/String?| = (R|/getAny|() as? R|kotlin/String|)) {
==($subj$, Null(null)) -> {
String()
}
else -> {
R|<local>/<elvis>|
}
}
lval y: R|kotlin/String| = (R|/getAny|() as? R|kotlin/String|) ?: String()
^ R|<local>/y|
}
)

View File

@@ -16,27 +16,11 @@ FILE: test.kt
}
public final fun test1(x: R|AnotherClass?|): R|kotlin/Unit| {
lval bar: R|kotlin/CharSequence| = when (lval <elvis>: R|kotlin/CharSequence?| = R|<local>/x|?.{ $subj$.R|/AnotherClass.bar| }) {
==($subj$, Null(null)) -> {
^test1 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval bar: R|kotlin/CharSequence| = R|<local>/x|?.{ $subj$.R|/AnotherClass.bar| } ?: ^test1 Unit
R|<local>/x|.R|/AnotherClass.bar|
}
public final fun test2(x: R|SomeClass?|): R|kotlin/Unit| {
lval bar: R|kotlin/CharSequence| = when (lval <elvis>: R|kotlin/CharSequence?| = R|<local>/x|?.{ $subj$.R|/SomeClass.bar| }) {
==($subj$, Null(null)) -> {
^test2 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval bar: R|kotlin/CharSequence| = R|<local>/x|?.{ $subj$.R|/SomeClass.bar| } ?: ^test2 Unit
R|<local>/x|.R|/SomeClass.bar|
}
public final fun test3(x: R|AnotherClass?|): R|kotlin/Unit| {
@@ -58,62 +42,22 @@ FILE: test.kt
}
public final fun test5(x: R|AnotherClass?|): R|kotlin/Unit| {
lval bar: R|kotlin/String| = when (lval <elvis>: R|kotlin/String?| = (R|<local>/x|?.{ $subj$.R|/AnotherClass.bar| } as? R|kotlin/String|)) {
==($subj$, Null(null)) -> {
^test5 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval bar: R|kotlin/String| = (R|<local>/x|?.{ $subj$.R|/AnotherClass.bar| } as? R|kotlin/String|) ?: ^test5 Unit
R|<local>/x|.R|/AnotherClass.foo|
}
public final fun test6(x: R|SomeClass?|): R|kotlin/Unit| {
lval bar: R|kotlin/String| = when (lval <elvis>: R|kotlin/String?| = (R|<local>/x|?.{ $subj$.R|/SomeClass.bar| } as? R|kotlin/String|)) {
==($subj$, Null(null)) -> {
^test6 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval bar: R|kotlin/String| = (R|<local>/x|?.{ $subj$.R|/SomeClass.bar| } as? R|kotlin/String|) ?: ^test6 Unit
R|<local>/x|.R|/SomeClass.foo|
}
public final fun test7(x: R|AnotherClass?|): R|kotlin/Unit| {
lval baz: R|kotlin/Boolean| = when (lval <elvis>: R|kotlin/Boolean?| = (R|<local>/x|?.{ $subj$.R|/AnotherClass.baz|() } as? R|kotlin/Boolean|)) {
==($subj$, Null(null)) -> {
^test7 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval baz: R|kotlin/Boolean| = (R|<local>/x|?.{ $subj$.R|/AnotherClass.baz|() } as? R|kotlin/Boolean|) ?: ^test7 Unit
R|<local>/x|.R|/AnotherClass.foo|
}
public final fun test8(x: R|AnotherClass?|): R|kotlin/Unit| {
lval bar: R|kotlin/CharSequence| = when (lval <elvis>: R|kotlin/CharSequence?| = R|<local>/x|?.{ $subj$.R|/AnotherClass.bar| }) {
==($subj$, Null(null)) -> {
^test8 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval bar: R|kotlin/CharSequence| = R|<local>/x|?.{ $subj$.R|/AnotherClass.bar| } ?: ^test8 Unit
R|<local>/x|.R|/AnotherClass.foo|
}
public final fun test9(x: R|AnotherClass?|): R|kotlin/Unit| {
lval baz: R|kotlin/Any| = when (lval <elvis>: R|kotlin/Any?| = R|<local>/x|?.{ $subj$.R|/AnotherClass.baz|() }) {
==($subj$, Null(null)) -> {
^test9 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval baz: R|kotlin/Any| = R|<local>/x|?.{ $subj$.R|/AnotherClass.baz|() } ?: ^test9 Unit
R|<local>/x|.R|/AnotherClass.foo|
}

View File

@@ -0,0 +1,19 @@
// ISSUE: KT-39075
class A {
fun unit() {}
}
fun foo(x: () -> Unit) {}
fun main(x: A?) {
val lambda = l@{
if (x?.hashCode() == 0) return@l
x?.unit()
}
// lambda has a type (() -> Unit?)
foo(lambda)
}

View File

@@ -0,0 +1,25 @@
FILE: coercionToUnitWithEarlyReturn.kt
public final class A : R|kotlin/Any| {
public constructor(): R|A| {
super<R|kotlin/Any|>()
}
public final fun unit(): R|kotlin/Unit| {
}
}
public final fun foo(x: R|() -> kotlin/Unit|): R|kotlin/Unit| {
}
public final fun main(x: R|A?|): R|kotlin/Unit| {
lval lambda: R|() -> kotlin/Unit| = l@fun <anonymous>(): R|kotlin/Unit| {
when () {
==(R|<local>/x|?.{ $subj$.R|kotlin/Any.hashCode|() }, Int(0)) -> {
^@l Unit
}
}
^ R|<local>/x|?.{ $subj$.R|/A.unit|() }
}
R|/foo|(R|<local>/lambda|)
}

View File

@@ -0,0 +1,14 @@
// ISSUE: KT-39048
// FILE: JavaClass.java
public class JavaClass<T extends Comparable<? super T>> {
public JavaClass(T from) {}
}
// FILE: main.kt
class K<T : Comparable<T>>(t: T)
fun main() {
K(0)
JavaClass(0)
}

View File

@@ -0,0 +1,11 @@
FILE: main.kt
public final class K<T : R|kotlin/Comparable<T>|> : R|kotlin/Any| {
public constructor<T : R|kotlin/Comparable<T>|>(t: R|T|): R|K<T>| {
super<R|kotlin/Any|>()
}
}
public final fun main(): R|kotlin/Unit| {
R|/K.K|<R|kotlin/Int|>(Int(0))
R|/JavaClass.JavaClass|<R|ft<ILT: 0, ILT: 0?>!|>(Int(0))
}

View File

@@ -0,0 +1,18 @@
// ISSUE: KT-39012
interface A
fun <T> foo(f: (MutableList<T>) -> Unit): List<T>? = TODO()
fun <T> listOf(): List<T> = TODO()
fun bar1(w: List<CharSequence>): List<CharSequence>? {
return foo { container ->
container.add("")
} ?: w
}
fun bar2(): List<CharSequence>? {
return foo { container ->
container.add("")
} ?: listOf()
}

View File

@@ -0,0 +1,21 @@
FILE: lambdaInElvis.kt
public abstract interface A : R|kotlin/Any| {
}
public final fun <T> foo(f: R|(kotlin/collections/MutableList<T>) -> kotlin/Unit|): R|kotlin/collections/List<T>?| {
^foo R|kotlin/TODO|()
}
public final fun <T> listOf(): R|kotlin/collections/List<T>| {
^listOf R|kotlin/TODO|()
}
public final fun bar1(w: R|kotlin/collections/List<kotlin/CharSequence>|): R|kotlin/collections/List<kotlin/CharSequence>?| {
^bar1 R|/foo|<R|kotlin/CharSequence|>(<L> = foo@fun <anonymous>(container: R|kotlin/collections/MutableList<kotlin/CharSequence>|): R|kotlin/Unit| {
^ R|<local>/container|.R|FakeOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(String())
}
) ?: R|<local>/w|
}
public final fun bar2(): R|kotlin/collections/List<kotlin/CharSequence>?| {
^bar2 R|/foo|<R|kotlin/CharSequence|>(<L> = foo@fun <anonymous>(container: R|kotlin/collections/MutableList<kotlin/CharSequence>|): R|kotlin/Unit| {
^ R|<local>/container|.R|FakeOverride<kotlin/collections/MutableList.add: R|kotlin/Boolean|>|(String())
}
) ?: R|/listOf|<R|kotlin/CharSequence|>()
}

View File

@@ -1,12 +1,4 @@
FILE: invokeInWhenSubjectVariableInitializer.kt
public final fun test(func: R|() -> kotlin/String?|): R|kotlin/Unit| {
lval x: R|kotlin/String| = when (lval <elvis>: R|kotlin/String?| = R|<local>/func|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/String?|>|()) {
==($subj$, Null(null)) -> {
String()
}
else -> {
R|<local>/<elvis>|
}
}
lval x: R|kotlin/String| = R|<local>/func|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/String?|>|() ?: String()
}

View File

@@ -0,0 +1,17 @@
// ISSUE: KT-39046
fun foo(b: B<Int, Int>) {}
fun test_1(b: B<String, Number>) {
foo(b.myMap {
it.k.length // implicits
} as B<Int, Int>)
}
fun test_2(s: String) {
val func = { s.length } as B<Int, Int>
}
class B<out K, V>(val k: K, val v: V)
fun <X, R, V> B<X, V>.myMap(transform: (B<X, V>) -> R): B<R, V> = TODO()

View File

@@ -0,0 +1,30 @@
FILE: lambdaInLhsOfTypeOperatorCall.kt
public final fun foo(b: R|B<kotlin/Int, kotlin/Int>|): R|kotlin/Unit| {
}
public final fun test_1(b: R|B<kotlin/String, kotlin/Number>|): R|kotlin/Unit| {
R|/foo|((R|<local>/b|.R|/myMap|<R|kotlin/String|, R|kotlin/Int|, R|kotlin/Number|>(<L> = myMap@fun <anonymous>(it: R|B<kotlin/String, kotlin/Number>|): R|kotlin/Int| {
^ R|<local>/it|.R|FakeOverride</B.k: R|kotlin/String|>|.R|kotlin/String.length|
}
) as R|B<kotlin/Int, kotlin/Int>|))
}
public final fun test_2(s: R|kotlin/String|): R|kotlin/Unit| {
lval func: R|B<kotlin/Int, kotlin/Int>| = (fun <anonymous>(): R|kotlin/Int| {
^ R|<local>/s|.R|kotlin/String.length|
}
as R|B<kotlin/Int, kotlin/Int>|)
}
public final class B<out K, V> : R|kotlin/Any| {
public constructor<out K, V>(k: R|K|, v: R|V|): R|B<K, V>| {
super<R|kotlin/Any|>()
}
public final val k: R|K| = R|<local>/k|
public get(): R|K|
public final val v: R|V| = R|<local>/v|
public get(): R|V|
}
public final fun <X, R, V> R|B<X, V>|.myMap(transform: R|(B<X, V>) -> R|): R|B<R, V>| {
^myMap R|kotlin/TODO|()
}

View File

@@ -366,81 +366,75 @@ digraph boundSmartcasts_kt {
subgraph cluster_34 {
color=blue
130 [label="Enter block"];
subgraph cluster_35 {
color=blue
131 [label="Enter when"];
132 [label="Access variable R|<local>/d|"];
133 [label="Access variable R|/D.any|"];
134 [label="Variable declaration: lval <elvis>: R|kotlin/Any?|"];
subgraph cluster_36 {
color=blue
135 [label="Enter when branch condition "];
136 [label="Const: Null(null)"];
137 [label="Operator =="];
138 [label="Exit when branch condition"];
}
subgraph cluster_37 {
color=blue
139 [label="Enter when branch condition else"];
140 [label="Exit when branch condition"];
}
141 [label="Enter when branch result"];
subgraph cluster_38 {
color=blue
142 [label="Enter block"];
143 [label="Access variable R|<local>/<elvis>|"];
144 [label="Exit block"];
}
145 [label="Exit when branch result"];
146 [label="Enter when branch result"];
subgraph cluster_39 {
color=blue
147 [label="Enter block"];
148 [label="Jump: ^test_5 Unit"];
149 [label="Stub" style="filled" fillcolor=gray];
150 [label="Exit block" style="filled" fillcolor=gray];
}
151 [label="Exit when branch result" style="filled" fillcolor=gray];
152 [label="Exit when"];
}
153 [label="Variable declaration: lval a: R|kotlin/Any|"];
154 [label="Access variable R|<local>/a|"];
155 [label="Function call: R|<local>/a|.R|/baz|()"];
156 [label="Access variable R|<local>/d|"];
157 [label="Access variable R|/D.any|"];
158 [label="Function call: R|<local>/d|.R|/D.any|.R|/baz|()"];
159 [label="Access variable R|<local>/a|"];
160 [label="Type operator: (R|<local>/a| as R|A|)"];
161 [label="Access variable R|<local>/a|"];
162 [label="Function call: R|<local>/a|.R|/A.foo|()"];
163 [label="Exit block"];
131 [label="Access variable R|<local>/d|"];
132 [label="Access variable R|/D.any|"];
133 [label="Exit lhs of ?:"];
134 [label="Enter rhs of ?:"];
135 [label="Jump: ^test_5 Unit"];
136 [label="Stub" style="filled" fillcolor=gray];
137 [label="Lhs of ?: is not null"];
138 [label="Exit ?:"];
139 [label="Variable declaration: lval a: R|kotlin/Any|"];
140 [label="Access variable R|<local>/a|"];
141 [label="Function call: R|<local>/a|.R|/baz|()"];
142 [label="Access variable R|<local>/d|"];
143 [label="Access variable R|/D.any|"];
144 [label="Function call: R|<local>/d|.R|/D.any|.R|/baz|()"];
145 [label="Access variable R|<local>/a|"];
146 [label="Type operator: (R|<local>/a| as R|A|)"];
147 [label="Access variable R|<local>/a|"];
148 [label="Function call: R|<local>/a|.R|/A.foo|()"];
149 [label="Exit block"];
}
164 [label="Exit function test_5" style="filled" fillcolor=red];
150 [label="Exit function test_5" style="filled" fillcolor=red];
}
129 -> {130};
130 -> {131};
131 -> {132};
132 -> {133};
133 -> {134};
133 -> {137 134};
134 -> {135};
135 -> {136};
136 -> {137};
135 -> {150};
135 -> {136} [style=dotted];
136 -> {138} [style=dotted];
137 -> {138};
138 -> {146 139};
138 -> {139};
139 -> {140};
140 -> {141};
141 -> {142};
142 -> {143};
143 -> {144};
144 -> {145};
145 -> {152};
145 -> {146};
146 -> {147};
147 -> {148};
148 -> {164};
148 -> {149} [style=dotted];
149 -> {150} [style=dotted];
150 -> {151} [style=dotted];
151 -> {152} [style=dotted];
148 -> {149};
149 -> {150};
subgraph cluster_35 {
color=red
151 [label="Enter function test_6" style="filled" fillcolor=red];
subgraph cluster_36 {
color=blue
152 [label="Enter block"];
153 [label="Access variable R|<local>/d1|"];
154 [label="Access variable R|/D.any|"];
155 [label="Variable declaration: lval a: R|kotlin/Any?|"];
156 [label="Access variable R|<local>/a|"];
157 [label="Type operator: (R|<local>/a| as R|A|)"];
158 [label="Access variable R|<local>/a|"];
159 [label="Function call: R|<local>/a|.R|/A.foo|()"];
160 [label="Access variable R|<local>/d1|"];
161 [label="Access variable R|/D.any|"];
162 [label="Function call: R|<local>/d1|.R|/D.any|.R|/A.foo|()"];
163 [label="Access variable R|<local>/d1|"];
164 [label="Access variable R|/D.any|"];
165 [label="Function call: R|<local>/d1|.R|/D.any|.R|/baz|()"];
166 [label="Exit block"];
}
167 [label="Exit function test_6" style="filled" fillcolor=red];
}
151 -> {152};
152 -> {153};
153 -> {154};
154 -> {155};
@@ -453,95 +447,58 @@ digraph boundSmartcasts_kt {
161 -> {162};
162 -> {163};
163 -> {164};
subgraph cluster_40 {
color=red
165 [label="Enter function test_6" style="filled" fillcolor=red];
subgraph cluster_41 {
color=blue
166 [label="Enter block"];
167 [label="Access variable R|<local>/d1|"];
168 [label="Access variable R|/D.any|"];
169 [label="Variable declaration: lval a: R|kotlin/Any?|"];
170 [label="Access variable R|<local>/a|"];
171 [label="Type operator: (R|<local>/a| as R|A|)"];
172 [label="Access variable R|<local>/a|"];
173 [label="Function call: R|<local>/a|.R|/A.foo|()"];
174 [label="Access variable R|<local>/d1|"];
175 [label="Access variable R|/D.any|"];
176 [label="Function call: R|<local>/d1|.R|/D.any|.R|/A.foo|()"];
177 [label="Access variable R|<local>/d1|"];
178 [label="Access variable R|/D.any|"];
179 [label="Function call: R|<local>/d1|.R|/D.any|.R|/baz|()"];
180 [label="Exit block"];
}
181 [label="Exit function test_6" style="filled" fillcolor=red];
}
164 -> {165};
165 -> {166};
166 -> {167};
167 -> {168};
subgraph cluster_37 {
color=red
168 [label="Enter function test_7" style="filled" fillcolor=red];
subgraph cluster_38 {
color=blue
169 [label="Enter block"];
170 [label="Access variable R|<local>/d1|"];
171 [label="Enter safe call"];
172 [label="Access variable R|/D.any|"];
173 [label="Exit safe call"];
174 [label="Variable declaration: lval a: R|kotlin/Any?|"];
175 [label="Access variable R|<local>/d2|"];
176 [label="Enter safe call"];
177 [label="Access variable R|/D.any|"];
178 [label="Exit safe call"];
179 [label="Variable declaration: lval b: R|kotlin/Any?|"];
180 [label="Access variable R|<local>/a|"];
181 [label="Type operator: (R|<local>/a| as R|A|)"];
182 [label="Access variable R|<local>/a|"];
183 [label="Function call: R|<local>/a|.R|/A.foo|()"];
184 [label="Access variable R|<local>/b|"];
185 [label="Type operator: (R|<local>/b| as R|B|)"];
186 [label="Access variable R|<local>/b|"];
187 [label="Function call: R|<local>/b|.R|/B.bar|()"];
188 [label="Exit block"];
}
189 [label="Exit function test_7" style="filled" fillcolor=red];
}
168 -> {169};
169 -> {170};
170 -> {171};
170 -> {171 173};
171 -> {172};
172 -> {173};
173 -> {174};
174 -> {175};
175 -> {176};
175 -> {176 178};
176 -> {177};
177 -> {178};
178 -> {179};
179 -> {180};
180 -> {181};
subgraph cluster_42 {
color=red
182 [label="Enter function test_7" style="filled" fillcolor=red];
subgraph cluster_43 {
color=blue
183 [label="Enter block"];
184 [label="Access variable R|<local>/d1|"];
185 [label="Enter safe call"];
186 [label="Access variable R|/D.any|"];
187 [label="Exit safe call"];
188 [label="Variable declaration: lval a: R|kotlin/Any?|"];
189 [label="Access variable R|<local>/d2|"];
190 [label="Enter safe call"];
191 [label="Access variable R|/D.any|"];
192 [label="Exit safe call"];
193 [label="Variable declaration: lval b: R|kotlin/Any?|"];
194 [label="Access variable R|<local>/a|"];
195 [label="Type operator: (R|<local>/a| as R|A|)"];
196 [label="Access variable R|<local>/a|"];
197 [label="Function call: R|<local>/a|.R|/A.foo|()"];
198 [label="Access variable R|<local>/b|"];
199 [label="Type operator: (R|<local>/b| as R|B|)"];
200 [label="Access variable R|<local>/b|"];
201 [label="Function call: R|<local>/b|.R|/B.bar|()"];
202 [label="Exit block"];
}
203 [label="Exit function test_7" style="filled" fillcolor=red];
}
181 -> {182};
182 -> {183};
183 -> {184};
184 -> {185 187};
184 -> {185};
185 -> {186};
186 -> {187};
187 -> {188};
188 -> {189};
189 -> {190 192};
190 -> {191};
191 -> {192};
192 -> {193};
193 -> {194};
194 -> {195};
195 -> {196};
196 -> {197};
197 -> {198};
198 -> {199};
199 -> {200};
200 -> {201};
201 -> {202};
202 -> {203};
}

View File

@@ -70,15 +70,7 @@ FILE: boundSmartcasts.kt
public final fun R|kotlin/Any|.baz(): R|kotlin/Unit| {
}
public final fun test_5(d: R|D|): R|kotlin/Unit| {
lval a: R|kotlin/Any| = when (lval <elvis>: R|kotlin/Any?| = R|<local>/d|.R|/D.any|) {
==($subj$, Null(null)) -> {
^test_5 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval a: R|kotlin/Any| = R|<local>/d|.R|/D.any| ?: ^test_5 Unit
R|<local>/a|.R|/baz|()
R|<local>/d|.R|/D.any|.R|/baz|()
(R|<local>/a| as R|A|)

View File

@@ -36,122 +36,102 @@ digraph elvis_kt {
subgraph cluster_6 {
color=blue
9 [label="Enter when branch condition "];
subgraph cluster_7 {
color=blue
10 [label="Enter when"];
11 [label="Access variable R|<local>/x|"];
12 [label="Enter safe call"];
13 [label="Access variable R|/A.b|"];
14 [label="Exit safe call"];
15 [label="Variable declaration: lval <elvis>: R|kotlin/Boolean?|"];
subgraph cluster_8 {
color=blue
16 [label="Enter when branch condition "];
17 [label="Const: Null(null)"];
18 [label="Operator =="];
19 [label="Exit when branch condition"];
}
subgraph cluster_9 {
color=blue
20 [label="Enter when branch condition else"];
21 [label="Exit when branch condition"];
}
22 [label="Enter when branch result"];
subgraph cluster_10 {
color=blue
23 [label="Enter block"];
24 [label="Access variable R|<local>/<elvis>|"];
25 [label="Exit block"];
}
26 [label="Exit when branch result"];
27 [label="Enter when branch result"];
subgraph cluster_11 {
color=blue
28 [label="Enter block"];
29 [label="Jump: ^test_1 Unit"];
30 [label="Stub" style="filled" fillcolor=gray];
31 [label="Exit block" style="filled" fillcolor=gray];
}
32 [label="Exit when branch result" style="filled" fillcolor=gray];
33 [label="Exit when"];
}
34 [label="Exit when branch condition"];
10 [label="Access variable R|<local>/x|"];
11 [label="Enter safe call"];
12 [label="Access variable R|/A.b|"];
13 [label="Exit safe call"];
14 [label="Exit lhs of ?:"];
15 [label="Enter rhs of ?:"];
16 [label="Jump: ^test_1 Unit"];
17 [label="Stub" style="filled" fillcolor=gray];
18 [label="Lhs of ?: is not null"];
19 [label="Exit ?:"];
20 [label="Exit when branch condition"];
}
35 [label="Synthetic else branch"];
36 [label="Enter when branch result"];
subgraph cluster_12 {
21 [label="Synthetic else branch"];
22 [label="Enter when branch result"];
subgraph cluster_7 {
color=blue
37 [label="Enter block"];
38 [label="Access variable R|<local>/x|"];
39 [label="Function call: R|<local>/x|.R|/A.foo|()"];
40 [label="Exit block"];
23 [label="Enter block"];
24 [label="Access variable R|<local>/x|"];
25 [label="Function call: R|<local>/x|.R|/A.foo|()"];
26 [label="Exit block"];
}
41 [label="Exit when branch result"];
42 [label="Exit when"];
27 [label="Exit when branch result"];
28 [label="Exit when"];
}
43 [label="Exit block"];
29 [label="Exit block"];
}
44 [label="Exit function test_1" style="filled" fillcolor=red];
30 [label="Exit function test_1" style="filled" fillcolor=red];
}
6 -> {7};
7 -> {8};
8 -> {9};
9 -> {10};
10 -> {11};
11 -> {12 14};
10 -> {11 13};
11 -> {12};
12 -> {13};
13 -> {14};
14 -> {15};
14 -> {18 15};
15 -> {16};
16 -> {17};
17 -> {18};
16 -> {30};
16 -> {17} [style=dotted];
17 -> {19} [style=dotted];
18 -> {19};
19 -> {27 20};
20 -> {21};
21 -> {22};
19 -> {20};
20 -> {22 21};
21 -> {28};
22 -> {23};
23 -> {24};
24 -> {25};
25 -> {26};
26 -> {33};
26 -> {27};
27 -> {28};
28 -> {29};
29 -> {44};
29 -> {30} [style=dotted];
30 -> {31} [style=dotted];
31 -> {32} [style=dotted];
32 -> {33} [style=dotted];
33 -> {34};
34 -> {36 35};
35 -> {42};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {44};
29 -> {30};
subgraph cluster_13 {
subgraph cluster_8 {
color=red
45 [label="Enter function test2" style="filled" fillcolor=red];
subgraph cluster_14 {
31 [label="Enter function test2" style="filled" fillcolor=red];
subgraph cluster_9 {
color=blue
46 [label="Enter block"];
subgraph cluster_15 {
32 [label="Enter block"];
subgraph cluster_10 {
color=blue
33 [label="Enter when"];
subgraph cluster_11 {
color=blue
34 [label="Enter when branch condition "];
35 [label="Access variable R|<local>/b|"];
36 [label="Type operator: (R|<local>/b| !is R|kotlin/String|)"];
37 [label="Exit when branch condition"];
}
38 [label="Synthetic else branch"];
39 [label="Enter when branch result"];
subgraph cluster_12 {
color=blue
40 [label="Enter block"];
41 [label="Const: String()"];
42 [label="Jump: ^test2 String()"];
43 [label="Stub" style="filled" fillcolor=gray];
44 [label="Exit block" style="filled" fillcolor=gray];
}
45 [label="Exit when branch result" style="filled" fillcolor=gray];
46 [label="Exit when"];
}
subgraph cluster_13 {
color=blue
47 [label="Enter when"];
subgraph cluster_16 {
subgraph cluster_14 {
color=blue
48 [label="Enter when branch condition "];
49 [label="Access variable R|<local>/b|"];
50 [label="Type operator: (R|<local>/b| !is R|kotlin/String|)"];
49 [label="Access variable R|<local>/a|"];
50 [label="Type operator: (R|<local>/a| !is R|kotlin/String?|)"];
51 [label="Exit when branch condition"];
}
52 [label="Synthetic else branch"];
53 [label="Enter when branch result"];
subgraph cluster_17 {
subgraph cluster_15 {
color=blue
54 [label="Enter block"];
55 [label="Const: String()"];
@@ -162,79 +142,34 @@ digraph elvis_kt {
59 [label="Exit when branch result" style="filled" fillcolor=gray];
60 [label="Exit when"];
}
subgraph cluster_18 {
color=blue
61 [label="Enter when"];
subgraph cluster_19 {
color=blue
62 [label="Enter when branch condition "];
63 [label="Access variable R|<local>/a|"];
64 [label="Type operator: (R|<local>/a| !is R|kotlin/String?|)"];
65 [label="Exit when branch condition"];
}
66 [label="Synthetic else branch"];
67 [label="Enter when branch result"];
subgraph cluster_20 {
color=blue
68 [label="Enter block"];
69 [label="Const: String()"];
70 [label="Jump: ^test2 String()"];
71 [label="Stub" style="filled" fillcolor=gray];
72 [label="Exit block" style="filled" fillcolor=gray];
}
73 [label="Exit when branch result" style="filled" fillcolor=gray];
74 [label="Exit when"];
}
subgraph cluster_21 {
color=blue
75 [label="Enter when"];
76 [label="Access variable R|<local>/a|"];
77 [label="Variable declaration: lval <elvis>: R|kotlin/String?|"];
subgraph cluster_22 {
color=blue
78 [label="Enter when branch condition "];
79 [label="Const: Null(null)"];
80 [label="Operator =="];
81 [label="Exit when branch condition"];
}
subgraph cluster_23 {
color=blue
82 [label="Enter when branch condition else"];
83 [label="Exit when branch condition"];
}
84 [label="Enter when branch result"];
subgraph cluster_24 {
color=blue
85 [label="Enter block"];
86 [label="Access variable R|<local>/<elvis>|"];
87 [label="Exit block"];
}
88 [label="Exit when branch result"];
89 [label="Enter when branch result"];
subgraph cluster_25 {
color=blue
90 [label="Enter block"];
91 [label="Access variable R|<local>/b|"];
92 [label="Exit block"];
}
93 [label="Exit when branch result"];
94 [label="Exit when"];
}
95 [label="Jump: ^test2 when (lval <elvis>: R|kotlin/String?| = R|<local>/a|) {
==($subj$, Null(null)) -> {
R|<local>/b|
}
else -> {
R|<local>/<elvis>|
}
}
"];
96 [label="Stub" style="filled" fillcolor=gray];
97 [label="Exit block" style="filled" fillcolor=gray];
61 [label="Access variable R|<local>/a|"];
62 [label="Exit lhs of ?:"];
63 [label="Enter rhs of ?:"];
64 [label="Access variable R|<local>/b|"];
65 [label="Lhs of ?: is not null"];
66 [label="Exit ?:"];
67 [label="Jump: ^test2 R|<local>/a| ?: R|<local>/b|"];
68 [label="Stub" style="filled" fillcolor=gray];
69 [label="Exit block" style="filled" fillcolor=gray];
}
98 [label="Exit function test2" style="filled" fillcolor=red];
70 [label="Exit function test2" style="filled" fillcolor=red];
}
45 -> {46};
31 -> {32};
32 -> {33};
33 -> {34};
34 -> {35};
35 -> {36};
36 -> {37};
37 -> {39 38};
38 -> {46};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {70};
42 -> {43} [style=dotted];
43 -> {44} [style=dotted];
44 -> {45} [style=dotted];
45 -> {46} [style=dotted];
46 -> {47};
47 -> {48};
48 -> {49};
@@ -245,50 +180,21 @@ digraph elvis_kt {
53 -> {54};
54 -> {55};
55 -> {56};
56 -> {98};
56 -> {70};
56 -> {57} [style=dotted];
57 -> {58} [style=dotted];
58 -> {59} [style=dotted];
59 -> {60} [style=dotted];
60 -> {61};
61 -> {62};
62 -> {63};
62 -> {65 63};
63 -> {64};
64 -> {65};
65 -> {67 66};
66 -> {74};
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {98};
70 -> {71} [style=dotted];
71 -> {72} [style=dotted];
72 -> {73} [style=dotted];
73 -> {74} [style=dotted];
74 -> {75};
75 -> {76};
76 -> {77};
77 -> {78};
78 -> {79};
79 -> {80};
80 -> {81};
81 -> {89 82};
82 -> {83};
83 -> {84};
84 -> {85};
85 -> {86};
86 -> {87};
87 -> {88};
88 -> {94};
89 -> {90};
90 -> {91};
91 -> {92};
92 -> {93};
93 -> {94};
94 -> {95};
95 -> {98};
95 -> {96} [style=dotted];
96 -> {97} [style=dotted];
97 -> {98} [style=dotted];
64 -> {66};
65 -> {66};
66 -> {67};
67 -> {70};
67 -> {68} [style=dotted];
68 -> {69} [style=dotted];
69 -> {70} [style=dotted];
}

View File

@@ -8,15 +8,7 @@ FILE: elvis.kt
}
public final fun test_1(x: R|A?|): R|kotlin/Unit| {
when () {
when (lval <elvis>: R|kotlin/Boolean?| = R|<local>/x|?.{ $subj$.R|/A.b| }) {
==($subj$, Null(null)) -> {
^test_1 Unit
}
else -> {
R|<local>/<elvis>|
}
}
-> {
R|<local>/x|?.{ $subj$.R|/A.b| } ?: ^test_1 Unit -> {
R|<local>/x|.R|/A.foo|()
}
}
@@ -35,13 +27,5 @@ FILE: elvis.kt
}
}
^test2 when (lval <elvis>: R|kotlin/String?| = R|<local>/a|) {
==($subj$, Null(null)) -> {
R|<local>/b|
}
else -> {
R|<local>/<elvis>|
}
}
^test2 R|<local>/a| ?: R|<local>/b|
}

View File

@@ -434,104 +434,61 @@ digraph returns_kt {
151 [label="Access variable R|<local>/a|"];
152 [label="Type operator: (R|<local>/a| as? R|kotlin/String|)"];
153 [label="Variable declaration: lval s: R|kotlin/String?|"];
154 [label="Access variable R|<local>/s|"];
155 [label="Enter safe call"];
156 [label="Access variable R|/ext|"];
157 [label="Exit safe call"];
158 [label="Exit lhs of ?:"];
159 [label="Enter rhs of ?:"];
160 [label="Jump: ^test_4 Unit"];
161 [label="Stub" style="filled" fillcolor=gray];
162 [label="Lhs of ?: is not null"];
163 [label="Exit ?:"];
164 [label="Variable declaration: lval length: R|kotlin/Int|"];
165 [label="Postponed enter to lambda"];
subgraph cluster_42 {
color=blue
154 [label="Enter when"];
155 [label="Access variable R|<local>/s|"];
156 [label="Enter safe call"];
157 [label="Access variable R|/ext|"];
158 [label="Exit safe call"];
159 [label="Variable declaration: lval <elvis>: R|kotlin/Int?|"];
170 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_43 {
color=blue
160 [label="Enter when branch condition "];
161 [label="Const: Null(null)"];
162 [label="Operator =="];
163 [label="Exit when branch condition"];
171 [label="Enter block"];
172 [label="Access variable R|<local>/s|"];
173 [label="Access variable R|kotlin/String.length|"];
174 [label="Exit block"];
}
subgraph cluster_44 {
color=blue
164 [label="Enter when branch condition else"];
165 [label="Exit when branch condition"];
}
166 [label="Enter when branch result"];
subgraph cluster_45 {
color=blue
167 [label="Enter block"];
168 [label="Access variable R|<local>/<elvis>|"];
169 [label="Exit block"];
}
170 [label="Exit when branch result"];
171 [label="Enter when branch result"];
subgraph cluster_46 {
color=blue
172 [label="Enter block"];
173 [label="Jump: ^test_4 Unit"];
174 [label="Stub" style="filled" fillcolor=gray];
175 [label="Exit block" style="filled" fillcolor=gray];
}
176 [label="Exit when branch result" style="filled" fillcolor=gray];
177 [label="Exit when"];
175 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
178 [label="Variable declaration: lval length: R|kotlin/Int|"];
179 [label="Postponed enter to lambda"];
subgraph cluster_47 {
color=blue
184 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_48 {
color=blue
185 [label="Enter block"];
186 [label="Access variable R|<local>/s|"];
187 [label="Access variable R|kotlin/String.length|"];
188 [label="Exit block"];
}
189 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
180 [label="Postponed exit from lambda"];
181 [label="Function call: R|/runHigherOrder|<R|kotlin/Int|>(...)"];
182 [label="Exit block"];
166 [label="Postponed exit from lambda"];
167 [label="Function call: R|/runHigherOrder|<R|kotlin/Int|>(...)"];
168 [label="Exit block"];
}
183 [label="Exit function test_4" style="filled" fillcolor=red];
169 [label="Exit function test_4" style="filled" fillcolor=red];
}
149 -> {150};
150 -> {151};
151 -> {152};
152 -> {153};
153 -> {154};
154 -> {155};
155 -> {156 158};
154 -> {155 157};
155 -> {156};
156 -> {157};
157 -> {158};
158 -> {159};
158 -> {162 159};
159 -> {160};
160 -> {161};
161 -> {162};
160 -> {169};
160 -> {161} [style=dotted];
161 -> {163} [style=dotted];
162 -> {163};
163 -> {171 164};
163 -> {164};
164 -> {165};
165 -> {166};
165 -> {166 170};
166 -> {167};
167 -> {168};
168 -> {169};
169 -> {170};
170 -> {177};
170 -> {171};
171 -> {172};
172 -> {173};
173 -> {183};
173 -> {174} [style=dotted];
174 -> {175} [style=dotted];
175 -> {176} [style=dotted];
176 -> {177} [style=dotted];
177 -> {178};
178 -> {179};
179 -> {180 184};
180 -> {181};
181 -> {182};
182 -> {183};
184 -> {185};
185 -> {186};
186 -> {187};
187 -> {188};
188 -> {189};
173 -> {174};
174 -> {175};
}

View File

@@ -74,15 +74,7 @@ FILE: returns.kt
}
public final fun test_4(a: R|kotlin/Any?|): R|kotlin/Unit| {
lval s: R|kotlin/String?| = (R|<local>/a| as? R|kotlin/String|)
lval length: R|kotlin/Int| = when (lval <elvis>: R|kotlin/Int?| = R|<local>/s|?.{ $subj$.R|/ext| }) {
==($subj$, Null(null)) -> {
^test_4 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval length: R|kotlin/Int| = R|<local>/s|?.{ $subj$.R|/ext| } ?: ^test_4 Unit
R|/runHigherOrder|<R|kotlin/Int|>(<L> = runHigherOrder@fun <anonymous>(): R|kotlin/Int| {
^ R|<local>/s|.R|kotlin/String.length|
}

View File

@@ -50,61 +50,32 @@ digraph smartcastFromArgument_kt {
subgraph cluster_7 {
color=blue
14 [label="Enter when branch condition "];
subgraph cluster_8 {
color=blue
15 [label="Enter when"];
16 [label="Access variable R|<local>/a|"];
17 [label="Type operator: (R|<local>/a| as? R|A|)"];
18 [label="Variable declaration: lval <elvis>: R|A?|"];
subgraph cluster_9 {
color=blue
19 [label="Enter when branch condition "];
20 [label="Const: Null(null)"];
21 [label="Operator =="];
22 [label="Exit when branch condition"];
}
subgraph cluster_10 {
color=blue
23 [label="Enter when branch condition else"];
24 [label="Exit when branch condition"];
}
25 [label="Enter when branch result"];
subgraph cluster_11 {
color=blue
26 [label="Enter block"];
27 [label="Access variable R|<local>/<elvis>|"];
28 [label="Exit block"];
}
29 [label="Exit when branch result"];
30 [label="Enter when branch result"];
subgraph cluster_12 {
color=blue
31 [label="Enter block"];
32 [label="Jump: ^test Unit"];
33 [label="Stub" style="filled" fillcolor=gray];
34 [label="Exit block" style="filled" fillcolor=gray];
}
35 [label="Exit when branch result" style="filled" fillcolor=gray];
36 [label="Exit when"];
}
37 [label="Function call: R|/takeA|(...)"];
38 [label="Exit when branch condition"];
15 [label="Access variable R|<local>/a|"];
16 [label="Type operator: (R|<local>/a| as? R|A|)"];
17 [label="Exit lhs of ?:"];
18 [label="Enter rhs of ?:"];
19 [label="Jump: ^test Unit"];
20 [label="Stub" style="filled" fillcolor=gray];
21 [label="Lhs of ?: is not null"];
22 [label="Exit ?:"];
23 [label="Function call: R|/takeA|(...)"];
24 [label="Exit when branch condition"];
}
39 [label="Synthetic else branch"];
40 [label="Enter when branch result"];
subgraph cluster_13 {
25 [label="Synthetic else branch"];
26 [label="Enter when branch result"];
subgraph cluster_8 {
color=blue
41 [label="Enter block"];
42 [label="Access variable R|<local>/a|"];
43 [label="Function call: R|<local>/a|.R|/A.foo|()"];
44 [label="Exit block"];
27 [label="Enter block"];
28 [label="Access variable R|<local>/a|"];
29 [label="Function call: R|<local>/a|.R|/A.foo|()"];
30 [label="Exit block"];
}
45 [label="Exit when branch result"];
46 [label="Exit when"];
31 [label="Exit when branch result"];
32 [label="Exit when"];
}
47 [label="Exit block"];
33 [label="Exit block"];
}
48 [label="Exit function test" style="filled" fillcolor=red];
34 [label="Exit function test" style="filled" fillcolor=red];
}
11 -> {12};
12 -> {13};
@@ -112,37 +83,23 @@ digraph smartcastFromArgument_kt {
14 -> {15};
15 -> {16};
16 -> {17};
17 -> {18};
17 -> {21 18};
18 -> {19};
19 -> {20};
20 -> {21};
19 -> {34};
19 -> {20} [style=dotted];
20 -> {22} [style=dotted];
21 -> {22};
22 -> {30 23};
22 -> {23};
23 -> {24};
24 -> {25};
25 -> {26};
24 -> {26 25};
25 -> {32};
26 -> {27};
27 -> {28};
28 -> {29};
29 -> {36};
29 -> {30};
30 -> {31};
31 -> {32};
32 -> {48};
32 -> {33} [style=dotted];
33 -> {34} [style=dotted];
34 -> {35} [style=dotted];
35 -> {36} [style=dotted];
36 -> {37};
37 -> {38};
38 -> {40 39};
39 -> {46};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {44};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {48};
32 -> {33};
33 -> {34};
}

View File

@@ -8,15 +8,7 @@ FILE: smartcastFromArgument.kt
}
public final fun test(a: R|kotlin/Any|): R|kotlin/Unit| {
when () {
R|/takeA|(when (lval <elvis>: R|A?| = (R|<local>/a| as? R|A|)) {
==($subj$, Null(null)) -> {
^test Unit
}
else -> {
R|<local>/<elvis>|
}
}
) -> {
R|/takeA|((R|<local>/a| as? R|A|) ?: ^test Unit) -> {
R|<local>/a|.R|/A.foo|()
}
}

View File

@@ -0,0 +1,250 @@
digraph lambdaInWhenBranch_kt {
graph [nodesep=3]
node [shape=box penwidth=2]
edge [penwidth=2]
subgraph cluster_0 {
color=red
0 [label="Enter class Sealed" style="filled" fillcolor=red];
1 [label="Exit class Sealed" style="filled" fillcolor=red];
}
0 -> {1} [color=green];
subgraph cluster_1 {
color=red
2 [label="Enter function <init>" style="filled" fillcolor=red];
3 [label="Delegated constructor call: super<R|kotlin/Any|>()"];
4 [label="Exit function <init>" style="filled" fillcolor=red];
}
2 -> {3};
3 -> {4};
subgraph cluster_2 {
color=red
5 [label="Enter class SubClass1" style="filled" fillcolor=red];
subgraph cluster_3 {
color=blue
7 [label="Enter property" style="filled" fillcolor=red];
8 [label="Access variable R|<local>/t|"];
9 [label="Exit property" style="filled" fillcolor=red];
}
6 [label="Exit class SubClass1" style="filled" fillcolor=red];
}
5 -> {7} [color=green];
7 -> {8};
8 -> {9};
9 -> {6} [color=green];
subgraph cluster_4 {
color=red
10 [label="Enter function <init>" style="filled" fillcolor=red];
11 [label="Delegated constructor call: super<R|Sealed|>()"];
12 [label="Exit function <init>" style="filled" fillcolor=red];
}
10 -> {11};
11 -> {12};
subgraph cluster_5 {
color=red
13 [label="Enter function getter" style="filled" fillcolor=red];
14 [label="Exit function getter" style="filled" fillcolor=red];
}
13 -> {14};
subgraph cluster_6 {
color=red
15 [label="Enter function component1" style="filled" fillcolor=red];
16 [label="Exit function component1" style="filled" fillcolor=red];
}
15 -> {16};
subgraph cluster_7 {
color=red
17 [label="Enter function copy" style="filled" fillcolor=red];
subgraph cluster_8 {
color=blue
19 [label="Enter default value of t" style="filled" fillcolor=red];
20 [label="Access variable R|/SubClass1.t|"];
21 [label="Exit default value of t" style="filled" fillcolor=red];
}
18 [label="Exit function copy" style="filled" fillcolor=red];
}
17 -> {19 18};
19 -> {20};
20 -> {21};
subgraph cluster_9 {
color=red
22 [label="Enter class SubClass2" style="filled" fillcolor=red];
23 [label="Exit class SubClass2" style="filled" fillcolor=red];
}
22 -> {23} [color=green];
subgraph cluster_10 {
color=red
24 [label="Enter function <init>" style="filled" fillcolor=red];
25 [label="Delegated constructor call: super<R|Sealed|>()"];
26 [label="Exit function <init>" style="filled" fillcolor=red];
}
24 -> {25};
25 -> {26};
subgraph cluster_11 {
color=red
27 [label="Enter function copy" style="filled" fillcolor=red];
28 [label="Exit function copy" style="filled" fillcolor=red];
}
27 -> {28};
subgraph cluster_12 {
color=red
29 [label="Enter function foo" style="filled" fillcolor=red];
subgraph cluster_13 {
color=blue
30 [label="Enter block"];
subgraph cluster_14 {
color=blue
31 [label="Enter when"];
32 [label="Access variable R|<local>/p|"];
subgraph cluster_15 {
color=blue
33 [label="Enter when branch condition "];
34 [label="Type operator: ($subj$ is R|SubClass1|)"];
35 [label="Exit when branch condition"];
}
subgraph cluster_16 {
color=blue
36 [label="Enter when branch condition "];
37 [label="Type operator: ($subj$ is R|SubClass2|)"];
38 [label="Exit when branch condition"];
}
39 [label="Enter when branch result"];
subgraph cluster_17 {
color=blue
40 [label="Enter block"];
41 [label="Const: String()"];
42 [label="Exit block"];
}
43 [label="Exit when branch result"];
44 [label="Enter when branch result"];
subgraph cluster_18 {
color=blue
45 [label="Enter block"];
46 [label="Const: String()"];
47 [label="Postponed enter to lambda"];
subgraph cluster_19 {
color=blue
78 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
subgraph cluster_20 {
color=blue
79 [label="Enter block"];
80 [label="Access variable R|<local>/it|"];
81 [label="Exit block"];
}
82 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
48 [label="Postponed exit from lambda"];
49 [label="Function call: String().R|kotlin/let|<R|kotlin/String|, R|kotlin/String|>(...)"];
50 [label="Exit block"];
}
51 [label="Exit when branch result"];
52 [label="Exit when"];
}
53 [label="Access variable R|<local>/p|"];
54 [label="Access variable <Unresolved name: t>#"];
subgraph cluster_21 {
color=blue
55 [label="Enter when"];
56 [label="Access variable R|<local>/p|"];
subgraph cluster_22 {
color=blue
57 [label="Enter when branch condition "];
58 [label="Type operator: ($subj$ is R|SubClass1|)"];
59 [label="Exit when branch condition"];
}
subgraph cluster_23 {
color=blue
60 [label="Enter when branch condition "];
61 [label="Type operator: ($subj$ is R|SubClass2|)"];
62 [label="Exit when branch condition"];
}
63 [label="Enter when branch result"];
subgraph cluster_24 {
color=blue
64 [label="Enter block"];
65 [label="Const: String(2)"];
66 [label="Exit block"];
}
67 [label="Exit when branch result"];
68 [label="Enter when branch result"];
subgraph cluster_25 {
color=blue
69 [label="Enter block"];
70 [label="Access variable R|<local>/p|"];
71 [label="Access variable R|/SubClass1.t|"];
72 [label="Exit block"];
}
73 [label="Exit when branch result"];
74 [label="Exit when"];
}
75 [label="Access variable R|kotlin/String.length|"];
76 [label="Exit block"];
}
77 [label="Exit function foo" style="filled" fillcolor=red];
}
29 -> {30};
30 -> {31};
31 -> {32};
32 -> {33};
33 -> {34};
34 -> {35};
35 -> {44 36};
36 -> {37};
37 -> {38};
38 -> {39};
39 -> {40};
40 -> {41};
41 -> {42};
42 -> {43};
43 -> {52};
44 -> {45};
45 -> {46};
46 -> {47};
47 -> {78};
47 -> {48} [color=red];
48 -> {49};
49 -> {50};
50 -> {51};
51 -> {52};
52 -> {53};
53 -> {54};
54 -> {55};
55 -> {56};
56 -> {57};
57 -> {58};
58 -> {59};
59 -> {68 60};
60 -> {61};
61 -> {62};
62 -> {63};
63 -> {64};
64 -> {65};
65 -> {66};
66 -> {67};
67 -> {74};
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
72 -> {73};
73 -> {74};
74 -> {75};
75 -> {76};
76 -> {77};
78 -> {79};
79 -> {80};
80 -> {81};
81 -> {82};
82 -> {48} [color=green];
}

View File

@@ -0,0 +1,23 @@
// ISSUE: KT-39080
// !DUMP_CFG
private sealed class Sealed
private data class SubClass1(val t: String) : Sealed()
private data class SubClass2 : Sealed()
private fun foo(p: Sealed) {
when (p) {
is SubClass1 -> "".let {
it
}
is SubClass2 -> ""
}
p.<!UNRESOLVED_REFERENCE!>t<!> // should not be resolved, but it has a smartcast to SubClass1 because of the lambda
when (p) {
is SubClass1 -> p.t
is SubClass2 -> "2"
}.length // should be resolved, but when is not considered as sealed because type of p is not a sealed class
}

View File

@@ -0,0 +1,52 @@
FILE: lambdaInWhenBranch.kt
private sealed class Sealed : R|kotlin/Any| {
private constructor(): R|Sealed| {
super<R|kotlin/Any|>()
}
}
private final data class SubClass1 : R|Sealed| {
public[private] constructor(t: R|kotlin/String|): R|SubClass1| {
super<R|Sealed|>()
}
public[private] final val t: R|kotlin/String| = R|<local>/t|
public get(): R|kotlin/String|
public[private] final fun component1(): R|kotlin/String|
public[private] final fun copy(t: R|kotlin/String| = this@R|/SubClass1|.R|/SubClass1.t|): R|SubClass1|
}
private final data class SubClass2 : R|Sealed| {
public[private] constructor(): R|SubClass2| {
super<R|Sealed|>()
}
public[private] final fun copy(): R|SubClass2|
}
private final fun foo(p: R|Sealed|): R|kotlin/Unit| {
when (R|<local>/p|) {
($subj$ is R|SubClass1|) -> {
String().R|kotlin/let|<R|kotlin/String|, R|kotlin/String|>(<L> = let@fun <anonymous>(it: R|kotlin/String|): R|kotlin/String| <kind=EXACTLY_ONCE> {
^ R|<local>/it|
}
)
}
($subj$ is R|SubClass2|) -> {
String()
}
}
R|<local>/p|.<Unresolved name: t>#
when (R|<local>/p|) {
($subj$ is R|SubClass1|) -> {
R|<local>/p|.R|/SubClass1.t|
}
($subj$ is R|SubClass2|) -> {
String(2)
}
}
.R|kotlin/String.length|
}

File diff suppressed because it is too large Load Diff

View File

@@ -86,15 +86,7 @@ FILE: nullability.kt
R|<local>/x|.<Inapplicable(WRONG_RECEIVER): [/A.foo]>#()
}
public final fun test_3(x: R|A?|): R|kotlin/Unit| {
when (lval <elvis>: R|A?| = R|<local>/x|) {
==($subj$, Null(null)) -> {
^test_3 Unit
}
else -> {
R|<local>/<elvis>|
}
}
R|<local>/x| ?: ^test_3 Unit
R|<local>/x|.R|/A.foo|()
}
public final fun test_4(x: R|A?|): R|kotlin/Unit| {
@@ -117,15 +109,7 @@ FILE: nullability.kt
}
public final fun test_6(q: R|Q?|): R|kotlin/Unit| {
when (lval <elvis>: R|kotlin/Int?| = R|<local>/q|?.{ $subj$.R|/Q.data| }?.{ $subj$.R|/MyData.s| }?.{ $subj$.R|kotlin/Int.inc|() }) {
==($subj$, Null(null)) -> {
^test_6 Unit
}
else -> {
R|<local>/<elvis>|
}
}
R|<local>/q|?.{ $subj$.R|/Q.data| }?.{ $subj$.R|/MyData.s| }?.{ $subj$.R|kotlin/Int.inc|() } ?: ^test_6 Unit
R|<local>/q|.R|/Q.data|
R|<local>/q|.R|/Q.data|.<Inapplicable(WRONG_RECEIVER): [/MyData.s]>#
R|<local>/q|.R|/Q.data|.<Inapplicable(WRONG_RECEIVER): [/MyData.s]>#.<Unresolved name: inc>#()

View File

@@ -198,164 +198,173 @@ digraph assignSafeCall_kt {
subgraph cluster_19 {
color=blue
68 [label="Enter block"];
subgraph cluster_20 {
color=blue
69 [label="Enter when"];
70 [label="Access variable R|<local>/x|"];
71 [label="Type operator: (R|<local>/x| as? R|A|)"];
72 [label="Variable declaration: lval <elvis>: R|A?|"];
subgraph cluster_21 {
color=blue
73 [label="Enter when branch condition "];
74 [label="Const: Null(null)"];
75 [label="Operator =="];
76 [label="Exit when branch condition"];
}
subgraph cluster_22 {
color=blue
77 [label="Enter when branch condition else"];
78 [label="Exit when branch condition"];
}
79 [label="Enter when branch result"];
subgraph cluster_23 {
color=blue
80 [label="Enter block"];
81 [label="Access variable R|<local>/<elvis>|"];
82 [label="Exit block"];
}
83 [label="Exit when branch result"];
84 [label="Enter when branch result"];
subgraph cluster_24 {
color=blue
85 [label="Enter block"];
86 [label="Jump: ^test_3 Unit"];
87 [label="Stub" style="filled" fillcolor=gray];
88 [label="Exit block" style="filled" fillcolor=gray];
}
89 [label="Exit when branch result" style="filled" fillcolor=gray];
90 [label="Exit when"];
}
91 [label="Variable declaration: lval a: R|A|"];
92 [label="Access variable R|<local>/a|"];
93 [label="Function call: R|<local>/a|.R|/A.foo|()"];
94 [label="Access variable R|<local>/x|"];
95 [label="Function call: R|<local>/x|.R|/A.foo|()"];
96 [label="Exit block"];
69 [label="Access variable R|<local>/x|"];
70 [label="Type operator: (R|<local>/x| as? R|A|)"];
71 [label="Exit lhs of ?:"];
72 [label="Enter rhs of ?:"];
73 [label="Jump: ^test_3 Unit"];
74 [label="Stub" style="filled" fillcolor=gray];
75 [label="Lhs of ?: is not null"];
76 [label="Exit ?:"];
77 [label="Variable declaration: lval a: R|A|"];
78 [label="Access variable R|<local>/a|"];
79 [label="Function call: R|<local>/a|.R|/A.foo|()"];
80 [label="Access variable R|<local>/x|"];
81 [label="Function call: R|<local>/x|.R|/A.foo|()"];
82 [label="Exit block"];
}
97 [label="Exit function test_3" style="filled" fillcolor=red];
83 [label="Exit function test_3" style="filled" fillcolor=red];
}
67 -> {68};
68 -> {69};
69 -> {70};
70 -> {71};
71 -> {72};
71 -> {75 72};
72 -> {73};
73 -> {74};
74 -> {75};
73 -> {83};
73 -> {74} [style=dotted];
74 -> {76} [style=dotted];
75 -> {76};
76 -> {84 77};
76 -> {77};
77 -> {78};
78 -> {79};
79 -> {80};
80 -> {81};
81 -> {82};
82 -> {83};
83 -> {90};
84 -> {85};
85 -> {86};
86 -> {97};
86 -> {87} [style=dotted];
87 -> {88} [style=dotted];
88 -> {89} [style=dotted];
89 -> {90} [style=dotted];
subgraph cluster_20 {
color=red
84 [label="Enter class B" style="filled" fillcolor=red];
85 [label="Exit class B" style="filled" fillcolor=red];
}
84 -> {85} [color=green];
subgraph cluster_21 {
color=red
86 [label="Enter function foo" style="filled" fillcolor=red];
87 [label="Exit function foo" style="filled" fillcolor=red];
}
86 -> {87};
subgraph cluster_22 {
color=red
88 [label="Enter function getter" style="filled" fillcolor=red];
89 [label="Exit function getter" style="filled" fillcolor=red];
}
88 -> {89};
subgraph cluster_23 {
color=red
90 [label="Enter function bar" style="filled" fillcolor=red];
91 [label="Exit function bar" style="filled" fillcolor=red];
}
90 -> {91};
91 -> {92};
subgraph cluster_24 {
color=red
92 [label="Enter function test_1" style="filled" fillcolor=red];
subgraph cluster_25 {
color=blue
93 [label="Enter block"];
94 [label="Access variable R|<local>/a|"];
95 [label="Enter safe call"];
96 [label="Access variable R|/B.x|"];
97 [label="Exit safe call"];
98 [label="Variable declaration: lval x: R|kotlin/Int?|"];
subgraph cluster_26 {
color=blue
99 [label="Enter when"];
subgraph cluster_27 {
color=blue
100 [label="Enter when branch condition "];
101 [label="Access variable R|<local>/x|"];
102 [label="Const: Null(null)"];
103 [label="Operator !="];
104 [label="Exit when branch condition"];
}
105 [label="Synthetic else branch"];
106 [label="Enter when branch result"];
subgraph cluster_28 {
color=blue
107 [label="Enter block"];
108 [label="Access variable R|<local>/a|"];
109 [label="Function call: R|<local>/a|.R|/B.bar|()"];
110 [label="Exit block"];
}
111 [label="Exit when branch result"];
112 [label="Exit when"];
}
113 [label="Exit block"];
}
114 [label="Exit function test_1" style="filled" fillcolor=red];
}
92 -> {93};
93 -> {94};
94 -> {95};
94 -> {95 97};
95 -> {96};
96 -> {97};
subgraph cluster_25 {
color=red
98 [label="Enter class B" style="filled" fillcolor=red];
99 [label="Exit class B" style="filled" fillcolor=red];
}
98 -> {99} [color=green];
subgraph cluster_26 {
color=red
100 [label="Enter function foo" style="filled" fillcolor=red];
101 [label="Exit function foo" style="filled" fillcolor=red];
}
97 -> {98};
98 -> {99};
99 -> {100};
100 -> {101};
subgraph cluster_27 {
color=red
102 [label="Enter function getter" style="filled" fillcolor=red];
103 [label="Exit function getter" style="filled" fillcolor=red];
}
101 -> {102};
102 -> {103};
subgraph cluster_28 {
color=red
104 [label="Enter function bar" style="filled" fillcolor=red];
105 [label="Exit function bar" style="filled" fillcolor=red];
}
104 -> {105};
subgraph cluster_29 {
color=red
106 [label="Enter function test_1" style="filled" fillcolor=red];
subgraph cluster_30 {
color=blue
107 [label="Enter block"];
108 [label="Access variable R|<local>/a|"];
109 [label="Enter safe call"];
110 [label="Access variable R|/B.x|"];
111 [label="Exit safe call"];
112 [label="Variable declaration: lval x: R|kotlin/Int?|"];
subgraph cluster_31 {
color=blue
113 [label="Enter when"];
subgraph cluster_32 {
color=blue
114 [label="Enter when branch condition "];
115 [label="Access variable R|<local>/x|"];
116 [label="Const: Null(null)"];
117 [label="Operator !="];
118 [label="Exit when branch condition"];
}
119 [label="Synthetic else branch"];
120 [label="Enter when branch result"];
subgraph cluster_33 {
color=blue
121 [label="Enter block"];
122 [label="Access variable R|<local>/a|"];
123 [label="Function call: R|<local>/a|.R|/B.bar|()"];
124 [label="Exit block"];
}
125 [label="Exit when branch result"];
126 [label="Exit when"];
}
127 [label="Exit block"];
}
128 [label="Exit function test_1" style="filled" fillcolor=red];
}
103 -> {104};
104 -> {106 105};
105 -> {112};
106 -> {107};
107 -> {108};
108 -> {109 111};
108 -> {109};
109 -> {110};
110 -> {111};
111 -> {112};
112 -> {113};
113 -> {114};
114 -> {115};
subgraph cluster_29 {
color=red
115 [label="Enter function test_2" style="filled" fillcolor=red];
subgraph cluster_30 {
color=blue
116 [label="Enter block"];
117 [label="Access variable R|<local>/a|"];
118 [label="Enter safe call"];
119 [label="Function call: $subj$.R|/B.foo|()"];
120 [label="Exit safe call"];
121 [label="Variable declaration: lval x: R|kotlin/Int?|"];
subgraph cluster_31 {
color=blue
122 [label="Enter when"];
subgraph cluster_32 {
color=blue
123 [label="Enter when branch condition "];
124 [label="Access variable R|<local>/x|"];
125 [label="Const: Null(null)"];
126 [label="Operator !="];
127 [label="Exit when branch condition"];
}
128 [label="Synthetic else branch"];
129 [label="Enter when branch result"];
subgraph cluster_33 {
color=blue
130 [label="Enter block"];
131 [label="Access variable R|<local>/a|"];
132 [label="Function call: R|<local>/a|.R|/B.bar|()"];
133 [label="Exit block"];
}
134 [label="Exit when branch result"];
135 [label="Exit when"];
}
136 [label="Exit block"];
}
137 [label="Exit function test_2" style="filled" fillcolor=red];
}
115 -> {116};
116 -> {117};
117 -> {118};
118 -> {120 119};
119 -> {126};
117 -> {118 120};
118 -> {119};
119 -> {120};
120 -> {121};
121 -> {122};
122 -> {123};
@@ -363,151 +372,56 @@ digraph assignSafeCall_kt {
124 -> {125};
125 -> {126};
126 -> {127};
127 -> {128};
subgraph cluster_34 {
color=red
129 [label="Enter function test_2" style="filled" fillcolor=red];
subgraph cluster_35 {
color=blue
130 [label="Enter block"];
131 [label="Access variable R|<local>/a|"];
132 [label="Enter safe call"];
133 [label="Function call: $subj$.R|/B.foo|()"];
134 [label="Exit safe call"];
135 [label="Variable declaration: lval x: R|kotlin/Int?|"];
subgraph cluster_36 {
color=blue
136 [label="Enter when"];
subgraph cluster_37 {
color=blue
137 [label="Enter when branch condition "];
138 [label="Access variable R|<local>/x|"];
139 [label="Const: Null(null)"];
140 [label="Operator !="];
141 [label="Exit when branch condition"];
}
142 [label="Synthetic else branch"];
143 [label="Enter when branch result"];
subgraph cluster_38 {
color=blue
144 [label="Enter block"];
145 [label="Access variable R|<local>/a|"];
146 [label="Function call: R|<local>/a|.R|/B.bar|()"];
147 [label="Exit block"];
}
148 [label="Exit when branch result"];
149 [label="Exit when"];
}
150 [label="Exit block"];
}
151 [label="Exit function test_2" style="filled" fillcolor=red];
}
127 -> {129 128};
128 -> {135};
129 -> {130};
130 -> {131};
131 -> {132 134};
131 -> {132};
132 -> {133};
133 -> {134};
134 -> {135};
135 -> {136};
136 -> {137};
137 -> {138};
subgraph cluster_34 {
color=red
138 [label="Enter function test_3" style="filled" fillcolor=red];
subgraph cluster_35 {
color=blue
139 [label="Enter block"];
140 [label="Access variable R|<local>/x|"];
141 [label="Type operator: (R|<local>/x| as? R|B|)"];
142 [label="Exit lhs of ?:"];
143 [label="Enter rhs of ?:"];
144 [label="Jump: ^test_3 Unit"];
145 [label="Stub" style="filled" fillcolor=gray];
146 [label="Lhs of ?: is not null"];
147 [label="Exit ?:"];
148 [label="Variable declaration: lval a: R|B|"];
149 [label="Access variable R|<local>/a|"];
150 [label="Function call: R|<local>/a|.R|/B.foo|()"];
151 [label="Access variable R|<local>/x|"];
152 [label="Function call: R|<local>/x|.R|/B.foo|()"];
153 [label="Exit block"];
}
154 [label="Exit function test_3" style="filled" fillcolor=red];
}
138 -> {139};
139 -> {140};
140 -> {141};
141 -> {143 142};
142 -> {149};
141 -> {142};
142 -> {146 143};
143 -> {144};
144 -> {145};
145 -> {146};
144 -> {154};
144 -> {145} [style=dotted];
145 -> {147} [style=dotted];
146 -> {147};
147 -> {148};
148 -> {149};
149 -> {150};
150 -> {151};
subgraph cluster_39 {
color=red
152 [label="Enter function test_3" style="filled" fillcolor=red];
subgraph cluster_40 {
color=blue
153 [label="Enter block"];
subgraph cluster_41 {
color=blue
154 [label="Enter when"];
155 [label="Access variable R|<local>/x|"];
156 [label="Type operator: (R|<local>/x| as? R|B|)"];
157 [label="Variable declaration: lval <elvis>: R|B?|"];
subgraph cluster_42 {
color=blue
158 [label="Enter when branch condition "];
159 [label="Const: Null(null)"];
160 [label="Operator =="];
161 [label="Exit when branch condition"];
}
subgraph cluster_43 {
color=blue
162 [label="Enter when branch condition else"];
163 [label="Exit when branch condition"];
}
164 [label="Enter when branch result"];
subgraph cluster_44 {
color=blue
165 [label="Enter block"];
166 [label="Access variable R|<local>/<elvis>|"];
167 [label="Exit block"];
}
168 [label="Exit when branch result"];
169 [label="Enter when branch result"];
subgraph cluster_45 {
color=blue
170 [label="Enter block"];
171 [label="Jump: ^test_3 Unit"];
172 [label="Stub" style="filled" fillcolor=gray];
173 [label="Exit block" style="filled" fillcolor=gray];
}
174 [label="Exit when branch result" style="filled" fillcolor=gray];
175 [label="Exit when"];
}
176 [label="Variable declaration: lval a: R|B|"];
177 [label="Access variable R|<local>/a|"];
178 [label="Function call: R|<local>/a|.R|/B.foo|()"];
179 [label="Access variable R|<local>/x|"];
180 [label="Function call: R|<local>/x|.R|/B.foo|()"];
181 [label="Exit block"];
}
182 [label="Exit function test_3" style="filled" fillcolor=red];
}
151 -> {152};
152 -> {153};
153 -> {154};
154 -> {155};
155 -> {156};
156 -> {157};
157 -> {158};
158 -> {159};
159 -> {160};
160 -> {161};
161 -> {169 162};
162 -> {163};
163 -> {164};
164 -> {165};
165 -> {166};
166 -> {167};
167 -> {168};
168 -> {175};
169 -> {170};
170 -> {171};
171 -> {182};
171 -> {172} [style=dotted];
172 -> {173} [style=dotted];
173 -> {174} [style=dotted];
174 -> {175} [style=dotted];
175 -> {176};
176 -> {177};
177 -> {178};
178 -> {179};
179 -> {180};
180 -> {181};
181 -> {182};
}

View File

@@ -34,15 +34,7 @@ FILE: assignSafeCall.kt
}
public final fun test_3(x: R|kotlin/Any?|): R|kotlin/Unit| {
lval a: R|A| = when (lval <elvis>: R|A?| = (R|<local>/x| as? R|A|)) {
==($subj$, Null(null)) -> {
^test_3 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval a: R|A| = (R|<local>/x| as? R|A|) ?: ^test_3 Unit
R|<local>/a|.R|/A.foo|()
R|<local>/x|.R|/A.foo|()
}
@@ -74,15 +66,7 @@ FILE: assignSafeCall.kt
}
public final fun test_3(x: R|kotlin/Any?|): R|kotlin/Unit| {
lval a: R|B| = when (lval <elvis>: R|B?| = (R|<local>/x| as? R|B|)) {
==($subj$, Null(null)) -> {
^test_3 Unit
}
else -> {
R|<local>/<elvis>|
}
}
lval a: R|B| = (R|<local>/x| as? R|B|) ?: ^test_3 Unit
R|<local>/a|.R|/B.foo|()
R|<local>/x|.R|/B.foo|()
}

View File

@@ -0,0 +1,6 @@
// FULL_JDK
// ISSUE: KT-39044
fun test(t: Throwable) {
t.fillInStackTrace()
}

View File

@@ -0,0 +1,4 @@
FILE: fillInStackTrace.kt
public final fun test(t: R|kotlin/Throwable|): R|kotlin/Unit| {
R|<local>/t|.R|java/lang/Throwable.fillInStackTrace|()
}

View File

@@ -0,0 +1,18 @@
// ISSUE: KT-39074
interface A
interface B : A {
fun bar()
}
fun <K : A> materialize(): K? = null!!
fun foo(b: B, cond: Boolean) {
val x = // inferred as A
if (cond)
b
else
materialize() ?: return
x.bar()
}

View File

@@ -0,0 +1,22 @@
FILE: ifElvisReturn.kt
public abstract interface A : R|kotlin/Any| {
}
public abstract interface B : R|A| {
public abstract fun bar(): R|kotlin/Unit|
}
public final fun <K : R|A|> materialize(): R|K?| {
^materialize Null(null)!!
}
public final fun foo(b: R|B|, cond: R|kotlin/Boolean|): R|kotlin/Unit| {
lval x: R|B| = when () {
R|<local>/cond| -> {
R|<local>/b|
}
else -> {
R|/materialize|<R|kotlin/Nothing|>() ?: ^foo Unit
}
}
R|<local>/x|.R|/B.bar|()
}

View File

@@ -1,15 +1,7 @@
FILE: MapCompute.kt
public final fun <D> R|kotlin/collections/MutableMap<kotlin/String, kotlin/collections/MutableSet<D>>|.initAndAdd(key: R|kotlin/String|, value: R|D|): R|kotlin/Unit| {
this@R|/initAndAdd|.R|FakeOverride<kotlin/collections/MutableMap.compute: R|kotlin/collections/MutableSet<D>?|>|(R|<local>/key|, <L> = compute@fun <anonymous>(_: R|ft<kotlin/String, kotlin/String?>!|, maybeValues: R|ft<kotlin/collections/MutableSet<D>, kotlin/collections/MutableSet<D>?>!|): R|ft<kotlin/collections/MutableSet<D>, kotlin/collections/MutableSet<D>?>!| {
lval setOfValues: R|kotlin/collections/MutableSet<D>| = when (lval <elvis>: R|ft<kotlin/collections/MutableSet<D>, kotlin/collections/MutableSet<D>?>!| = R|<local>/maybeValues|) {
==($subj$, Null(null)) -> {
R|kotlin/collections/mutableSetOf|<R|D|>()
}
else -> {
R|<local>/<elvis>|
}
}
lval setOfValues: R|kotlin/collections/MutableSet<D>| = R|<local>/maybeValues| ?: R|kotlin/collections/mutableSetOf|<R|D|>()
R|<local>/setOfValues|.R|FakeOverride<kotlin/collections/MutableSet.add: R|kotlin/Boolean|>|(R|<local>/value|)
^ R|<local>/setOfValues|
}

View File

@@ -0,0 +1,13 @@
// FILE: JavaClass.java
import org.jetbrains.annotations.Nullable;
public class JavaClass {
private String myFoo = "";
public String getFoo() { return myFoo; }
public void setFoo(@Nullable String s) { myFoo = s; }
}
// FILE: main.kt
fun main(j: JavaClass) {
j.foo += "OK"
}

View File

@@ -0,0 +1,4 @@
FILE: main.kt
public final fun main(j: R|JavaClass|): R|kotlin/Unit| {
R|<local>/j|.R|/JavaClass.foo| = R|<local>/j|.R|/JavaClass.foo|.R|kotlin/String.plus|(String(OK))
}

View File

@@ -243,6 +243,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/lambdaArgInScopeFunction.kt");
}
@TestMetadata("lambdaInLhsOfTypeOperatorCall.kt")
public void testLambdaInLhsOfTypeOperatorCall() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/lambdaInLhsOfTypeOperatorCall.kt");
}
@TestMetadata("lambdaPropertyTypeInference.kt")
public void testLambdaPropertyTypeInference() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/lambdaPropertyTypeInference.kt");
@@ -648,6 +653,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
public void testTypeAliasWithNotNullBound() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/typeAliasWithNotNullBound.kt");
}
@TestMetadata("uselessMultipleBounds.kt")
public void testUselessMultipleBounds() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/uselessMultipleBounds.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
@@ -1459,6 +1469,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/capturedTypeForJavaTypeParameter.kt");
}
@TestMetadata("coercionToUnitWithEarlyReturn.kt")
public void testCoercionToUnitWithEarlyReturn() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/coercionToUnitWithEarlyReturn.kt");
}
@TestMetadata("definitelyNotNullIntersectionType.kt")
public void testDefinitelyNotNullIntersectionType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/definitelyNotNullIntersectionType.kt");
@@ -1469,6 +1484,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/extensionCallableReferences.kt");
}
@TestMetadata("integerLiteralAsComparable.kt")
public void testIntegerLiteralAsComparable() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/integerLiteralAsComparable.kt");
}
@TestMetadata("intersectionTypesInConstraints.kt")
public void testIntersectionTypesInConstraints() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/intersectionTypesInConstraints.kt");
@@ -1479,6 +1499,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaAsReturnStatementOfLambda.kt");
}
@TestMetadata("lambdaInElvis.kt")
public void testLambdaInElvis() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt");
}
@TestMetadata("nestedExtensionFunctionType.kt")
public void testNestedExtensionFunctionType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nestedExtensionFunctionType.kt");
@@ -2075,6 +2100,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/inPlaceLambdas.kt");
}
@TestMetadata("lambdaInWhenBranch.kt")
public void testLambdaInWhenBranch() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt");
}
@TestMetadata("smartcastOnLambda.kt")
public void testSmartcastOnLambda() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/smartcastOnLambda.kt");

View File

@@ -243,6 +243,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/lambdaArgInScopeFunction.kt");
}
@TestMetadata("lambdaInLhsOfTypeOperatorCall.kt")
public void testLambdaInLhsOfTypeOperatorCall() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/lambdaInLhsOfTypeOperatorCall.kt");
}
@TestMetadata("lambdaPropertyTypeInference.kt")
public void testLambdaPropertyTypeInference() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/lambdaPropertyTypeInference.kt");
@@ -648,6 +653,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
public void testTypeAliasWithNotNullBound() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/typeAliasWithNotNullBound.kt");
}
@TestMetadata("uselessMultipleBounds.kt")
public void testUselessMultipleBounds() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/uselessMultipleBounds.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
@@ -1459,6 +1469,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/inference/capturedTypeForJavaTypeParameter.kt");
}
@TestMetadata("coercionToUnitWithEarlyReturn.kt")
public void testCoercionToUnitWithEarlyReturn() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/coercionToUnitWithEarlyReturn.kt");
}
@TestMetadata("definitelyNotNullIntersectionType.kt")
public void testDefinitelyNotNullIntersectionType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/definitelyNotNullIntersectionType.kt");
@@ -1469,6 +1484,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/inference/extensionCallableReferences.kt");
}
@TestMetadata("integerLiteralAsComparable.kt")
public void testIntegerLiteralAsComparable() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/integerLiteralAsComparable.kt");
}
@TestMetadata("intersectionTypesInConstraints.kt")
public void testIntersectionTypesInConstraints() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/intersectionTypesInConstraints.kt");
@@ -1479,6 +1499,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaAsReturnStatementOfLambda.kt");
}
@TestMetadata("lambdaInElvis.kt")
public void testLambdaInElvis() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/lambdaInElvis.kt");
}
@TestMetadata("nestedExtensionFunctionType.kt")
public void testNestedExtensionFunctionType() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/inference/nestedExtensionFunctionType.kt");
@@ -2075,6 +2100,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/inPlaceLambdas.kt");
}
@TestMetadata("lambdaInWhenBranch.kt")
public void testLambdaInWhenBranch() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/lambdaInWhenBranch.kt");
}
@TestMetadata("smartcastOnLambda.kt")
public void testSmartcastOnLambda() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/lambdas/smartcastOnLambda.kt");

View File

@@ -108,6 +108,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/factoryFunctionOverloads.kt");
}
@TestMetadata("fillInStackTrace.kt")
public void testFillInStackTrace() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/fillInStackTrace.kt");
}
@TestMetadata("functionAndFunctionN.kt")
public void testFunctionAndFunctionN() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/functionAndFunctionN.kt");
@@ -706,6 +711,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
public void testFlexibleTypeInSystem() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/flexibleTypeInSystem.kt");
}
@TestMetadata("ifElvisReturn.kt")
public void testIfElvisReturn() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/inference/ifElvisReturn.kt");
}
}
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k")
@@ -860,6 +870,11 @@ public class FirDiagnosticsWithStdlibTestGenerated extends AbstractFirDiagnostic
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/KotlinClassParameterGeneric.kt");
}
@TestMetadata("kt39076.kt")
public void testKt39076() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/kt39076.kt");
}
@TestMetadata("LoggerInstance.kt")
public void testLoggerInstance() throws Exception {
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/LoggerInstance.kt");

View File

@@ -5616,6 +5616,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/declarationChecks/MultiDeclarationErrors.kt");
}
@TestMetadata("nameWithDangerousCharacters.kt")
public void testNameWithDangerousCharacters() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/nameWithDangerousCharacters.kt");
}
@TestMetadata("namedFunAsLastExpressionInBlock.kt")
public void testNamedFunAsLastExpressionInBlock() throws Exception {
runTest("compiler/testData/diagnostics/tests/declarationChecks/namedFunAsLastExpressionInBlock.kt");
@@ -10054,6 +10059,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/commonSuperTypeOfErrorTypes.kt");
}
@TestMetadata("compatibilityResolveWhenVariableHasComplexIntersectionType.kt")
public void testCompatibilityResolveWhenVariableHasComplexIntersectionType() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/compatibilityResolveWhenVariableHasComplexIntersectionType.kt");
}
@TestMetadata("completeInferenceIfManyFailed.kt")
public void testCompleteInferenceIfManyFailed() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/completeInferenceIfManyFailed.kt");
@@ -10204,6 +10214,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypeMultipleBoundsAsReceiver.kt");
}
@TestMetadata("intersectionTypesWithContravariantTypes.kt")
public void testIntersectionTypesWithContravariantTypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionTypesWithContravariantTypes.kt");
}
@TestMetadata("intersectionWithEnum.kt")
public void testIntersectionWithEnum() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/intersectionWithEnum.kt");
@@ -10649,6 +10664,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coercionWithoutExpectedType.kt");
}
@TestMetadata("coerctionToUnitForATypeWithUpperBound.kt")
public void testCoerctionToUnitForATypeWithUpperBound() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coerctionToUnitForATypeWithUpperBound.kt");
}
@TestMetadata("coersionWithAnonymousFunctionsAndUnresolved.kt")
public void testCoersionWithAnonymousFunctionsAndUnresolved() throws Exception {
runTest("compiler/testData/diagnostics/tests/inference/coercionToUnit/coersionWithAnonymousFunctionsAndUnresolved.kt");

View File

@@ -96,8 +96,8 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() {
private fun checkFunction(declaration: FirFunction<*>, reporter: DiagnosticReporter) {
val functionVisibility = (declaration as FirMemberDeclaration).firEffectiveVisibility(declaration.session)
if (declaration !is FirConstructor) {
val restricting = declaration.returnTypeRef.coneType
.leastPermissiveDescriptor(declaration.session, functionVisibility)
val restricting = declaration.returnTypeRef.coneTypeSafe<ConeKotlinType>()
?.leastPermissiveDescriptor(declaration.session, functionVisibility)
if (restricting != null) {
reporter.reportExposure(
FirErrors.EXPOSED_FUNCTION_RETURN_TYPE,

View File

@@ -70,6 +70,7 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
ReturnNotAllowed -> FirErrors.RETURN_NOT_ALLOWED
UnresolvedLabel -> FirErrors.UNRESOLVED_LABEL
IllegalConstExpression -> FirErrors.ILLEGAL_CONST_EXPRESSION
IllegalUnderscore -> FirErrors.ILLEGAL_UNDERSCORE
DeserializationError -> FirErrors.DESERIALIZATION_ERROR
InferenceError -> FirErrors.INFERENCE_ERROR
TypeParameterAsSupertype -> FirErrors.TYPE_PARAMETER_AS_SUPERTYPE

View File

@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PROPERTY_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_RECEIVER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_MODIFIERS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR
@@ -53,6 +54,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(SYNTAX_ERROR, "Syntax error")
map.put(UNRESOLVED_LABEL, "Unresolved label")
map.put(ILLEGAL_CONST_EXPRESSION, "Illegal const expression")
map.put(ILLEGAL_UNDERSCORE, "Illegal underscore")
map.put(DESERIALIZATION_ERROR, "Deserialization error")
map.put(INFERENCE_ERROR, "Inference error")
map.put(TYPE_PARAMETER_AS_SUPERTYPE, "Type parameter as supertype")

View File

@@ -27,6 +27,7 @@ object FirErrors {
val SYNTAX_ERROR by error0<FirSourceElement, PsiElement>()
val UNRESOLVED_LABEL by error0<FirSourceElement, PsiElement>()
val ILLEGAL_CONST_EXPRESSION by error0<FirSourceElement, PsiElement>()
val ILLEGAL_UNDERSCORE by error0<FirSourceElement, PsiElement>()
val DESERIALIZATION_ERROR by error0<FirSourceElement, PsiElement>()
val INFERENCE_ERROR by error0<FirSourceElement, PsiElement>()
val TYPE_PARAMETER_AS_SUPERTYPE by error0<FirSourceElement, PsiElement>()

View File

@@ -9,20 +9,28 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
object SyntheticCallableId {
private val syntheticPackageName: FqName = FqName("_synthetic")
val WHEN = CallableId(
FqName("_synthetic"),
syntheticPackageName,
Name.identifier("WHEN_CALL")
)
val TRY = CallableId(
FqName("_synthetic"),
syntheticPackageName,
Name.identifier("TRY_CALL")
)
val CHECK_NOT_NULL = CallableId(
FqName("_synthetic"),
syntheticPackageName,
Name.identifier("CHECK_NOT_NULL_CALL")
)
val ELVIS_NOT_NULL = CallableId(
syntheticPackageName,
Name.identifier("ELVIS_CALL")
)
val ID = CallableId(
FqName("_synthetic"),
syntheticPackageName,
Name.identifier("ID_CALL")
)
}

View File

@@ -1359,6 +1359,12 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
+"!!"
}
private fun FlowContent.generate(elvisExpression: FirElvisExpression) {
generate(elvisExpression.lhs)
+" ?: "
generate(elvisExpression.rhs)
}
@Suppress("UNUSED_PARAMETER")
private fun FlowContent.generate(elseIfTrueCondition: FirElseIfTrueCondition) {
keyword("else")
@@ -1563,6 +1569,7 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
is FirOperatorCall -> generate(expression)
is FirBinaryLogicExpression -> generate(expression)
is FirCheckNotNullCall -> generate(expression)
is FirElvisExpression -> generate(expression)
is FirVarargArgumentsExpression -> generate(expression)
is FirResolvedReifiedParameterReference -> generate(expression)
is FirComparisonExpression -> generate(expression)

View File

@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.fir.backend
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.generators.ClassMemberGenerator
import org.jetbrains.kotlin.fir.backend.generators.OperatorExpressionGenerator
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
import org.jetbrains.kotlin.fir.expressions.impl.FirStubStatement
@@ -32,10 +35,7 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.IrGeneratorContextInterface
import org.jetbrains.kotlin.ir.builders.constFalse
import org.jetbrains.kotlin.ir.builders.constTrue
import org.jetbrains.kotlin.ir.builders.elseBranch
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.expressions.*
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtBinaryExpression
@@ -330,6 +331,17 @@ class Fir2IrVisitor(
return callGenerator.convertToIrCall(qualifiedAccessExpression, qualifiedAccessExpression.typeRef, explicitReceiverExpression)
}
// Note that this mimics psi2ir [StatementGenerator#isThisForClassPhysicallyAvailable].
private fun isThisForClassPhysicallyAvailable(irClass: IrClass): Boolean {
var lastClass = conversionScope.lastClass()
while (lastClass != null) {
if (irClass == lastClass) return true
if (!lastClass.isInner) return false
lastClass = lastClass.parentClassOrNull
}
return false
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: Any?): IrElement {
val calleeReference = thisReceiverExpression.calleeReference
val boundSymbol = calleeReference.boundSymbol
@@ -337,11 +349,9 @@ class Fir2IrVisitor(
// Object case
val firClass = boundSymbol.fir as FirClass
val irClass = classifierStorage.getCachedIrClass(firClass)!!
if (firClass is FirAnonymousObject || firClass is FirRegularClass && firClass.classKind == ClassKind.OBJECT) {
if (irClass != conversionScope.lastClass()) {
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
}
if (firClass.classKind == ClassKind.OBJECT && !isThisForClassPhysicallyAvailable(irClass)) {
return thisReceiverExpression.convertWithOffsets { startOffset, endOffset ->
IrGetObjectValueImpl(startOffset, endOffset, irClass.defaultType, irClass.symbol)
}
}
@@ -552,6 +562,120 @@ class Fir2IrVisitor(
}
}
override fun visitElvisExpression(elvisExpression: FirElvisExpression, data: Any?): IrElement {
val firLhsVariable = buildProperty {
source = elvisExpression.source
session = this@Fir2IrVisitor.session
origin = FirDeclarationOrigin.Source
returnTypeRef = elvisExpression.lhs.typeRef
name = Name.special("<elvis>")
initializer = elvisExpression.lhs
symbol = FirPropertySymbol(name)
isVar = false
isLocal = true
status = FirDeclarationStatusImpl(Visibilities.LOCAL, Modality.FINAL)
}
val irLhsVariable = firLhsVariable.accept(this, null) as IrVariable
return elvisExpression.convertWithOffsets { startOffset, endOffset ->
fun irGetLhsValue(): IrGetValue =
IrGetValueImpl(startOffset, endOffset, irLhsVariable.type, irLhsVariable.symbol)
// TODO: replace with .coneType
val originalType = firLhsVariable.returnTypeRef.coneTypeUnsafe<ConeKotlinType>()
val notNullType = originalType.withNullability(ConeNullability.NOT_NULL)
val irBranches = listOf(
IrBranchImpl(
startOffset, endOffset, primitiveOp2(
startOffset, endOffset, irBuiltIns.eqeqSymbol,
irBuiltIns.booleanType, IrStatementOrigin.EQEQ,
irGetLhsValue(),
IrConstImpl.constNull(startOffset, endOffset, irBuiltIns.nothingNType)
),
convertToIrExpression(elvisExpression.rhs)
),
IrElseBranchImpl(
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true),
if (notNullType == originalType) {
irGetLhsValue()
} else {
implicitCastOrExpression(
irGetLhsValue(),
firLhsVariable.returnTypeRef.resolvedTypeFromPrototype(notNullType).toIrType()
)
}
)
)
generateWhen(
startOffset, endOffset, IrStatementOrigin.ELVIS,
irLhsVariable, irBranches,
elvisExpression.typeRef.toIrType()
)
}
}
override fun visitWhenExpression(whenExpression: FirWhenExpression, data: Any?): IrElement {
val subjectVariable = generateWhenSubjectVariable(whenExpression)
val psi = whenExpression.psi
val origin = when (whenExpression.source?.elementType) {
KtNodeTypes.WHEN -> IrStatementOrigin.WHEN
KtNodeTypes.IF -> IrStatementOrigin.IF
KtNodeTypes.BINARY_EXPRESSION -> when ((psi as? KtBinaryExpression)?.operationToken) {
KtTokens.OROR -> IrStatementOrigin.OROR
KtTokens.ANDAND -> IrStatementOrigin.ANDAND
else -> null
}
KtNodeTypes.POSTFIX_EXPRESSION -> IrStatementOrigin.EXCLEXCL
else -> null
}
return conversionScope.withWhenSubject(subjectVariable) {
whenExpression.convertWithOffsets { startOffset, endOffset ->
// If the constant true branch has empty body, it won't be converted. Thus, the entire `when` expression is effectively _not_
// exhaustive anymore. In that case, coerce the return type of `when` expression to Unit as per the backend expectation.
val irBranches = whenExpression.branches.mapNotNullTo(mutableListOf()) { branch ->
branch.takeIf {
it.condition !is FirElseIfTrueCondition || it.result.statements.isNotEmpty()
}?.toIrWhenBranch()
}
if (whenExpression.isExhaustive && whenExpression.branches.none { it.condition is FirElseIfTrueCondition }) {
val irResult = IrCallImpl(
startOffset, endOffset, irBuiltIns.nothingType,
irBuiltIns.noWhenBranchMatchedExceptionSymbol,
typeArgumentsCount = 0,
valueArgumentsCount = 0
)
irBranches += IrElseBranchImpl(
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true), irResult
)
}
generateWhen(
startOffset, endOffset, origin,
subjectVariable, irBranches,
if (whenExpression.isExhaustive && whenExpression.branches.none {
it.condition is FirElseIfTrueCondition && it.result.statements.isEmpty()
}
) whenExpression.typeRef.toIrType() else irBuiltIns.unitType
)
}
}
}
private fun generateWhen(
startOffset: Int,
endOffset: Int,
origin: IrStatementOrigin?,
subjectVariable: IrVariable?,
branches: List<IrBranch>,
resultType: IrType
): IrExpression {
val irWhen = IrWhenImpl(startOffset, endOffset, resultType, origin, branches)
return if (subjectVariable == null) {
irWhen
} else {
IrBlockImpl(startOffset, endOffset, irWhen.type, origin, listOf(subjectVariable, irWhen))
}
}
private fun generateWhenSubjectVariable(whenExpression: FirWhenExpression): IrVariable? {
val subjectVariable = whenExpression.subjectVariable
val subjectExpression = whenExpression.subject
@@ -564,68 +688,10 @@ class Fir2IrVisitor(
}
}
override fun visitWhenExpression(whenExpression: FirWhenExpression, data: Any?): IrElement {
val subjectVariable = generateWhenSubjectVariable(whenExpression)
val psi = whenExpression.psi
val origin = when (whenExpression.source?.elementType) {
KtNodeTypes.WHEN -> IrStatementOrigin.WHEN
KtNodeTypes.IF -> IrStatementOrigin.IF
KtNodeTypes.BINARY_EXPRESSION -> when ((psi as? KtBinaryExpression)?.operationToken) {
KtTokens.ELVIS -> IrStatementOrigin.ELVIS
KtTokens.OROR -> IrStatementOrigin.OROR
KtTokens.ANDAND -> IrStatementOrigin.ANDAND
else -> null
}
KtNodeTypes.POSTFIX_EXPRESSION -> IrStatementOrigin.EXCLEXCL
else -> null
}
// If the constant true branch has empty body, it won't be converted. Thus, the entire `when` expression is effectively _not_
// exhaustive anymore. In that case, coerce the return type of `when` expression to Unit as per the backend expectation.
val effectivelyNotExhaustive = !whenExpression.isExhaustive ||
whenExpression.branches.any { it.condition is FirElseIfTrueCondition && it.result.statements.isEmpty() }
return conversionScope.withWhenSubject(subjectVariable) {
whenExpression.convertWithOffsets { startOffset, endOffset ->
val irWhen = IrWhenImpl(
startOffset, endOffset,
if (effectivelyNotExhaustive) irBuiltIns.unitType else whenExpression.typeRef.toIrType(),
origin
).apply {
var unconditionalBranchFound = false
for (branch in whenExpression.branches) {
if (branch.condition !is FirElseIfTrueCondition) {
branches += branch.accept(this@Fir2IrVisitor, data) as IrBranch
} else {
unconditionalBranchFound = true
if (branch.result.statements.isNotEmpty()) {
branches += branch.accept(this@Fir2IrVisitor, data) as IrBranch
}
}
}
if (whenExpression.isExhaustive && !unconditionalBranchFound) {
val irResult = IrCallImpl(
startOffset, endOffset, irBuiltIns.nothingType,
irBuiltIns.noWhenBranchMatchedExceptionSymbol,
typeArgumentsCount = 0,
valueArgumentsCount = 0
)
branches += IrElseBranchImpl(
IrConstImpl.boolean(startOffset, endOffset, irBuiltIns.booleanType, true), irResult
)
}
}
if (subjectVariable == null) {
irWhen
} else {
IrBlockImpl(startOffset, endOffset, irWhen.type, origin, listOf(subjectVariable, irWhen))
}
}
}
}
override fun visitWhenBranch(whenBranch: FirWhenBranch, data: Any?): IrElement {
return whenBranch.convertWithOffsets { startOffset, endOffset ->
val condition = whenBranch.condition
val irResult = convertToIrExpression(whenBranch.result)
private fun FirWhenBranch.toIrWhenBranch(): IrBranch {
return convertWithOffsets { startOffset, endOffset ->
val condition = condition
val irResult = convertToIrExpression(result)
if (condition is FirElseIfTrueCondition) {
IrElseBranchImpl(IrConstImpl.boolean(irResult.startOffset, irResult.endOffset, irBuiltIns.booleanType, true), irResult)
} else {
@@ -673,7 +739,7 @@ class Fir2IrVisitor(
}
private fun FirJump<FirLoop>.convertJumpWithOffsets(
f: (startOffset: Int, endOffset: Int, irLoop: IrLoop) -> IrBreakContinueBase
f: (startOffset: Int, endOffset: Int, irLoop: IrLoop, label: String?) -> IrBreakContinue
): IrExpression {
return convertWithOffsets { startOffset, endOffset ->
val firLoop = target.labeledElement
@@ -681,22 +747,24 @@ class Fir2IrVisitor(
if (irLoop == null) {
IrErrorExpressionImpl(startOffset, endOffset, irBuiltIns.nothingType, "Unbound loop: ${render()}")
} else {
f(startOffset, endOffset, irLoop).apply {
label = irLoop.label.takeIf { target.labelName != null }
}
f(startOffset, endOffset, irLoop, irLoop.label.takeIf { target.labelName != null })
}
}
}
override fun visitBreakExpression(breakExpression: FirBreakExpression, data: Any?): IrElement {
return breakExpression.convertJumpWithOffsets { startOffset, endOffset, irLoop ->
IrBreakImpl(startOffset, endOffset, irBuiltIns.nothingType, irLoop)
return breakExpression.convertJumpWithOffsets { startOffset, endOffset, irLoop, label ->
IrBreakImpl(startOffset, endOffset, irBuiltIns.nothingType, irLoop).apply {
this.label = label
}
}
}
override fun visitContinueExpression(continueExpression: FirContinueExpression, data: Any?): IrElement {
return continueExpression.convertJumpWithOffsets { startOffset, endOffset, irLoop ->
IrContinueImpl(startOffset, endOffset, irBuiltIns.nothingType, irLoop)
return continueExpression.convertJumpWithOffsets { startOffset, endOffset, irLoop, label ->
IrContinueImpl(startOffset, endOffset, irBuiltIns.nothingType, irLoop).apply {
this.label = label
}
}
}

View File

@@ -30,7 +30,8 @@ import org.jetbrains.kotlin.ir.declarations.IrProperty
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.psi2ir.generators.hasNoSideEffects
@@ -317,7 +318,7 @@ class CallAndReferenceGenerator(
internal fun IrExpression.applyCallArguments(call: FirCall?): IrExpression {
if (call == null) return this
return when (this) {
is IrCallWithIndexedArgumentsBase -> {
is IrMemberAccessExpression<*> -> {
val argumentsCount = call.arguments.size
if (argumentsCount <= valueArgumentsCount) {
apply {
@@ -362,11 +363,11 @@ class CallAndReferenceGenerator(
}
}
private fun IrCallWithIndexedArgumentsBase.applyArgumentsWithReorderingIfNeeded(
private fun IrMemberAccessExpression<*>.applyArgumentsWithReorderingIfNeeded(
call: FirCall,
argumentMapping: Map<FirExpression, FirValueParameter>,
valueParameters: List<FirValueParameter>,
): IrExpressionBase {
): IrExpression {
// Assuming compile-time constants only inside annotation, we don't need a block to reorder arguments to preserve semantics.
// But, we still need to pick correct indices for named arguments.
if (call !is FirAnnotationCall &&
@@ -436,7 +437,7 @@ class CallAndReferenceGenerator(
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
return when (this) {
is IrMemberAccessExpressionBase -> {
is IrMemberAccessExpression<*> -> {
val argumentsCount = access.typeArguments.size
if (argumentsCount <= typeArgumentsCount) {
apply {
@@ -494,8 +495,10 @@ class CallAndReferenceGenerator(
private fun IrExpression.applyReceivers(qualifiedAccess: FirQualifiedAccess, explicitReceiverExpression: IrExpression?): IrExpression {
return when (this) {
is IrCallWithIndexedArgumentsBase -> {
val ownerFunction = symbol.owner as? IrFunction
is IrMemberAccessExpression<*> -> {
val ownerFunction =
symbol.owner as? IrFunction
?: (symbol.owner as? IrProperty)?.getter
if (ownerFunction?.dispatchReceiverParameter != null) {
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
}
@@ -504,17 +507,7 @@ class CallAndReferenceGenerator(
}
this
}
is IrNoArgumentsCallableReferenceBase -> {
val ownerPropertyGetter = (symbol.owner as? IrProperty)?.getter
if (ownerPropertyGetter?.dispatchReceiverParameter != null) {
dispatchReceiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)
}
if (ownerPropertyGetter?.extensionReceiverParameter != null) {
extensionReceiver = qualifiedAccess.findIrExtensionReceiver(explicitReceiverExpression)
}
this
}
is IrFieldExpressionBase -> {
is IrFieldAccessExpression -> {
val ownerField = symbol.owner
if (!ownerField.isStatic) {
receiver = qualifiedAccess.findIrDispatchReceiver(explicitReceiverExpression)

View File

@@ -95,7 +95,7 @@ class DataClassMembersGenerator(val components: Fir2IrComponents) {
return components.irBuiltIns.anyType
}
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression, descriptor: CallableDescriptor) {
override fun commitSubstituted(irMemberAccessExpression: IrMemberAccessExpression<*>, descriptor: CallableDescriptor) {
// TODO
}
}

View File

@@ -144,6 +144,7 @@ class FakeOverrideGenerator(
)
irProperty.parent = this
result += irProperty.withProperty {
discardAccessorsAccordingToBaseVisibility(baseSymbol)
setOverriddenSymbolsForAccessors(declarationStorage, originalProperty, firOverriddenSymbol = baseSymbol)
}
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalProperty.allowsToHaveFakeOverrideIn(klass)) {
@@ -160,15 +161,7 @@ class FakeOverrideGenerator(
fakeOverrideProperty, irParent = this,
thisReceiverOwner = declarationStorage.findIrParent(originalProperty) as? IrClass,
origin = origin
).apply {
// Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var.
if (baseSymbol.fir.getter?.allowsToHaveFakeOverride != true) {
getter = null
}
if (baseSymbol.fir.setter?.allowsToHaveFakeOverride != true) {
setter = null
}
}
)
if (irProperty.backingField?.type?.containsErrorType() == true ||
irProperty.getter?.returnType?.containsErrorType() == true
) {
@@ -176,6 +169,7 @@ class FakeOverrideGenerator(
}
irProperty.parent = this
result += irProperty.withProperty {
discardAccessorsAccordingToBaseVisibility(baseSymbol)
setOverriddenSymbolsForAccessors(declarationStorage, fakeOverrideProperty, firOverriddenSymbol = baseSymbol)
}
}
@@ -185,6 +179,17 @@ class FakeOverrideGenerator(
return result
}
private fun IrProperty.discardAccessorsAccordingToBaseVisibility(baseSymbol: FirPropertySymbol) {
// Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var.
if (baseSymbol.fir.getter?.allowsToHaveFakeOverride != true) {
getter = null
}
// or private setter
if (baseSymbol.fir.setter?.allowsToHaveFakeOverride != true) {
setter = null
}
}
private fun IrProperty.setOverriddenSymbolsForAccessors(
declarationStorage: Fir2IrDeclarationStorage,
property: FirProperty,

View File

@@ -8,7 +8,8 @@ package org.jetbrains.kotlin.fir.lazy
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.toIrType
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.symbols.Fir2IrBindableSymbol
import org.jetbrains.kotlin.ir.IrElementBase
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
@@ -38,7 +39,7 @@ abstract class AbstractFir2IrLazyDeclaration<F : FirMemberDeclaration, D : IrSym
lateinit var typeParameters: List<IrTypeParameter>
override var metadata: Nothing?
override var metadata: MetadataSource?
get() = null
set(_) = error("We should never need to store metadata of external declarations.")

View File

@@ -6,8 +6,9 @@
package org.jetbrains.kotlin.fir.lazy
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.declareThisReceiverParameter
import org.jetbrains.kotlin.fir.backend.toIrType
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.resolve.buildUseSiteMemberScope
import org.jetbrains.kotlin.fir.symbols.Fir2IrClassSymbol
@@ -19,8 +20,8 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.mapOptimized
import org.jetbrains.kotlin.ir.util.transform
import org.jetbrains.kotlin.ir.util.transformIfNeeded
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
@@ -190,7 +191,7 @@ class Fir2IrLazyClass(
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
thisReceiver = thisReceiver?.transform(transformer, data)
typeParameters = typeParameters.mapOptimized { it.transform(transformer, data) }
typeParameters = typeParameters.transformIfNeeded(transformer, data)
declarations.transform { it.transform(transformer, data) }
}
}

View File

@@ -20,8 +20,8 @@ import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.lazy.lazyVar
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.mapOptimized
import org.jetbrains.kotlin.ir.util.parentClassOrNull
import org.jetbrains.kotlin.ir.util.transformIfNeeded
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
@@ -125,11 +125,11 @@ class Fir2IrLazyConstructor(
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
typeParameters = typeParameters.mapOptimized { it.transform(transformer, data) }
typeParameters = typeParameters.transformIfNeeded(transformer, data)
dispatchReceiverParameter = dispatchReceiverParameter?.transform(transformer, data)
extensionReceiverParameter = extensionReceiverParameter?.transform(transformer, data)
valueParameters = valueParameters.mapOptimized { it.transform(transformer, data) }
valueParameters = valueParameters.transformIfNeeded(transformer, data)
body = body?.transform(transformer, data)
}

View File

@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.mapOptimized
import org.jetbrains.kotlin.ir.util.transformIfNeeded
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.name.Name
@@ -147,11 +147,11 @@ class Fir2IrLazySimpleFunction(
}
override fun <D> transformChildren(transformer: IrElementTransformer<D>, data: D) {
typeParameters = typeParameters.mapOptimized { it.transform(transformer, data) }
typeParameters = typeParameters.transformIfNeeded(transformer, data)
dispatchReceiverParameter = dispatchReceiverParameter?.transform(transformer, data)
extensionReceiverParameter = extensionReceiverParameter?.transform(transformer, data)
valueParameters = valueParameters.mapOptimized { it.transform(transformer, data) }
valueParameters = valueParameters.transformIfNeeded(transformer, data)
body = body?.transform(transformer, data)
}

View File

@@ -8306,6 +8306,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTestWithPackageReplacement("compiler/testData/codegen/box/coroutines/unitTypeReturn/coroutineReturn.kt", "kotlin.coroutines");
}
@TestMetadata("inlineUnitFunction.kt")
public void testInlineUnitFunction() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/unitTypeReturn/inlineUnitFunction.kt");
}
@TestMetadata("interfaceDelegation.kt")
public void testInterfaceDelegation() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/unitTypeReturn/interfaceDelegation.kt");
@@ -9631,6 +9636,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/kt18902.kt");
}
@TestMetadata("kt39588.kt")
public void testKt39588() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/kt39588.kt");
}
@TestMetadata("local.kt")
public void testLocal() throws Exception {
runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/local.kt");

View File

@@ -17,10 +17,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.MemberSignature
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
import org.jetbrains.kotlin.metadata.deserialization.hasReceiver
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId
@@ -145,28 +142,34 @@ class JvmBinaryAnnotationDeserializer(
containerSource: DeserializedContainerSource?,
callableProto: MessageLite,
valueParameterProto: ProtoBuf.ValueParameter,
classProto: ProtoBuf.Class?,
nameResolver: NameResolver,
typeTable: TypeTable,
kind: CallableKind,
parameterIndex: Int,
): List<FirAnnotationCall> {
val methodSignature = getCallableSignature(callableProto, nameResolver, typeTable, kind) ?: return emptyList()
val index = parameterIndex + computeJvmParameterIndexShift(callableProto)
val index = parameterIndex + computeJvmParameterIndexShift(classProto, callableProto)
val paramSignature = MemberSignature.fromMethodSignatureAndParameterIndex(methodSignature, index)
return findJvmBinaryClassAndLoadMemberAnnotations(containerSource, paramSignature)
}
/*
* TODO: Support container proto and fix index shift for
* constructors of inner classes and enums
*
* See [AbstractBinaryClassAnnotationAndConstantLoader]
*/
private fun computeJvmParameterIndexShift(message: MessageLite): Int {
private fun computeJvmParameterIndexShift(classProto: ProtoBuf.Class?, message: MessageLite): Int {
return when (message) {
is ProtoBuf.Function -> if (message.hasReceiver()) 1 else 0
is ProtoBuf.Property -> if (message.hasReceiver()) 1 else 0
is ProtoBuf.Constructor -> 0
is ProtoBuf.Constructor -> {
assert(classProto != null) {
"Constructor call without information about enclosing Class: $message"
}
val kind = Flags.CLASS_KIND.get(classProto!!.flags) ?: ProtoBuf.Class.Kind.CLASS
val isInner = Flags.IS_INNER.get(classProto.flags)
when {
kind == ProtoBuf.Class.Kind.ENUM_CLASS -> 2
isInner -> 1
else -> 0
}
}
else -> throw UnsupportedOperationException("Unsupported message: ${message::class.java}")
}
}

View File

@@ -30,12 +30,12 @@ class JvmMappedScope(
val jvmSignature = symbol.fir.computeJvmDescriptor()
.replace("kotlin/Any", "java/lang/Object")
.replace("kotlin/String", "java/lang/String")
.replace("kotlin/Throwable", "java/lang/Throwable")
if (jvmSignature in whiteListSignatures) {
processor(symbol)
}
}
declaredMemberScope.processFunctionsByName(name, processor)
}

View File

@@ -235,21 +235,26 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
val type = expression.elementType
val text: String = expression.asText
val sourceElement = expression.toFirSourceElement()
fun reportIncorrectConstant(kind: DiagnosticKind): FirErrorExpression {
return buildErrorExpression {
source = sourceElement
diagnostic = ConeSimpleDiagnostic("Incorrect constant expression: $text", kind)
}
}
val convertedText: Any? = when (type) {
INTEGER_CONSTANT, FLOAT_CONSTANT -> parseNumericLiteral(text, type)
INTEGER_CONSTANT, FLOAT_CONSTANT -> when {
hasIllegalUnderscore(text, type) -> return reportIncorrectConstant(DiagnosticKind.IllegalUnderscore)
else -> parseNumericLiteral(text, type)
}
BOOLEAN_CONSTANT -> parseBoolean(text)
else -> null
}
return when (type) {
INTEGER_CONSTANT -> {
val kind = when {
convertedText !is Long -> return buildErrorExpression {
source = sourceElement
diagnostic = ConeSimpleDiagnostic(
"Incorrect constant expression: $text",
DiagnosticKind.IllegalConstExpression
)
}
convertedText !is Long -> return reportIncorrectConstant(DiagnosticKind.IllegalConstExpression)
hasUnsignedLongSuffix(text) -> {
FirConstKind.UnsignedLong
@@ -285,7 +290,7 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
buildConstOrErrorExpression(
sourceElement,
FirConstKind.Double,
convertedText as Double,
convertedText as? Double,
ConeSimpleDiagnostic("Incorrect double: $text", DiagnosticKind.IllegalConstExpression)
)
}

View File

@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.fir.expressions.builder.*
import org.jetbrains.kotlin.fir.expressions.impl.FirModifiableQualifiedAccess
import org.jetbrains.kotlin.fir.expressions.impl.FirSingleExpressionBlock
import org.jetbrains.kotlin.fir.expressions.impl.FirStubStatement
import org.jetbrains.kotlin.fir.expressions.impl.buildSingleExpressionBlock
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.builder.buildDelegateFieldReference
import org.jetbrains.kotlin.fir.references.builder.buildImplicitThisReference
@@ -141,45 +140,12 @@ fun IElementType.toFirOperation(): FirOperation =
}
fun FirExpression.generateNotNullOrOther(
session: FirSession, other: FirExpression, caseId: String, baseSource: FirSourceElement?,
): FirWhenExpression {
val subjectName = Name.special("<$caseId>")
val subjectSource = baseSource?.withKind(FirFakeSourceElementKind.WhenGeneratedSubject)
val subjectVariable = generateTemporaryVariable(session, subjectSource, subjectName, this)
@OptIn(FirContractViolation::class)
val ref = FirExpressionRef<FirWhenExpression>()
val subjectExpression = buildWhenSubjectExpression {
source = subjectSource
whenRef = ref
}
return buildWhenExpression {
other: FirExpression, baseSource: FirSourceElement?,
): FirElvisExpression {
return buildElvisExpression {
source = baseSource
this.subject = this@generateNotNullOrOther
this.subjectVariable = subjectVariable
branches += buildWhenBranch {
val branchSource = baseSource?.withKind(FirFakeSourceElementKind.WhenCondition)
source = branchSource
condition = buildOperatorCall {
source = branchSource
operation = FirOperation.EQ
argumentList = buildBinaryArgumentList(
subjectExpression, buildConstExpression(branchSource, FirConstKind.Null, null)
)
}
result = buildSingleExpressionBlock(other)
}
branches += buildWhenBranch {
val otherSource = other.source?.withKind(FirFakeSourceElementKind.WhenCondition)
source = otherSource
condition = buildElseIfTrueCondition {
source = otherSource
}
result = buildSingleExpressionBlock(generateResolvedAccessExpression(otherSource, subjectVariable))
}
}.also {
ref.bind(it)
lhs = this@generateNotNullOrOther
rhs = other
}
}

View File

@@ -246,7 +246,7 @@ class ExpressionsConverter(
when (operationToken) {
ELVIS ->
return leftArgAsFir.generateNotNullOrOther(baseSession, rightArgAsFir, "elvis", baseSource)
return leftArgAsFir.generateNotNullOrOther(rightArgAsFir, baseSource)
ANDAND, OROR ->
return leftArgAsFir.generateLazyLogicalOperation(rightArgAsFir, operationToken == ANDAND, baseSource)
in OperatorConventions.IN_OPERATIONS ->

View File

@@ -1554,7 +1554,7 @@ class RawFirBuilder(
when (operationToken) {
ELVIS ->
return leftArgument.generateNotNullOrOther(baseSession, rightArgument, "elvis", source)
return leftArgument.generateNotNullOrOther(rightArgument, source)
ANDAND, OROR ->
return leftArgument.generateLazyLogicalOperation(rightArgument, operationToken == ANDAND, source)
in OperatorConventions.IN_OPERATIONS ->

View File

@@ -1,14 +1,6 @@
FILE: nullability.kt
public? final? fun orFourtyTwo(arg: Int?): <implicit> {
^orFourtyTwo when (lval <elvis>: <implicit> = arg#) {
==($subj$, Null(null)) -> {
IntegerLiteral(42)
}
else -> {
R|<local>/<elvis>|
}
}
^orFourtyTwo arg# ?: IntegerLiteral(42)
}
public? final? fun bang(arg: Int?): <implicit> {
^bang arg#!!

View File

@@ -135,6 +135,7 @@ abstract class AbstractAnnotationDeserializer(
containerSource: DeserializedContainerSource?,
callableProto: MessageLite,
valueParameterProto: ProtoBuf.ValueParameter,
classProto: ProtoBuf.Class?,
nameResolver: NameResolver,
typeTable: TypeTable,
kind: CallableKind,

View File

@@ -100,7 +100,6 @@ fun deserializeClassToSymbol(
typeParameters += context.typeDeserializer.ownTypeParameters.map { it.fir }
if (status.isInner)
typeParameters += parentContext?.allTypeParameters?.map { buildOuterClassTypeParameterRef { this.symbol = it } }.orEmpty()
// annotations += context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
val typeDeserializer = context.typeDeserializer
val classDeserializer = context.memberDeserializer
@@ -114,12 +113,21 @@ fun deserializeClassToSymbol(
buildResolvedTypeRef { type = it }
}
addDeclarations(classProto.functionList.map(classDeserializer::loadFunction))
addDeclarations(classProto.propertyList.map(classDeserializer::loadProperty))
addDeclarations(
classProto.functionList.map {
classDeserializer.loadFunction(it, classProto)
}
)
addDeclarations(
classProto.propertyList.map {
classDeserializer.loadProperty(it, classProto)
}
)
addDeclarations(
classProto.constructorList.map {
classDeserializer.loadConstructor(it, this)
classDeserializer.loadConstructor(it, classProto, this)
}
)
@@ -167,7 +175,8 @@ fun deserializeClassToSymbol(
ClassId.fromString(nameResolver.getQualifiedClassName(nameIndex))
}
}
(it.annotations as MutableList<FirAnnotationCall>) += context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
(it.annotations as MutableList<FirAnnotationCall>) +=
context.annotationDeserializer.loadClassAnnotations(classProto, context.nameResolver)
}
}

View File

@@ -177,7 +177,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
}
}
fun loadProperty(proto: ProtoBuf.Property): FirProperty {
fun loadProperty(proto: ProtoBuf.Property, classProto: ProtoBuf.Class? = null): FirProperty {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
val callableName = c.nameResolver.getName(proto.name)
val symbol = FirPropertySymbol(CallableId(c.packageFqName, c.relativeClassName, callableName))
@@ -237,7 +237,8 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
valueParameters += local.memberDeserializer.valueParameters(
listOf(proto.setterValueParameter),
proto,
AbstractAnnotationDeserializer.CallableKind.PROPERTY_SETTER
AbstractAnnotationDeserializer.CallableKind.PROPERTY_SETTER,
classProto
)
}
} else {
@@ -287,7 +288,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
}
}
fun loadFunction(proto: ProtoBuf.Function, byteContent: ByteArray? = null): FirSimpleFunction {
fun loadFunction(proto: ProtoBuf.Function, classProto: ProtoBuf.Class? = null): FirSimpleFunction {
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
val receiverAnnotations =
@@ -329,7 +330,8 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
valueParameters += local.memberDeserializer.valueParameters(
proto.valueParameterList,
proto,
AbstractAnnotationDeserializer.CallableKind.OTHERS
AbstractAnnotationDeserializer.CallableKind.OTHERS,
classProto
)
annotations +=
c.annotationDeserializer.loadFunctionAnnotations(c.containerSource, proto, local.nameResolver, local.typeTable)
@@ -344,7 +346,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
return simpleFunction
}
fun loadConstructor(proto: ProtoBuf.Constructor, classBuilder: FirRegularClassBuilder): FirConstructor {
fun loadConstructor(proto: ProtoBuf.Constructor, classProto: ProtoBuf.Class, classBuilder: FirRegularClassBuilder): FirConstructor {
val flags = proto.flags
val relativeClassName = c.relativeClassName!!
val symbol = FirConstructorSymbol(CallableId(c.packageFqName, relativeClassName, relativeClassName.shortName()))
@@ -383,6 +385,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
proto.valueParameterList,
proto,
AbstractAnnotationDeserializer.CallableKind.OTHERS,
classProto,
addDefaultValue = classBuilder.symbol.classId == StandardClassIds.Enum
)
annotations +=
@@ -401,6 +404,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
valueParameters: List<ProtoBuf.ValueParameter>,
callableProto: MessageLite,
callableKind: AbstractAnnotationDeserializer.CallableKind,
classProto: ProtoBuf.Class?,
addDefaultValue: Boolean = false
): List<FirValueParameter> {
return valueParameters.mapIndexed { index, proto ->
@@ -423,6 +427,7 @@ class FirMemberDeserializer(private val c: FirDeserializationContext) {
c.containerSource,
callableProto,
proto,
classProto,
c.nameResolver,
c.typeTable,
callableKind,

View File

@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerLiteralTypeScope
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
import org.jetbrains.kotlin.fir.scopes.impl.FirTypeIntersectionScope
import org.jetbrains.kotlin.fir.scopes.scope
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.typeContext
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
@@ -31,15 +33,14 @@ fun ConeKotlinType.scope(useSiteSession: FirSession, scopeSession: ScopeSession)
fir.scope(substitutorByMap(substitution), useSiteSession, scopeSession, skipPrivateMembers = false)
}
is ConeTypeParameterType -> {
// TODO: support LibraryTypeParameterSymbol or get rid of it
val fir = lookupTag.toSymbol().fir
FirTypeIntersectionScope.prepareIntersectionScope(
useSiteSession,
FirStandardOverrideChecker(useSiteSession),
fir.bounds.mapNotNullTo(mutableListOf()) {
it.coneType.scope(useSiteSession, scopeSession)
}
)
val symbol = lookupTag.toSymbol()
scopeSession.getOrBuild(symbol, TYPE_PARAMETER_SCOPE_KEY) {
val intersectionType = ConeTypeIntersector.intersectTypes(
useSiteSession.typeContext,
symbol.fir.bounds.map { it.coneType }
)
intersectionType.scope(useSiteSession, scopeSession) ?: FirTypeScope.Empty
}
}
is ConeRawType -> lowerBound.scope(useSiteSession, scopeSession)
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession)
@@ -87,3 +88,5 @@ fun FirAnonymousObject.defaultType(): ConeClassLikeType {
isNullable = false
)
}
val TYPE_PARAMETER_SCOPE_KEY = scopeSessionKey<FirTypeParameterSymbol, FirTypeScope>()

View File

@@ -42,7 +42,7 @@ fun Candidate.resolveArgumentExpression(
isDispatch: Boolean
) {
when (argument) {
is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall -> resolveSubCallArgument(
is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, is FirElvisExpression -> resolveSubCallArgument(
csBuilder,
argument as FirResolvable,
expectedType,

View File

@@ -116,7 +116,8 @@ fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(statement: Fir
is FirWhenExpression,
is FirTryExpression,
is FirCheckNotNullCall,
is FirCallableReferenceAccess
is FirCallableReferenceAccess,
is FirElvisExpression
-> (statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
is FirSafeCallExpression -> addSubsystemFromExpression(statement.regularQualifiedAccess)

View File

@@ -18,8 +18,7 @@ import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.SyntheticSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.propertyNameByGetMethodName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
@@ -102,7 +101,7 @@ class FirSyntheticPropertiesScope(
val parameter = setter.valueParameters.singleOrNull() ?: return
if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.type ?: return
if (parameterType != getterReturnType) return
if (getterReturnType.withNullability(ConeNullability.NOT_NULL) != parameterType.withNullability(ConeNullability.NOT_NULL)) return
matchingSetter = setter
})
}

View File

@@ -493,8 +493,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
graphBuilder.exitWhenBranchResult(whenBranch).mergeIncomingFlow()
}
fun exitWhenExpression(whenExpression: FirWhenExpression, callCompleted: Boolean) {
val (whenExitNode, syntheticElseNode, unionNode) = graphBuilder.exitWhenExpression(whenExpression, callCompleted)
fun exitWhenExpression(whenExpression: FirWhenExpression) {
val (whenExitNode, syntheticElseNode) = graphBuilder.exitWhenExpression(whenExpression)
if (syntheticElseNode != null) {
val previousConditionExitNode = syntheticElseNode.firstPreviousNode as? WhenBranchConditionExitNode
// previous node for syntheticElseNode can be not WhenBranchConditionExitNode in case of `when` without any branches
@@ -512,7 +512,6 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
}
}
whenExitNode.mergeIncomingFlow(updateReceivers = true)
unionNode?.let { unionFlowFromArguments(unionNode) }
}
// ----------------------------------- While Loop -----------------------------------
@@ -1015,6 +1014,35 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
graphBuilder.exitContractDescription()
}
// ----------------------------------- Elvis -----------------------------------
fun exitElvisLhs(elvisExpression: FirElvisExpression) {
val (lhsExitNode, lhsIsNotNullNode, rhsEnterNode) = graphBuilder.exitElvisLhs(elvisExpression)
lhsExitNode.mergeIncomingFlow()
val flow = lhsExitNode.flow
val lhsVariable = variableStorage.getOrCreateVariable(flow, elvisExpression.lhs)
rhsEnterNode.flow = logicSystem.approveStatementsInsideFlow(
flow,
lhsVariable eq null,
shouldForkFlow = true,
shouldRemoveSynthetics = false
)
lhsIsNotNullNode.flow = logicSystem.approveStatementsInsideFlow(
flow,
lhsVariable notEq null,
shouldForkFlow = true,
shouldRemoveSynthetics = false
).also {
if (lhsVariable.isReal()) {
it.addTypeStatement(lhsVariable typeEq any)
}
}
}
fun exitElvis() {
graphBuilder.exitElvis().mergeIncomingFlow()
}
// ------------------------------------------------------ Utils ------------------------------------------------------
private var CFGNode<*>.flow: FLOW

View File

@@ -601,6 +601,32 @@ class ExitSafeCallNode(owner: ControlFlowGraph, override val fir: FirSafeCallExp
}
}
// ----------------------------------- Elvis -----------------------------------
class ElvisLhsExitNode(owner: ControlFlowGraph, override val fir: FirElvisExpression, level: Int, id: Int) : CFGNode<FirElvisExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitElvisLhsExitNode(this, data)
}
}
class ElvisLhsIsNotNullNode(owner: ControlFlowGraph, override val fir: FirElvisExpression, level: Int, id: Int) : CFGNode<FirElvisExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitElvisLhsIsNotNullNode(this, data)
}
}
class ElvisRhsEnterNode(owner: ControlFlowGraph, override val fir: FirElvisExpression, level: Int, id: Int) : CFGNode<FirElvisExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitElvisRhsEnterNode(this, data)
}
}
class ElvisExitNode(owner: ControlFlowGraph, override val fir: FirElvisExpression, level: Int, id: Int) : AbstractBinaryExitNode<FirElvisExpression>(owner, level, id) {
override fun <R, D> accept(visitor: ControlFlowGraphVisitor<R, D>, data: D): R {
return visitor.visitElvisExitNode(this, data)
}
}
// ----------------------------------- Other -----------------------------------
class AnnotationEnterNode(owner: ControlFlowGraph, override val fir: FirAnnotationCall, level: Int, id: Int) : CFGNode<FirAnnotationCall>(owner, level, id), EnterNodeMarker {

View File

@@ -106,10 +106,15 @@ fun CFGNode<*>.render(): String =
is ContractDescriptionEnterNode -> "Enter contract description"
is AbstractBinaryExitNode -> throw IllegalStateException()
is EnterDefaultArgumentsNode -> "Enter default value of ${fir.name}"
is ExitDefaultArgumentsNode -> "Exit default value of ${fir.name}"
is ElvisLhsExitNode -> "Exit lhs of ?:"
is ElvisLhsIsNotNullNode -> "Lhs of ?: is not null"
is ElvisRhsEnterNode -> "Enter rhs of ?:"
is ElvisExitNode -> "Exit ?:"
is AbstractBinaryExitNode -> throw IllegalStateException()
},
)
}

View File

@@ -91,6 +91,7 @@ class ControlFlowGraphBuilder {
private val initBlockExitNodes: Stack<InitBlockExitNode> = stackOf()
private val exitSafeCallNodes: Stack<ExitSafeCallNode> = stackOf()
private val exitElvisExpressionNodes: Stack<ElvisExitNode> = stackOf()
// ----------------------------------- API for node builders -----------------------------------
@@ -532,10 +533,7 @@ class ControlFlowGraphBuilder {
return node
}
fun exitWhenExpression(
whenExpression: FirWhenExpression,
callCompleted: Boolean
): Triple<WhenExitNode, WhenSyntheticElseBranchNode?, UnionFunctionCallArgumentsNode?> {
fun exitWhenExpression(whenExpression: FirWhenExpression): Pair<WhenExitNode, WhenSyntheticElseBranchNode?> {
val whenExitNode = whenExitNodes.pop()
// exit from last condition node still on stack
// we should remove it
@@ -548,9 +546,9 @@ class ControlFlowGraphBuilder {
} else null
whenExitNode.updateDeadStatus()
lastNodes.push(whenExitNode)
val (_, unionNode) = processUnionOfArguments(whenExitNode, callCompleted)
dropPostponedLambdasForNonDeterministicCalls()
levelCounter--
return Triple(whenExitNode, syntheticElseBranchNode, unionNode)
return whenExitNode to syntheticElseBranchNode
}
// ----------------------------------- While Loop -----------------------------------
@@ -869,6 +867,16 @@ class ControlFlowGraphBuilder {
return node to unionNode
}
/*
* This is needed for some control flow constructions which are resolved as calls (when and elvis)
* For usual call we have invariant that all arguments will be called before function call, but for
* when and elvis only one of arguments will be actually called, so it's illegal to pass data flow info
* from lambda in one of branches
*/
private fun dropPostponedLambdasForNonDeterministicCalls() {
exitsFromCompletedPostponedAnonymousFunctions.clear()
}
private fun processUnionOfArguments(
node: CFGNode<*>,
callCompleted: Boolean
@@ -986,6 +994,37 @@ class ControlFlowGraphBuilder {
}
}
// ----------------------------------- Elvis -----------------------------------
fun exitElvisLhs(elvisExpression: FirElvisExpression): Triple<ElvisLhsExitNode, ElvisLhsIsNotNullNode, ElvisRhsEnterNode> {
val exitNode = createElvisExitNode(elvisExpression).also {
exitElvisExpressionNodes.push(it)
}
val lhsExitNode = createElvisLhsExitNode(elvisExpression).also {
popAndAddEdge(it)
}
val lhsIsNotNullNode = createElvisLhsIsNotNullNode(elvisExpression).also {
addEdge(lhsExitNode, it)
addEdge(it, exitNode)
}
val rhsEnterNode = createElvisRhsEnterNode(elvisExpression).also {
addEdge(lhsExitNode, it)
}
lastNodes.push(rhsEnterNode)
return Triple(lhsExitNode, lhsIsNotNullNode, rhsEnterNode)
}
fun exitElvis(): ElvisExitNode {
val exitNode = exitElvisExpressionNodes.pop()
addNewSimpleNode(exitNode)
exitNode.updateDeadStatus()
dropPostponedLambdasForNonDeterministicCalls()
return exitNode
}
// ----------------------------------- Contract description -----------------------------------
fun enterContractDescription(): CFGNode<*> {

View File

@@ -125,6 +125,18 @@ fun ControlFlowGraphBuilder.createAnnotationExitNode(fir: FirAnnotationCall): An
fun ControlFlowGraphBuilder.createAnnotationEnterNode(fir: FirAnnotationCall): AnnotationEnterNode =
AnnotationEnterNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createElvisLhsIsNotNullNode(fir: FirElvisExpression): ElvisLhsIsNotNullNode =
ElvisLhsIsNotNullNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createElvisRhsEnterNode(fir: FirElvisExpression): ElvisRhsEnterNode =
ElvisRhsEnterNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createElvisLhsExitNode(fir: FirElvisExpression): ElvisLhsExitNode =
ElvisLhsExitNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createElvisExitNode(fir: FirElvisExpression): ElvisExitNode =
ElvisExitNode(currentGraph, fir, levelCounter, createId())
fun ControlFlowGraphBuilder.createVariableDeclarationNode(fir: FirProperty): VariableDeclarationNode =
VariableDeclarationNode(currentGraph, fir, levelCounter, createId())

View File

@@ -307,6 +307,24 @@ abstract class ControlFlowGraphVisitor<out R, in D> {
return visitNode(node, data)
}
// ----------------------------------- Elvis -----------------------------------
open fun visitElvisLhsExitNode(node: ElvisLhsExitNode, data: D): R {
return visitNode(node, data)
}
open fun visitElvisLhsIsNotNullNode(node: ElvisLhsIsNotNullNode, data: D): R {
return visitNode(node, data)
}
open fun visitElvisRhsEnterNode(node: ElvisRhsEnterNode, data: D): R {
return visitNode(node, data)
}
open fun visitElvisExitNode(node: ElvisExitNode, data: D): R {
return visitNode(node, data)
}
// ----------------------------------- Other -----------------------------------
open fun visitAnnotationEnterNode(node: AnnotationEnterNode, data: D): R {

View File

@@ -134,12 +134,13 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
c,
c.notFixedTypeVariables.getValue(variable.typeConstructor),
TypeVariableDirectionCalculator.ResolveDirection.TO_SUPERTYPE
) as ConeKotlinType).lowerBoundIfFlexible() as ConeClassLikeType
) as ConeKotlinType).lowerBoundIfFlexible()
val isExtensionWithoutParameters = false
// TODO
// functionalType.isExtensionFunctionType && functionalType.arguments.size == 2 && parameterTypes?.isEmpty() == true
if (parameterTypes?.all { type -> type != null } == true && !isExtensionWithoutParameters) return this
if (!functionalType.isSuitable()) return this
require(functionalType is ConeClassLikeType)
val returnVariable = typeVariableCreator()
csBuilder.registerVariable(returnVariable)
@@ -292,6 +293,12 @@ fun FirStatement.processAllContainingCallCandidates(processBlocks: Boolean, proc
processCandidateIfApplicable(processor, processBlocks)
this.arguments.forEach { it.processAllContainingCallCandidates(processBlocks, processor) }
}
is FirElvisExpression -> {
processCandidateIfApplicable(processor, processBlocks)
lhs.processAllContainingCallCandidates(processBlocks, processor)
rhs.processAllContainingCallCandidates(processBlocks, processor)
}
}
}

View File

@@ -423,14 +423,21 @@ class FirCallCompletionResultsWriterTransformer(
// Transformations for synthetic calls generated by FirSyntheticCallGenerator
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: ExpectedArgumentType?) =
transformSyntheticCall(whenExpression, data)
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: ExpectedArgumentType?): CompositeTransformResult<FirStatement> {
return transformSyntheticCall(whenExpression, data)
}
override fun transformTryExpression(tryExpression: FirTryExpression, data: ExpectedArgumentType?) =
transformSyntheticCall(tryExpression, data)
override fun transformTryExpression(tryExpression: FirTryExpression, data: ExpectedArgumentType?): CompositeTransformResult<FirStatement> {
return transformSyntheticCall(tryExpression, data)
}
override fun transformCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, data: ExpectedArgumentType?) =
transformSyntheticCall(checkNotNullCall, data)
override fun transformCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, data: ExpectedArgumentType?): CompositeTransformResult<FirStatement> {
return transformSyntheticCall(checkNotNullCall, data)
}
override fun transformElvisExpression(elvisExpression: FirElvisExpression, data: ExpectedArgumentType?): CompositeTransformResult<FirStatement> {
return transformSyntheticCall(elvisExpression, data)
}
private inline fun <reified D> transformSyntheticCall(
syntheticCall: D,

View File

@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.SyntheticCallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
@@ -47,6 +48,7 @@ class FirSyntheticCallGenerator(
private val trySelectFunction: FirSimpleFunction = generateSyntheticSelectFunction(SyntheticCallableId.TRY)
private val idFunction: FirSimpleFunction = generateSyntheticSelectFunction(SyntheticCallableId.ID)
private val checkNotNullFunction: FirSimpleFunction = generateSyntheticCheckNotNullFunction()
private val elvisFunction: FirSimpleFunction = generateSyntheticElvisFunction()
fun generateCalleeForWhenExpression(whenExpression: FirWhenExpression): FirWhenExpression? {
val stubReference = whenExpression.calleeReference
@@ -101,6 +103,22 @@ class FirSyntheticCallGenerator(
return checkNotNullCall.transformCalleeReference(UpdateReference, reference)
}
fun generateCalleeForElvisExpression(elvisExpression: FirElvisExpression): FirElvisExpression? {
if (elvisExpression.calleeReference !is FirStubReference) return null
val argumentList = buildArgumentList {
arguments += elvisExpression.lhs
arguments += elvisExpression.rhs
}
val reference = generateCalleeReferenceWithCandidate(
elvisFunction,
argumentList,
SyntheticCallableId.ELVIS_NOT_NULL.callableName
) ?: return null
return elvisExpression.transformCalleeReference(UpdateReference, reference)
}
fun resolveCallableReferenceWithSyntheticOuterCall(
callableReferenceAccess: FirCallableReferenceAccess,
expectedTypeRef: FirTypeRef?
@@ -225,6 +243,42 @@ class FirSyntheticCallGenerator(
}.build()
}
private fun generateSyntheticElvisFunction(): FirSimpleFunction {
// Synthetic function signature:
// fun <K> checkNotNull(x: K?, y: K): @Exact K
//
// Note: The upper bound of `K` cannot be `Any` because of the following case:
// fun <X> test(a: X, b: X) = a ?: b
// `X` is not a subtype of `Any` and hence cannot satisfy `K` if it had an upper bound of `Any`.
val functionSymbol = FirSyntheticFunctionSymbol(SyntheticCallableId.ELVIS_NOT_NULL)
val (typeParameter, rightArgumentType) = generateSyntheticSelectTypeParameter()
val leftArgumentType = buildResolvedTypeRef {
type = rightArgumentType.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE, session.typeContext)
}
val returnType = rightArgumentType.resolvedTypeFromPrototype(
rightArgumentType.type.withAttributes(
ConeAttributes.create(listOf(CompilerConeAttributes.Exact))
)
)
val typeArgument = buildTypeProjectionWithVariance {
typeRef = returnType
variance = Variance.INVARIANT
}
return generateMemberFunction(
functionSymbol,
SyntheticCallableId.ELVIS_NOT_NULL.callableName,
typeArgument.typeRef
).apply {
typeParameters += typeParameter
valueParameters += leftArgumentType.toValueParameter("x")
valueParameters += rightArgumentType.toValueParameter("y")
}.build()
}
private fun generateMemberFunction(
symbol: FirNamedFunctionSymbol, name: Name, returnType: FirTypeRef
): FirSimpleFunctionBuilder {

View File

@@ -304,6 +304,10 @@ open class FirBodyResolveTransformer(
return controlFlowStatementsTransformer.transformThrowExpression(throwExpression, data)
}
override fun transformElvisExpression(elvisExpression: FirElvisExpression, data: ResolutionMode): CompositeTransformResult<FirStatement> {
return controlFlowStatementsTransformer.transformElvisExpression(elvisExpression, data)
}
// --------------------------------------------------------------------------
fun <D> FirElement.visitNoTransform(transformer: FirTransformer<D>, data: D) {

View File

@@ -68,19 +68,18 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
@Suppress("NAME_SHADOWING")
var whenExpression = whenExpression.transformSubject(transformer, ResolutionMode.ContextIndependent)
val callCompleted = when {
whenExpression.branches.isEmpty() -> true
when {
whenExpression.branches.isEmpty() -> {}
whenExpression.isOneBranch() -> {
whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextIndependent)
whenExpression.resultType = whenExpression.branches.first().result.resultType
true
}
else -> {
whenExpression = whenExpression.transformBranches(transformer, ResolutionMode.ContextDependent)
whenExpression = syntheticCallGenerator.generateCalleeForWhenExpression(whenExpression) ?: run {
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted = true)
dataFlowAnalyzer.exitWhenExpression(whenExpression)
whenExpression.resultType = buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic("Can't resolve when expression", DiagnosticKind.InferenceError)
}
@@ -90,11 +89,10 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
val expectedTypeRef = data.expectedType
val completionResult = callCompleter.completeCall(whenExpression, expectedTypeRef)
whenExpression = completionResult.result
completionResult.callCompleted
}
}
whenExpression = whenExpression.transformSingle(whenExhaustivenessTransformer, null)
dataFlowAnalyzer.exitWhenExpression(whenExpression, callCompleted)
dataFlowAnalyzer.exitWhenExpression(whenExpression)
whenExpression = whenExpression.replaceReturnTypeIfNotExhaustive()
whenExpression.compose()
}
@@ -208,4 +206,25 @@ class FirControlFlowStatementsResolveTransformer(transformer: FirBodyResolveTran
dataFlowAnalyzer.exitThrowExceptionNode(it.single as FirThrowExpression)
}
}
// ------------------------------- Elvis -------------------------------
override fun transformElvisExpression(elvisExpression: FirElvisExpression, data: ResolutionMode): CompositeTransformResult<FirStatement> {
if (elvisExpression.calleeReference is FirResolvedNamedReference) return elvisExpression.compose()
elvisExpression.transformAnnotations(transformer, data)
elvisExpression.transformLhs(transformer, ResolutionMode.ContextDependent)
dataFlowAnalyzer.exitElvisLhs(elvisExpression)
elvisExpression.transformRhs(transformer, ResolutionMode.ContextDependent)
val result = syntheticCallGenerator.generateCalleeForElvisExpression(elvisExpression)?.let {
callCompleter.completeCall(it, data.expectedType).result
} ?: elvisExpression.also {
it.resultType = buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic("Can't resolve ?: operator call", DiagnosticKind.InferenceError)
}
}
dataFlowAnalyzer.exitElvis()
return result.compose()
}
}

View File

@@ -385,7 +385,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
typeOperatorCall: FirTypeOperatorCall,
data: ResolutionMode,
): CompositeTransformResult<FirStatement> {
val resolved = transformExpression(typeOperatorCall, data).single as FirTypeOperatorCall
val resolved = transformExpression(typeOperatorCall, ResolutionMode.ContextIndependent).single as FirTypeOperatorCall
resolved.argumentList.transformArguments(integerLiteralTypeApproximator, null)
val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument)
resolved.transformChildren(object : FirDefaultTransformer<Nothing?>() {

View File

@@ -6,14 +6,12 @@
package org.jetbrains.kotlin.fir.types
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.name.ClassId
@@ -22,7 +20,6 @@ import org.jetbrains.kotlin.types.AbstractNullabilityChecker
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker
import org.jetbrains.kotlin.types.AbstractTypeCheckerContext
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
object ConeNullabilityChecker {
fun isSubtypeOfAny(context: ConeTypeContext, type: ConeKotlinType): Boolean {
@@ -106,6 +103,21 @@ fun <T : ConeKotlinType> T.withArguments(arguments: Array<out ConeTypeProjection
}
}
fun <T : ConeKotlinType> T.withAttributes(attributes: ConeAttributes): T {
if (this.attributes == attributes) {
return this
}
@Suppress("UNCHECKED_CAST")
return when (this) {
is ConeClassErrorType -> this
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(lookupTag, typeArguments, nullability.isNullable, attributes)
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType.create(original.withAttributes(attributes))!!
is ConeTypeParameterTypeImpl -> ConeTypeParameterTypeImpl(lookupTag, nullability.isNullable, attributes)
else -> error("Not supported: $this: ${this.render()}")
} as T
}
fun ConeTypeContext.hasNullableSuperType(type: ConeKotlinType): Boolean {
if (type is ConeClassLikeType) return false

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2010-2020 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.expressions
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
abstract class FirElvisExpression : FirExpression(), FirResolvable {
abstract override val source: FirSourceElement?
abstract override val typeRef: FirTypeRef
abstract override val annotations: List<FirAnnotationCall>
abstract override val calleeReference: FirReference
abstract val lhs: FirExpression
abstract val rhs: FirExpression
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitElvisExpression(this, data)
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract override fun replaceCalleeReference(newCalleeReference: FirReference)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirElvisExpression
abstract override fun <D> transformCalleeReference(transformer: FirTransformer<D>, data: D): FirElvisExpression
abstract fun <D> transformLhs(transformer: FirTransformer<D>, data: D): FirElvisExpression
abstract fun <D> transformRhs(transformer: FirTransformer<D>, data: D): FirElvisExpression
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2010-2020 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.expressions.builder
import kotlin.contracts.*
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.builder.FirAnnotationContainerBuilder
import org.jetbrains.kotlin.fir.builder.FirBuilderDsl
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirElvisExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.builder.FirExpressionBuilder
import org.jetbrains.kotlin.fir.expressions.impl.FirElvisExpressionImpl
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.impl.FirStubReference
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
@FirBuilderDsl
class FirElvisExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBuilder {
override var source: FirSourceElement? = null
override val annotations: MutableList<FirAnnotationCall> = mutableListOf()
var calleeReference: FirReference = FirStubReference
lateinit var lhs: FirExpression
lateinit var rhs: FirExpression
override fun build(): FirElvisExpression {
return FirElvisExpressionImpl(
source,
annotations,
calleeReference,
lhs,
rhs,
)
}
@Deprecated("Modification of 'typeRef' has no impact for FirElvisExpressionBuilder", level = DeprecationLevel.HIDDEN)
override var typeRef: FirTypeRef
get() = throw IllegalStateException()
set(value) {
throw IllegalStateException()
}
}
@OptIn(ExperimentalContracts::class)
inline fun buildElvisExpression(init: FirElvisExpressionBuilder.() -> Unit): FirElvisExpression {
contract {
callsInPlace(init, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
}
return FirElvisExpressionBuilder().apply(init).build()
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2010-2020 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.expressions.impl
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirElvisExpression
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
import org.jetbrains.kotlin.fir.visitors.*
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
internal class FirElvisExpressionImpl(
override val source: FirSourceElement?,
override val annotations: MutableList<FirAnnotationCall>,
override var calleeReference: FirReference,
override var lhs: FirExpression,
override var rhs: FirExpression,
) : FirElvisExpression() {
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
calleeReference.accept(visitor, data)
lhs.accept(visitor, data)
rhs.accept(visitor, data)
}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElvisExpressionImpl {
typeRef = typeRef.transformSingle(transformer, data)
transformAnnotations(transformer, data)
transformCalleeReference(transformer, data)
transformLhs(transformer, data)
transformRhs(transformer, data)
return this
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirElvisExpressionImpl {
annotations.transformInplace(transformer, data)
return this
}
override fun <D> transformCalleeReference(transformer: FirTransformer<D>, data: D): FirElvisExpressionImpl {
calleeReference = calleeReference.transformSingle(transformer, data)
return this
}
override fun <D> transformLhs(transformer: FirTransformer<D>, data: D): FirElvisExpressionImpl {
lhs = lhs.transformSingle(transformer, data)
return this
}
override fun <D> transformRhs(transformer: FirTransformer<D>, data: D): FirElvisExpressionImpl {
rhs = rhs.transformSingle(transformer, data)
return this
}
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
override fun replaceCalleeReference(newCalleeReference: FirReference) {
calleeReference = newCalleeReference
}
}

View File

@@ -76,6 +76,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessWithoutCallee
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
import org.jetbrains.kotlin.fir.expressions.FirElvisExpression
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirAugmentedArraySetCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
@@ -419,6 +420,10 @@ abstract class FirTransformer<in D> : FirVisitor<CompositeTransformResult<FirEle
return transformElement(checkNotNullCall, data)
}
open fun transformElvisExpression(elvisExpression: FirElvisExpression, data: D): CompositeTransformResult<FirStatement> {
return transformElement(elvisExpression, data)
}
open fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: D): CompositeTransformResult<FirStatement> {
return transformElement(arrayOfCall, data)
}
@@ -911,6 +916,10 @@ abstract class FirTransformer<in D> : FirVisitor<CompositeTransformResult<FirEle
return transformCheckNotNullCall(checkNotNullCall, data)
}
final override fun visitElvisExpression(elvisExpression: FirElvisExpression, data: D): CompositeTransformResult<FirStatement> {
return transformElvisExpression(elvisExpression, data)
}
final override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: D): CompositeTransformResult<FirStatement> {
return transformArrayOfCall(arrayOfCall, data)
}

View File

@@ -76,6 +76,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessWithoutCallee
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
import org.jetbrains.kotlin.fir.expressions.FirElvisExpression
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirAugmentedArraySetCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
@@ -277,6 +278,8 @@ abstract class FirVisitor<out R, in D> {
open fun visitCheckNotNullCall(checkNotNullCall: FirCheckNotNullCall, data: D): R = visitElement(checkNotNullCall, data)
open fun visitElvisExpression(elvisExpression: FirElvisExpression, data: D): R = visitElement(elvisExpression, data)
open fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: D): R = visitElement(arrayOfCall, data)
open fun visitAugmentedArraySetCall(augmentedArraySetCall: FirAugmentedArraySetCall, data: D): R = visitElement(augmentedArraySetCall, data)

View File

@@ -76,6 +76,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhenBranch
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessWithoutCallee
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
import org.jetbrains.kotlin.fir.expressions.FirElvisExpression
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
import org.jetbrains.kotlin.fir.expressions.FirAugmentedArraySetCall
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
@@ -417,6 +418,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitElement(checkNotNullCall)
}
open fun visitElvisExpression(elvisExpression: FirElvisExpression) {
visitElement(elvisExpression)
}
open fun visitArrayOfCall(arrayOfCall: FirArrayOfCall) {
visitElement(arrayOfCall)
}
@@ -909,6 +914,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitCheckNotNullCall(checkNotNullCall)
}
final override fun visitElvisExpression(elvisExpression: FirElvisExpression, data: Nothing?) {
visitElvisExpression(elvisExpression)
}
final override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: Nothing?) {
visitArrayOfCall(arrayOfCall)
}

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