Compare commits

...

27 Commits

Author SHA1 Message Date
Dmitry Petrov
ef461d4a3a JVM_IR KT-36646 fuze primitive equality with safe call 2021-04-27 16:22:53 +03:00
Dmitry Petrov
eaf870bfd4 JVM_IR update test for KT-36637 2021-04-27 16:22:52 +03:00
Dmitry Petrov
e8982765c8 JVM_IR use static 'hashCode' for boxed primitives on JVM 1.8+ 2021-04-27 16:22:52 +03:00
Andrey Zinovyev
0c6066db74 [KAPT] Don't fail on illegal delegate
Kapt ignores error diagnostics, but backend can't
 compile such code at all
This is workaround so backend won't fail.
#KT-46176 Fixed
2021-04-27 16:18:44 +03:00
Ilmir Usmanov
0c0710bb79 Fix outer class accesses inside suspendImpl functions
We need to generate this$0 fields to get to the outer class and generate
accesses to these fields inside suspendImpl function.
 #KT-46214 Fixed
2021-04-27 10:44:18 +02:00
Pavel Kirpichenkov
71365d2452 [IDE] Move library dependency filtering to dependencies cache
The primary client of LibraryDependenciesCache is LibraryInfo,
but it is also used for maintaining modification trackers of
source-dependent libraries. Moving dependency filtering to
cache allows keeping all client in sync.

^KT-45908 In Progress
2021-04-27 10:14:13 +03:00
Mikhael Bogdanov
dfc6d85aee Enable runtime string concatenation by default (for -Xjvm-target=9 or greater)
#KT-42522 Fixed
2021-04-27 09:08:28 +02:00
Ilmir Usmanov
dc2485ae71 Support suspend functions as superinterfaces
Forbid mixing suspend and non-suspend functional supertypes.
Since JVM BE generates suspend functional types as non-suspend ones
with SuspendFunction marker interface, there is not way to distinguish
non-suspend functional type from suspend one if they are mixed.
 #KT-18707 Fixed
2021-04-26 22:14:32 +02:00
Alexander Udalov
37ccd82b6c Fix some warnings in kotlin-gradle-plugin 2021-04-26 22:02:26 +03:00
Alexander Udalov
19a5c2f1c8 Fix warnings related to appendln in kotlin-gradle-plugin
`appendln` is deprecated, but its replacement `appendLine` can't be used
yet in kotlin-gradle-plugin because it's compiled with API version 1.3.
2021-04-26 22:02:25 +03:00
Alexander Udalov
e5128a8772 Improve generated code for Gradle properties
Fix warnings about double nullability and useless elvis.
2021-04-26 22:02:24 +03:00
Svyatoslav Kuzmich
ccc27b6a0c [IR] Add module property to IrFile 2021-04-26 18:52:42 +03:00
Vasily Levchenko
6f2af740cb [kotlin-native][tests][lldb] adds possibility to run simple lldb scenarious with simulator 2021-04-26 14:46:51 +00:00
Ilya Gorbunov
ed3542cdf5 Support covariant MutableMap.entries.remove in JS/IR
Workaround for KT-43321
Follow up to KT-41278
2021-04-26 17:45:27 +03:00
Anton Yalyshev
666ad1f9d5 1.5.0 Change-notes correction. Restore excessively removed items 2021-04-26 16:23:11 +03:00
Anton Yalyshev
ea7ea979ee 1.5.0 Change-notes correction according to KT-42522 2021-04-26 16:01:00 +03:00
Ilya Kirillov
e2acc507d4 FIR IDE: fix inconsistency in element collecting in DiagnosticTraversalCounterTest 2021-04-26 15:11:47 +03:00
Dmitriy Novozhilov
9cb740bfdb Fix tests broken in c6fa3634 2021-04-26 15:11:46 +03:00
Steven Schäfer
a1c1a32515 JVM: Fix unsigned literals in API version < 1.5 2021-04-26 15:11:45 +03:00
Mark Punzalan
af2d0ad36f FIR: Properly set light-tree source for all nested types (e.g.,
nullable function type) and error type refs.
2021-04-26 15:11:44 +03:00
Mark Punzalan
1835185b16 FIR: Remove duplicated diagnostics on annotations on types. 2021-04-26 15:11:43 +03:00
Mark Punzalan
edb6b337dc FIR: Resolve anonymous function bodies during
IMPLICIT_TYPES_BODY_RESOLVE phase.

This fixes an issue where some FirAnnotationCalls can be left with some
implicit type refs if they have anonymous functions in the arguments.
2021-04-26 15:11:42 +03:00
Mark Punzalan
e69b729e21 FIR checker: Create a new kind of checker FirTypeChecker and add
FirSuspendModifierChecker to report WRONG_MODIFIER_TARGET for `suspend`
on  non-functional types.
2021-04-26 15:11:41 +03:00
Dmitriy Novozhilov
4282d17467 [FIR] Optimize imports 2021-04-26 15:11:40 +03:00
Mark Punzalan
b88913af1d FIR checker: Report WRONG_MODIFIER_TARGET for suspend on
non-functional types.
2021-04-26 15:11:39 +03:00
Mark Punzalan
9a4742c08d FIR: Properly build nullable suspend function types, and aggregate
modifiers and annotations within KtTypeReference/REFERENCE_TYPE nodes.
2021-04-26 15:11:38 +03:00
Mark Punzalan
9cf5ac1fbd FIR: Render "?" on nullable function types. 2021-04-26 15:11:37 +03:00
251 changed files with 3726 additions and 653 deletions

View File

@@ -188,6 +188,12 @@ class JvmRuntimeTypes(
else -> if (isMutable) mutablePropertyReferences else propertyReferences
}
return classes[arity].defaultType
return if (arity >= 0) {
classes[arity].defaultType
} else {
//in case of ErrorUtils.ERROR_PROPERTY there would be no dispatchReceiverParameter and arity becomes negative
//so we just take zero argument reference class (because it is incorrect anyway)
classes[0].defaultType
}
}
}

View File

@@ -39,7 +39,7 @@ class RedundantBoxingMethodTransformer(private val generationState: GenerationSt
override fun transform(internalClassName: String, node: MethodNode) {
val interpreter = RedundantBoxingInterpreter(node.instructions, generationState)
val frames = MethodTransformer.analyze(internalClassName, node, interpreter)
val frames = analyze(internalClassName, node, interpreter)
interpretPopInstructionsForBoxedValues(interpreter, node, frames)
@@ -168,7 +168,8 @@ class RedundantBoxingMethodTransformer(private val generationState: GenerationSt
val frame = frames[i] ?: continue
val insn = insnList[i]
if ((insn.opcode == Opcodes.ASTORE || insn.opcode == Opcodes.ALOAD) &&
(insn as VarInsnNode).`var` == localVariableNode.index) {
(insn as VarInsnNode).`var` == localVariableNode.index
) {
if (insn.getOpcode() == Opcodes.ASTORE) {
values.add(frame.top()!!)
} else {

View File

@@ -377,7 +377,7 @@ class K2JVMCompilerArguments : CommonCompilerArguments() {
default: `indy-with-constants` for JVM target 9 or greater, `inline` otherwise"""
)
var stringConcat: String? by NullableStringFreezableVar(JvmStringConcat.INLINE.description)
var stringConcat: String? by NullableStringFreezableVar(null)
@Argument(
value = "-Xsam-conversions",

View File

@@ -54,19 +54,20 @@ fun CompilerConfiguration.setupJvmSpecificArguments(arguments: K2JVMCompilerArgu
}
}
if (arguments.stringConcat != null) {
val runtimeStringConcat = JvmStringConcat.fromString(arguments.stringConcat!!)
val stringConcat = arguments.stringConcat
if (stringConcat != null) {
val runtimeStringConcat = JvmStringConcat.fromString(stringConcat)
if (runtimeStringConcat != null) {
put(JVMConfigurationKeys.STRING_CONCAT, runtimeStringConcat)
if (jvmTarget.majorVersion < JvmTarget.JVM_9.majorVersion && runtimeStringConcat != JvmStringConcat.INLINE) {
messageCollector.report(
WARNING,
"`-Xstring-concat=${arguments.stringConcat}` does nothing with JVM target `${jvmTarget.description}`."
"`-Xstring-concat=$stringConcat` does nothing with JVM target `${jvmTarget.description}`."
)
}
} else {
messageCollector.report(
ERROR, "Unknown `-Xstring-concat` mode: ${arguments.stringConcat}\n" +
ERROR, "Unknown `-Xstring-concat` mode: $stringConcat\n" +
"Supported modes: ${JvmStringConcat.values().joinToString { it.description }}"
)
}

View File

@@ -1,5 +1,5 @@
public open class MethodWithFunctionTypes : R|kotlin/Any| {
public open fun foo(f: R|(kotlin/String?) -> kotlin/String|): R|kotlin/String.() -> kotlin/String?|
public open fun foo(f: R|(kotlin/String?) -> kotlin/String|): R|(kotlin/String.() -> kotlin/String?)?|
public constructor(): R|test/MethodWithFunctionTypes|

View File

@@ -1,8 +1,16 @@
public final fun test1(): R|suspend () -> kotlin/Unit|
public final fun test1N(): R|(suspend () -> kotlin/Unit)?|
public final fun test2(): R|suspend kotlin/Int.() -> kotlin/Int|
public final fun test2N(): R|(suspend kotlin/Int.() -> kotlin/Int)?|
public final fun test3(): R|kotlin/collections/List<kotlin/coroutines/SuspendFunction0<kotlin/Unit>>|
public final fun test3N(): R|kotlin/collections/List<kotlin/coroutines/SuspendFunction0<kotlin/Unit>?>|
public final fun test4(): R|suspend () -> kotlin/coroutines/SuspendFunction0<kotlin/Unit>|
public final fun test4N(): R|(suspend () -> kotlin/coroutines/SuspendFunction0<kotlin/Unit>?)?|

View File

@@ -1,5 +1,5 @@
FILE: safeCallOnTypeAlias.kt
public final typealias MyTypeAlias = R|() -> kotlin/String?|
public final typealias MyTypeAlias = R|(() -> kotlin/String?)?|
public final fun foo(x: R|MyTypeAlias|): R|kotlin/Unit| {
R|<local>/x|?.{ $subj$.R|kotlin/let|<R|() -> kotlin/String?|, R|kotlin/String?|>(<L> = let@fun <anonymous>(y: R|() -> kotlin/String?|): R|kotlin/String?| <inline=Inline, kind=EXACTLY_ONCE> {
^ R|<local>/y|.R|SubstitutionOverride<kotlin/Function0.invoke: R|kotlin/String?|>|()?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/String|>(<L> = let@fun <anonymous>(result: R|kotlin/String|): R|kotlin/String| <inline=Inline, kind=EXACTLY_ONCE> {

View File

@@ -18,7 +18,7 @@ FILE: kt41982.kt
}
}
public final fun <Type : R|Base|, Base : R|DelegateProvider<Base>|> R|Type|.long(initializer: R|() -> kotlin/Long?| = Null(null)): R|Delegate<Type, kotlin/Long>| {
public final fun <Type : R|Base|, Base : R|DelegateProvider<Base>|> R|Type|.long(initializer: R|(() -> kotlin/Long?)?| = Null(null)): R|Delegate<Type, kotlin/Long>| {
^long Null(null)!!
}
public final class Test : R|DelegateProvider<kotlin/Any>| {

View File

@@ -1,11 +1,11 @@
FILE: propertyWithExtensionType.kt
public final class A : R|kotlin/Any| {
public constructor(x: R|kotlin/String.() -> kotlin/Unit|, y: R|kotlin/String.() -> kotlin/Int|): R|A| {
public constructor(x: R|(kotlin/String.() -> kotlin/Unit)?|, y: R|kotlin/String.() -> kotlin/Int|): R|A| {
super<R|kotlin/Any|>()
}
public final val x: R|kotlin/String.() -> kotlin/Unit| = R|<local>/x|
public get(): R|kotlin/String.() -> kotlin/Unit|
public final val x: R|(kotlin/String.() -> kotlin/Unit)?| = R|<local>/x|
public get(): R|(kotlin/String.() -> kotlin/Unit)?|
public final val y: R|kotlin/String.() -> kotlin/Int| = R|<local>/y|
public get(): R|kotlin/String.() -> kotlin/Int|
@@ -14,7 +14,7 @@ FILE: propertyWithExtensionType.kt
public final fun test(a: R|A|): R|kotlin/Unit| {
when () {
!=(R|<local>/a|.R|/A.x|, Null(null)) -> {
lval b: R|kotlin/String.() -> kotlin/Unit| = R|<local>/a|.R|/A.x|
lval b: R|(kotlin/String.() -> kotlin/Unit)?| = R|<local>/a|.R|/A.x|
R|<local>/b|.R|SubstitutionOverride<kotlin/Function1.invoke: R|kotlin/Unit|>|(String())
}
}

View File

@@ -5,7 +5,7 @@ interface I {
}
class A {
fun too(): <!NOT_AN_ANNOTATION_CLASS, NOT_AN_ANNOTATION_CLASS!>@Annotation<!> Unit {}
fun too(): <!NOT_AN_ANNOTATION_CLASS!>@Annotation<!> Unit {}
fun foo(): <!REDUNDANT_RETURN_UNIT_TYPE!>Unit<!>
{

View File

@@ -8,8 +8,8 @@ FILE: kt41989.kt
}
public abstract interface C : R|B| {
public open val lineCellStyle: R|A.() -> kotlin/Unit|
public get(): R|A.() -> kotlin/Unit| {
public open val lineCellStyle: R|(A.() -> kotlin/Unit)?|
public get(): R|(A.() -> kotlin/Unit)?| {
^ when () {
R|/cond|() -> {
fun R|A|.<anonymous>(): R|kotlin/Unit| <inline=Unknown> {

View File

@@ -21,14 +21,14 @@ FILE: lambdaArgInScopeFunction.kt
this@R|special/anonymous|.R|/_|<R|KotlinClass?|>()
}
)
lval lambda: R|() -> KotlinClass| = R|<local>/kotlinClass|?.{ $subj$.R|kotlin/let|<R|KotlinClass|, R|() -> KotlinClass|>(<L> = let@fun <anonymous>(it: R|KotlinClass|): R|() -> KotlinClass| <inline=Inline, kind=EXACTLY_ONCE> {
lval lambda: R|(() -> KotlinClass)?| = R|<local>/kotlinClass|?.{ $subj$.R|kotlin/let|<R|KotlinClass|, R|() -> KotlinClass|>(<L> = let@fun <anonymous>(it: R|KotlinClass|): R|() -> KotlinClass| <inline=Inline, kind=EXACTLY_ONCE> {
^ let@fun <anonymous>(): R|KotlinClass| <inline=Unknown> {
^ R|<local>/it|
}
}
) }
R|<local>/lambda|.R|/checkType|<R|() -> KotlinClass|>(<L> = checkType@fun R|CheckTypeInv<kotlin/Function0<KotlinClass>?>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
R|<local>/lambda|.R|/checkType|<R|(() -> KotlinClass)?|>(<L> = checkType@fun R|CheckTypeInv<kotlin/Function0<KotlinClass>?>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
this@R|special/anonymous|.<Inapplicable(INAPPLICABLE_WRONG_RECEIVER): /_>#<R|(kotlin/Unit) -> KotlinClass?|>()
}
)

View File

@@ -1,5 +1,5 @@
FILE: smartcastOnLambda.kt
public final fun test(func: R|() -> kotlin/Unit|): R|kotlin/Unit| {
public final fun test(func: R|(() -> kotlin/Unit)?|): R|kotlin/Unit| {
when () {
!=(R|<local>/func|, Null(null)) -> {
R|<local>/func|.R|SubstitutionOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()

View File

@@ -5680,6 +5680,136 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/coroutines/callableReference/outsideSuspend.kt");
}
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype")
@TestDataPath("$PROJECT_ROOT")
public class SuspendFunctionAsSupertype {
@Test
public void testAllFilesPresentInSuspendFunctionAsSupertype() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN")
@TestDataPath("$PROJECT_ROOT")
public class KSuspendFunctionN {
@Test
public void testAllFilesPresentInKSuspendFunctionN() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypes.kt")
public void testMixingSuspendAndNonSuspendSupertypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypes.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperinterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple")
@TestDataPath("$PROJECT_ROOT")
public class Simple {
@Test
public void testAllFilesPresentInSimple() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypes.kt")
public void testMixingSuspendAndNonSuspendSupertypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypes.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperinterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN")
@TestDataPath("$PROJECT_ROOT")
public class SuspendFunctionN {
@Test
public void testAllFilesPresentInSuspendFunctionN() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypes.kt")
public void testMixingSuspendAndNonSuspendSupertypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypes.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperinterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/simple.kt");
}
}
}
}
@Nested

View File

@@ -5680,6 +5680,136 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/coroutines/callableReference/outsideSuspend.kt");
}
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype")
@TestDataPath("$PROJECT_ROOT")
public class SuspendFunctionAsSupertype {
@Test
public void testAllFilesPresentInSuspendFunctionAsSupertype() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN")
@TestDataPath("$PROJECT_ROOT")
public class KSuspendFunctionN {
@Test
public void testAllFilesPresentInKSuspendFunctionN() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypes.kt")
public void testMixingSuspendAndNonSuspendSupertypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypes.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperinterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/kSuspendFunctionN/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple")
@TestDataPath("$PROJECT_ROOT")
public class Simple {
@Test
public void testAllFilesPresentInSimple() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypes.kt")
public void testMixingSuspendAndNonSuspendSupertypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypes.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperinterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/simple/simple.kt");
}
}
@Nested
@TestMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN")
@TestDataPath("$PROJECT_ROOT")
public class SuspendFunctionN {
@Test
public void testAllFilesPresentInSuspendFunctionN() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypes.kt")
public void testMixingSuspendAndNonSuspendSupertypes() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypes.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperClass() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperClass.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperFunInterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperFunInterface.kt");
}
@Test
@TestMetadata("mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt")
public void testMixingSuspendAndNonSuspendSupertypesThruSuperinterface() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/mixingSuspendAndNonSuspendSupertypesThruSuperinterface.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/diagnostics/tests/coroutines/suspendFunctionAsSupertype/suspendFunctionN/simple.kt");
}
}
}
}
@Nested

View File

@@ -9,11 +9,17 @@ import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.DIAGNOSTICS_LIST
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.generateDiagnostics
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.types.FirTypeRef
import java.io.File
fun main(args: Array<String>) {
val generationPath = args.firstOrNull()?.let { File(it) } ?: File("compiler/fir/checkers/gen").absoluteFile
val typePackage = "org.jetbrains.kotlin.fir.analysis.checkers.type"
generateCheckersComponents(generationPath, typePackage, "FirTypeChecker") {
alias<FirTypeRef>("TypeRefChecker")
}
val expressionPackage = "org.jetbrains.kotlin.fir.analysis.checkers.expression"
generateCheckersComponents(generationPath, expressionPackage, "FirExpressionChecker") {
alias<FirStatement>("BasicExpressionChecker")

View File

@@ -0,0 +1,25 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.type
import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
internal class ComposedTypeCheckers : TypeCheckers() {
override val typeRefCheckers: Set<FirTypeRefChecker>
get() = _typeRefCheckers
private val _typeRefCheckers: MutableSet<FirTypeRefChecker> = mutableSetOf()
@CheckersComponentInternal
internal fun register(checkers: TypeCheckers) {
_typeRefCheckers += checkers.typeRefCheckers
}
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.type
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
import org.jetbrains.kotlin.fir.types.FirTypeRef
typealias FirTypeRefChecker = FirTypeChecker<FirTypeRef>

View File

@@ -0,0 +1,23 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.type
import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
abstract class TypeCheckers {
companion object {
val EMPTY: TypeCheckers = object : TypeCheckers() {}
}
open val typeRefCheckers: Set<FirTypeRefChecker> = emptySet()
@CheckersComponentInternal internal val allTypeRefCheckers: Set<FirTypeRefChecker> get() = typeRefCheckers
}

View File

@@ -13,6 +13,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.declaration.ComposedDeclaratio
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ComposedExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.ComposedTypeCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
@RequiresOptIn
@@ -26,6 +28,9 @@ class CheckersComponent : FirSessionComponent {
val expressionCheckers: ExpressionCheckers get() = _expressionCheckers
private val _expressionCheckers = ComposedExpressionCheckers()
val typeCheckers: TypeCheckers get() = _typeCheckers
private val _typeCheckers = ComposedTypeCheckers()
@SessionConfiguration
@OptIn(CheckersComponentInternal::class)
fun register(checkers: DeclarationCheckers) {
@@ -38,10 +43,17 @@ class CheckersComponent : FirSessionComponent {
_expressionCheckers.register(checkers)
}
@SessionConfiguration
@OptIn(CheckersComponentInternal::class)
fun register(checkers: TypeCheckers) {
_typeCheckers.register(checkers)
}
@SessionConfiguration
fun register(checkers: FirAdditionalCheckersExtension) {
register(checkers.declarationCheckers)
register(checkers.expressionCheckers)
register(checkers.typeCheckers)
}
}

View File

@@ -3,7 +3,7 @@
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
package org.jetbrains.kotlin.fir.analysis.checkers
import com.intellij.lang.ASTNode
import com.intellij.lang.LighterASTNode
@@ -11,8 +11,6 @@ import com.intellij.psi.tree.TokenSet
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtModifierList
@@ -95,6 +93,6 @@ internal fun FirSourceElement?.getModifierList(): FirModifierList? {
internal operator fun FirModifierList?.contains(token: KtModifierKeywordToken): Boolean = this?.contains(token) == true
internal fun FirDeclaration.getModifier(token: KtModifierKeywordToken): FirModifier<*>? = source.getModifierList()?.get(token)
internal fun FirElement.getModifier(token: KtModifierKeywordToken): FirModifier<*>? = source.getModifierList()?.get(token)
internal fun FirDeclaration.hasModifier(token: KtModifierKeywordToken): Boolean = token in source.getModifierList()
internal fun FirElement.hasModifier(token: KtModifierKeywordToken): Boolean = token in source.getModifierList()

View File

@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.canBeUsedForConstVal
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -9,7 +9,10 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirModifierList
import org.jetbrains.kotlin.fir.analysis.checkers.contains
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.checkers.modality
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors

View File

@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors

View File

@@ -7,7 +7,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.contains
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.cfa.PropertyInitializationInfo
import org.jetbrains.kotlin.fir.analysis.cfa.PropertyInitializationInfoCollector
import org.jetbrains.kotlin.fir.analysis.checkers.contains
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -7,7 +7,10 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.FirModifier
import org.jetbrains.kotlin.fir.analysis.checkers.FirModifierList
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*

View File

@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirProperty

View File

@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration.jvm
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirMemberDeclarationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirModifierList
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.getModifier
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.getModifierList
import org.jetbrains.kotlin.fir.analysis.checkers.getModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.type
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getModifier
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.types.FirFunctionTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRefWithNullability
import org.jetbrains.kotlin.lexer.KtTokens
object FirSuspendModifierChecker : FirTypeRefChecker() {
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
// We are only interested in source type refs (i.e., Fir(Dynamic|User|Function)TypeRef).
if (typeRef !is FirTypeRefWithNullability) return
val suspendModifier = typeRef.getModifier(KtTokens.SUSPEND_KEYWORD) ?: return
// `suspend` is invalid for non-function types (i.e., FirDynamicTypeRef or FirUserTypeRef).
//
// It is also invalid for nullable function types, e.g., `suspend (() -> Int)?`.
// The correct way to denote a nullable suspend function type is `(suspend () -> Int)?`.
// (To clarify: You can "mark nullable" a suspend function type, but you cannot "mark suspend" a nullable function type.)
//
// In both invalid and correct cases, the source for the FirFunctionTypeRef is the TYPE_REFERENCE element.
// In the invalid case, the `suspend` modifier is in the source TYPE_REFERENCE element.
// But in the correct case, the `suspend` modifier is in the child NULLABLE_TYPE element, i.e., the source TYPE_REFERENCE element
// will not have the `suspend` modifier.
//
// In both cases, the FirFunctionTypeRef is marked nullable. But it is invalid to have the `suspend` modifier on the source element.
if (typeRef !is FirFunctionTypeRef || typeRef.isMarkedNullable) {
reporter.reportOn(
suspendModifier.source,
FirErrors.WRONG_MODIFIER_TARGET,
suspendModifier.token,
"non-functional type",
context
)
}
}
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.type
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.types.FirTypeRef
abstract class FirTypeChecker<in T : FirTypeRef> {
/**
* [FirTypeChecker] should only be used when the check can be performed independent of the context of the type refs. That is,
* you should NOT be examining containing declarations, qualified accesses, etc. when writing a FirTypeChecker.
*
* If the check is dependent on context, or if it is specific to type refs in a certain kind of declaration or expression,
* please write a [org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirDeclarationChecker] or
* [org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecker] instead.
*/
abstract fun check(typeRef: T, context: CheckerContext, reporter: DiagnosticReporter)
}

View File

@@ -72,6 +72,7 @@ fun AbstractDiagnosticCollector.registerAllComponents() {
initializeComponents(
DeclarationCheckersDiagnosticComponent(this),
ExpressionCheckersDiagnosticComponent(this),
TypeCheckersDiagnosticComponent(this),
ErrorNodeDiagnosticCollectorComponent(this),
ControlFlowAnalysisDiagnosticComponent(this),
)

View File

@@ -15,11 +15,8 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.collectImplicitReceivers
import org.jetbrains.kotlin.fir.resolve.defaultType
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.name.Name
@@ -165,7 +162,12 @@ abstract class AbstractDiagnosticCollectorVisitor(
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: Nothing?) {
super.visitResolvedTypeRef(resolvedTypeRef, data)
// Assuming no errors, the children of FirResolvedTypeRef (currently this can be FirAnnotationCalls) will also be present
// as children in delegatedTypeRef. We should make sure those elements are only visited once, otherwise diagnostics will be
// collected twice: once through resolvedTypeRef's children and another through resolvedTypeRef.delegatedTypeRef's children.
if (resolvedTypeRef.type is ConeClassErrorType) {
super.visitResolvedTypeRef(resolvedTypeRef, data)
}
resolvedTypeRef.delegatedTypeRef?.accept(this, data)
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.collectors.components
import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeChecker
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.types.*
@OptIn(CheckersComponentInternal::class)
class TypeCheckersDiagnosticComponent(
collector: AbstractDiagnosticCollector,
private val checkers: TypeCheckers = collector.session.checkersComponent.typeCheckers,
) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitDynamicTypeRef(dynamicTypeRef: FirDynamicTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(dynamicTypeRef, data, reporter)
}
override fun visitFunctionTypeRef(functionTypeRef: FirFunctionTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(functionTypeRef, data, reporter)
}
override fun visitUserTypeRef(userTypeRef: FirUserTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(userTypeRef, data, reporter)
}
override fun visitResolvedTypeRef(resolvedTypeRef: FirResolvedTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(resolvedTypeRef, data, reporter)
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(errorTypeRef, data, reporter)
}
override fun visitTypeRefWithNullability(typeRefWithNullability: FirTypeRefWithNullability, data: CheckerContext) {
checkers.allTypeRefCheckers.check(typeRefWithNullability, data, reporter)
}
override fun visitImplicitTypeRef(implicitTypeRef: FirImplicitTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(implicitTypeRef, data, reporter)
}
override fun visitTypeRef(typeRef: FirTypeRef, data: CheckerContext) {
checkers.allTypeRefCheckers.check(typeRef, data, reporter)
}
private fun <T : FirTypeRef> Collection<FirTypeChecker<T>>.check(
typeRef: T,
context: CheckerContext,
reporter: DiagnosticReporter
) {
for (checker in this) {
checker.check(typeRef, context, reporter)
}
}
}

View File

@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.extensions
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
import org.jetbrains.kotlin.fir.extensions.AbstractFirAdditionalCheckersExtension
import org.jetbrains.kotlin.fir.extensions.FirExtensionPointName
import org.jetbrains.kotlin.fir.extensions.FirExtensionService
@@ -19,6 +20,7 @@ abstract class FirAdditionalCheckersExtension(session: FirSession) : AbstractFir
open val declarationCheckers: DeclarationCheckers = DeclarationCheckers.EMPTY
open val expressionCheckers: ExpressionCheckers = ExpressionCheckers.EMPTY
open val typeCheckers: TypeCheckers = TypeCheckers.EMPTY
final override val name: FirExtensionPointName
get() = NAME

View File

@@ -69,7 +69,7 @@ fun ConeKotlinType.renderFunctionType(
kind: FunctionClassKind?, isExtension: Boolean, renderType: ConeTypeProjection.() -> String = { render() }
): String {
if (!kind.withPrettyRender()) return renderType()
return buildString {
val renderedType = buildString {
if (kind == FunctionClassKind.SuspendFunction) {
append("suspend ")
}
@@ -88,6 +88,7 @@ fun ConeKotlinType.renderFunctionType(
append(" -> ")
append(returnType.renderType())
}
return if (isMarkedNullable) "($renderedType)?" else renderedType
}
@OptIn(ExperimentalContracts::class)

View File

@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.session.FirSessionFactory
fun FirSessionFactory.FirSessionConfigurator.registerCommonCheckers() {
useCheckers(CommonDeclarationCheckers)
useCheckers(CommonExpressionCheckers)
useCheckers(CommonTypeCheckers)
}
fun FirSessionFactory.FirSessionConfigurator.registerExtendedCommonCheckers() {

View File

@@ -0,0 +1,22 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.checkers
import org.jetbrains.kotlin.fir.analysis.cfa.AbstractFirPropertyInitializationChecker
import org.jetbrains.kotlin.fir.analysis.cfa.FirCallsEffectAnalyzer
import org.jetbrains.kotlin.fir.analysis.cfa.FirPropertyInitializationAnalyzer
import org.jetbrains.kotlin.fir.analysis.cfa.FirReturnsImpliesAnalyzer
import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirSuspendModifierChecker
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeRefChecker
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
object CommonTypeCheckers : TypeCheckers() {
override val typeRefCheckers: Set<FirTypeRefChecker> = setOf(
FirSuspendModifierChecker
)
}

View File

@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.PrivateSessionConstructor
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
import org.jetbrains.kotlin.fir.analysis.checkersComponent
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers
@@ -53,6 +54,10 @@ object FirSessionFactory {
session.checkersComponent.register(checkers)
}
fun useCheckers(checkers: TypeCheckers) {
session.checkersComponent.register(checkers)
}
@SessionConfiguration
fun configure() {
session.extensionService.registerExtensions(registeredExtensions.reduce(BunchOfRegisteredExtensions::plus))

View File

@@ -55,10 +55,11 @@ class Fir2IrConverter(
processClassMembers(regularClass, irClass)
}
fun registerFileAndClasses(file: FirFile): IrFile {
fun registerFileAndClasses(file: FirFile, moduleFragment: IrModuleFragment) {
val irFile = IrFileImpl(
PsiIrFileEntry(file.psi as KtFile),
moduleDescriptor.getPackage(file.packageFqName).fragments.first()
moduleDescriptor.getPackage(file.packageFqName).fragments.first(),
moduleFragment
)
declarationStorage.registerFile(file, irFile)
file.declarations.forEach {
@@ -66,7 +67,7 @@ class Fir2IrConverter(
registerClassAndNestedClasses(it, irFile)
}
}
return irFile
moduleFragment.files += irFile
}
fun processClassHeaders(file: FirFile) {
@@ -279,12 +280,11 @@ class Fir2IrConverter(
components.visibilityConverter = visibilityConverter
components.builtIns = builtIns
components.annotationGenerator = annotationGenerator
val irFiles = mutableListOf<IrFile>()
val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, irBuiltIns)
for (firFile in firFiles) {
irFiles += converter.registerFileAndClasses(firFile)
converter.registerFileAndClasses(firFile, irModuleFragment)
}
val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, irBuiltIns, irFiles)
val irProviders =
generateTypicalIrProviderList(irModuleFragment.descriptor, irBuiltIns, symbolTable, extensions = generatorExtensions)
val externalDependenciesGenerator = ExternalDependenciesGenerator(

View File

@@ -2794,6 +2794,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/callableReference/adaptedReferences/suspendConversion/isAs.kt");
}
@Test
@TestMetadata("nullableParameter.kt")
public void testNullableParameter() throws Exception {
runTest("compiler/testData/codegen/box/callableReference/adaptedReferences/suspendConversion/nullableParameter.kt");
}
@Test
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
@@ -9252,6 +9258,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambdaDeep.kt");
}
@Test
@TestMetadata("nullableSuspendFunctionType.kt")
public void testNullableSuspendFunctionType() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/nullableSuspendFunctionType.kt");
}
@Test
@TestMetadata("overrideDefaultArgument.kt")
public void testOverrideDefaultArgument() throws Exception {
@@ -9354,6 +9366,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/suspendFunImportedFromObject.kt");
}
@Test
@TestMetadata("suspendFunctionAsSupertype.kt")
public void testSuspendFunctionAsSupertype() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/suspendFunctionAsSupertype.kt");
}
@Test
@TestMetadata("suspendFunctionMethodReference.kt")
public void testSuspendFunctionMethodReference() throws Exception {
@@ -9777,6 +9795,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInlineClass.kt");
}
@Test
@TestMetadata("overrideInInnerClass.kt")
public void testOverrideInInnerClass() throws Exception {
runTest("compiler/testData/codegen/box/coroutines/featureIntersection/overrideInInnerClass.kt");
}
@Test
@TestMetadata("safeCallOnTwoReceivers.kt")
public void testSafeCallOnTwoReceivers() throws Exception {
@@ -41086,6 +41110,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsForMaxLongValue.kt");
}
@Test
@TestMetadata("unsignedLiteralsInApiVersion14.kt")
public void testUnsignedLiteralsInApiVersion14() throws Exception {
runTest("compiler/testData/codegen/box/unsignedTypes/unsignedLiteralsInApiVersion14.kt");
}
@Test
@TestMetadata("unsignedLiteralsWithSignedOverflow.kt")
public void testUnsignedLiteralsWithSignedOverflow() throws Exception {

View File

@@ -916,7 +916,8 @@ class DeclarationsConverter(
}
constructedTypeRef = delegatedType.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef)
this.isThis = isThis
val calleeKind = if (isImplicit) FirFakeSourceElementKind.ImplicitConstructor else FirFakeSourceElementKind.DelegatingConstructorCall
val calleeKind =
if (isImplicit) FirFakeSourceElementKind.ImplicitConstructor else FirFakeSourceElementKind.DelegatingConstructorCall
val calleeSource = constructorDelegationCall.getChildNodeByType(CONSTRUCTOR_DELEGATION_REFERENCE)
?.toFirSourceElement(calleeKind)
?: this@buildDelegatedConstructorCall.source?.fakeElement(calleeKind)
@@ -1281,7 +1282,8 @@ class DeclarationsConverter(
CONTRACT_EFFECT -> {
val effect = it.getFirstChild()
if (effect == null) {
val errorExpression = buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected))
val errorExpression =
buildErrorExpression(null, ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionExpected))
destination.add(errorExpression)
} else {
val expression = expressionConverter.convertExpression(effect, errorReason)
@@ -1671,33 +1673,62 @@ class DeclarationsConverter(
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRef
*/
fun convertType(type: LighterASTNode): FirTypeRef {
val typeRefSource = type.toFirSourceElement()
if (type.asText.isEmpty()) {
return buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Unwrapped type is null", DiagnosticKind.Syntax) }
}
var typeModifiers = TypeModifier()
var firType: FirTypeRef = buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Incomplete code", DiagnosticKind.Syntax) }
var afterLPar = false
type.forEachChildren {
when (it.tokenType) {
LPAR -> afterLPar = true
TYPE_REFERENCE -> firType = convertType(it)
MODIFIER_LIST -> if (!afterLPar || typeModifiers.hasNoAnnotations()) typeModifiers = convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(it)
DEFINITELY_NOT_NULL_TYPE -> firType = unwrapDefinitelyNotNullableType(it)
NULLABLE_TYPE -> firType = convertNullableType(it)
FUNCTION_TYPE -> firType = convertFunctionType(it, isSuspend = typeModifiers.hasSuspend)
DYNAMIC_TYPE -> firType = buildDynamicTypeRef {
source = type.toFirSourceElement()
isMarkedNullable = false
}
TokenType.ERROR_ELEMENT -> firType =
buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Unwrapped type is null", DiagnosticKind.Syntax) }
return buildErrorTypeRef {
source = typeRefSource
diagnostic = ConeSimpleDiagnostic("Unwrapped type is null", DiagnosticKind.Syntax)
}
}
return firType.also { (it.annotations as MutableList<FirAnnotationCall>) += typeModifiers.annotations }
// There can be MODIFIER_LIST children on the TYPE_REFERENCE node AND the descendant NULLABLE_TYPE nodes.
// We aggregate them to get modifiers and annotations. Not only that, there could be multiple modifier lists on each. Examples:
//
// `@A() (@B Int)` -> Has 2 modifier lists (@A and @B) in TYPE_REFERENCE
// `(@A() (@B Int))? -> No modifier list on TYPE_REFERENCE, but 2 modifier lists (@A and @B) on child NULLABLE_TYPE
// `@A() (@B Int)? -> Has 1 modifier list (@A) on TYPE_REFERENCE, and 1 modifier list (@B) on child NULLABLE_TYPE
// `@A (@B() (@C() (@Bar D)?)?)?` -> Has 1 modifier list (@A) on B and 1 modifier list on each of the
// 3 descendant NULLABLE_TYPE (@B, @C, @D)
//
// We need to examine all modifier lists for some cases:
// 1. `@A Int?` and `(@A Int)?` are effectively the same, but in the latter, the modifier list is on the child NULLABLE_TYPE
// 2. `(suspend @A () -> Int)?` is a nullable suspend function type but the modifier list is on the child NULLABLE_TYPE
//
// TODO: Report MODIFIER_LIST_NOT_ALLOWED error when there are multiple modifier lists. How do we report on each of them?
val allTypeModifiers = mutableListOf<TypeModifier>()
var firType: FirTypeRef = buildErrorTypeRef {
source = typeRefSource
diagnostic = ConeSimpleDiagnostic("Incomplete code", DiagnosticKind.Syntax)
}
type.forEachChildren {
when (it.tokenType) {
TYPE_REFERENCE -> firType = convertType(it)
MODIFIER_LIST -> allTypeModifiers += convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(typeRefSource, it)
DEFINITELY_NOT_NULL_TYPE -> firType = unwrapDefinitelyNotNullableType(typeRefSource, it, allTypeModifiers)
NULLABLE_TYPE -> firType = convertNullableType(typeRefSource, it, allTypeModifiers)
FUNCTION_TYPE -> firType = convertFunctionType(typeRefSource, it, isSuspend = allTypeModifiers.hasSuspend())
DYNAMIC_TYPE -> firType = buildDynamicTypeRef {
source = typeRefSource
isMarkedNullable = false
}
TokenType.ERROR_ELEMENT -> firType =
buildErrorTypeRef {
source = typeRefSource
diagnostic = ConeSimpleDiagnostic("Unwrapped type is null", DiagnosticKind.Syntax)
}
}
}
for (modifierList in allTypeModifiers) {
(firType.annotations as MutableList<FirAnnotationCall>) += modifierList.annotations
}
return firType
}
private fun Collection<TypeModifier>.hasSuspend() = any { it.hasSuspend }
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeRefContents
*/
@@ -1715,17 +1746,23 @@ class DeclarationsConverter(
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseNullableTypeSuffix
*/
private fun convertNullableType(nullableType: LighterASTNode): FirTypeRef {
private fun convertNullableType(
typeRefSource: FirSourceElement,
nullableType: LighterASTNode,
allTypeModifiers: MutableList<TypeModifier>,
isNullable: Boolean = true
): FirTypeRef {
lateinit var firType: FirTypeRef
nullableType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> firType =
convertUserType(it, true)
FUNCTION_TYPE -> firType = convertFunctionType(it, true)
NULLABLE_TYPE -> firType = convertNullableType(it)
DEFINITELY_NOT_NULL_TYPE -> firType = unwrapDefinitelyNotNullableType(it, nullable = true)
MODIFIER_LIST -> allTypeModifiers += convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(typeRefSource, it, isNullable)
FUNCTION_TYPE -> firType = convertFunctionType(typeRefSource, it, isNullable, isSuspend = allTypeModifiers.hasSuspend())
NULLABLE_TYPE -> firType = convertNullableType(typeRefSource, it, allTypeModifiers)
DEFINITELY_NOT_NULL_TYPE -> firType =
unwrapDefinitelyNotNullableType(typeRefSource, it, allTypeModifiers, isNullable = true)
DYNAMIC_TYPE -> firType = buildDynamicTypeRef {
source = nullableType.toFirSourceElement()
source = typeRefSource
isMarkedNullable = true
}
}
@@ -1734,18 +1771,23 @@ class DeclarationsConverter(
return firType
}
private fun unwrapDefinitelyNotNullableType(definitelyNotNullType: LighterASTNode, nullable: Boolean = false): FirTypeRef {
private fun unwrapDefinitelyNotNullableType(
typeRefSource: FirSourceElement,
definitelyNotNullType: LighterASTNode,
allTypeModifiers: MutableList<TypeModifier>,
isNullable: Boolean = false
): FirTypeRef {
lateinit var firType: FirTypeRef
// TODO: Support proper DefinitelyNotNullableType
definitelyNotNullType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> firType =
convertUserType(it, nullable)
FUNCTION_TYPE -> firType = convertFunctionType(it, nullable)
NULLABLE_TYPE -> firType = convertNullableType(it)
DEFINITELY_NOT_NULL_TYPE -> firType = unwrapDefinitelyNotNullableType(it, nullable)
MODIFIER_LIST -> allTypeModifiers += convertTypeModifierList(it)
USER_TYPE -> firType = convertUserType(typeRefSource, it, isNullable)
FUNCTION_TYPE -> firType = convertFunctionType(typeRefSource, it, isNullable, isSuspend = allTypeModifiers.hasSuspend())
NULLABLE_TYPE -> firType = convertNullableType(typeRefSource, it, allTypeModifiers, isNullable = false)
DEFINITELY_NOT_NULL_TYPE -> firType = unwrapDefinitelyNotNullableType(typeRefSource, it, allTypeModifiers, isNullable)
DYNAMIC_TYPE -> firType = buildDynamicTypeRef {
source = definitelyNotNullType.toFirSourceElement()
source = typeRefSource
isMarkedNullable = false
}
}
@@ -1757,32 +1799,37 @@ class DeclarationsConverter(
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseUserType
*/
private fun convertUserType(userType: LighterASTNode, isNullable: Boolean = false): FirTypeRef {
private fun convertUserType(
typeRefSource: FirSourceElement,
userType: LighterASTNode,
isNullable: Boolean = false
): FirTypeRef {
var simpleFirUserType: FirUserTypeRef? = null
var identifier: String? = null
val firTypeArguments = mutableListOf<FirTypeProjection>()
userType.forEachChildren {
when (it.tokenType) {
USER_TYPE -> simpleFirUserType = convertUserType(it) as? FirUserTypeRef //simple user type
USER_TYPE -> simpleFirUserType = convertUserType(typeRefSource, it) as? FirUserTypeRef //simple user type
REFERENCE_EXPRESSION -> identifier = it.asText
TYPE_ARGUMENT_LIST -> firTypeArguments += convertTypeArguments(it)
}
}
if (identifier == null)
return buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("Incomplete user type", DiagnosticKind.Syntax) }
return buildErrorTypeRef {
source = typeRefSource
diagnostic = ConeSimpleDiagnostic("Incomplete user type", DiagnosticKind.Syntax)
}
// Note: we take TYPE_REFERENCE, not USER_TYPE, as the source (to be consistent with RawFirBuilder)
val theSource = tree.getParent(userType)!!.toFirSourceElement()
val qualifierPart = FirQualifierPartImpl(
identifier.nameAsSafeName(),
FirTypeArgumentListImpl(theSource).apply {
FirTypeArgumentListImpl(typeRefSource).apply {
typeArguments += firTypeArguments
}
)
return buildUserTypeRef {
source = theSource
source = typeRefSource
isMarkedNullable = isNullable
qualifier.add(qualifierPart)
simpleFirUserType?.qualifier?.let { this.qualifier.addAll(0, it) }
@@ -1827,7 +1874,12 @@ class DeclarationsConverter(
/**
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionType
*/
private fun convertFunctionType(functionType: LighterASTNode, isNullable: Boolean = false, isSuspend: Boolean = false): FirTypeRef {
private fun convertFunctionType(
typeRefSource: FirSourceElement,
functionType: LighterASTNode,
isNullable: Boolean = false,
isSuspend: Boolean = false
): FirTypeRef {
var receiverTypeReference: FirTypeRef? = null
lateinit var returnTypeReference: FirTypeRef
val valueParametersList = mutableListOf<ValueParameter>()
@@ -1840,7 +1892,7 @@ class DeclarationsConverter(
}
return buildFunctionTypeRef {
source = functionType.toFirSourceElement()
source = typeRefSource
isMarkedNullable = isNullable
receiverTypeRef = receiverTypeReference
returnTypeRef = returnTypeReference

View File

@@ -46,6 +46,16 @@ public class LightTree2FirConverterTestCaseGenerated extends AbstractLightTree2F
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
}
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnNullableParenthesizedTypes.kt");
}
@TestMetadata("annotationsOnParenthesizedTypes.kt")
public void testAnnotationsOnParenthesizedTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnParenthesizedTypes.kt");
}
@TestMetadata("complexTypes.kt")
public void testComplexTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/complexTypes.kt");
@@ -156,6 +166,16 @@ public class LightTree2FirConverterTestCaseGenerated extends AbstractLightTree2F
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/simpleTypeAlias.kt");
}
@TestMetadata("splitModifierList.kt")
public void testSplitModifierList() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/splitModifierList.kt");
}
@TestMetadata("suspendFunctionTypes.kt")
public void testSuspendFunctionTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/suspendFunctionTypes.kt");
}
@TestMetadata("typeAliasWithGeneric.kt")
public void testTypeAliasWithGeneric() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/typeAliasWithGeneric.kt");

View File

@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.name.LocalCallableIdConstructor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.expressions.OperatorConventions
@@ -1354,11 +1355,37 @@ open class RawFirBuilder(
val source = typeReference.toFirSourceElement()
val isNullable = typeElement is KtNullableType
// There can be KtDeclarationModifierLists in the KtTypeReference AND the descendant KtNullableTypes.
// We aggregate them to get modifiers and annotations. Not only that, there could be multiple modifier lists on each. Examples:
//
// `@A() (@B Int)` -> Has 2 modifier lists (@A and @B) on KtTypeReference
// `(@A() (@B Int))? -> No modifier list on KtTypeReference, but 2 modifier lists (@A and @B) on child KtNullableType
// `@A() (@B Int)? -> Has 1 modifier list (@A) on KtTypeReference, and 1 modifier list (@B) on child KtNullableType
// `@A (@B() (@C() (@Bar D)?)?)?` -> Has 1 modifier list (@A) on KtTypeReference and 1 modifier list on each of the
// 3 descendant KtNullableTypes (@B, @C, @D)
//
// We need to examine all modifier lists for some cases:
// 1. `@A Int?` and `(@A Int)?` are effectively the same, but in the latter, the modifier list is on the child KtNullableType
// 2. `(suspend @A () -> Int)?` is a nullable suspend function type but the modifier list is on the child KtNullableType
//
// `getModifierList()` only returns the first one so we have to get all modifier list children.
// TODO: Report MODIFIER_LIST_NOT_ALLOWED error when there are multiple modifier lists. How do we report on each of them?
fun KtElementImplStub<*>.getAllModifierLists(): Array<out KtDeclarationModifierList> =
getStubOrPsiChildren(KtStubElementTypes.MODIFIER_LIST, KtStubElementTypes.MODIFIER_LIST.arrayFactory)
val allModifierLists = mutableListOf<KtModifierList>(*typeReference.getAllModifierLists())
fun KtTypeElement?.unwrapNullable(): KtTypeElement? =
when (this) {
is KtNullableType -> this.innerType.unwrapNullable()
is KtNullableType -> {
allModifierLists += getAllModifierLists()
this.innerType.unwrapNullable()
}
// TODO: Support explicit definitely not null type
is KtDefinitelyNotNullType -> this.innerType.unwrapNullable()
is KtDefinitelyNotNullType -> {
allModifierLists += getAllModifierLists()
this.innerType.unwrapNullable()
}
else -> this
}
@@ -1403,7 +1430,7 @@ open class RawFirBuilder(
FirFunctionTypeRefBuilder().apply {
this.source = source
isMarkedNullable = isNullable
isSuspend = typeReference.hasModifier(SUSPEND_KEYWORD)
isSuspend = allModifierLists.any { it.hasSuspendModifier() }
receiverTypeRef = unwrappedElement.receiverTypeReference.convertSafe()
// TODO: probably implicit type should not be here
returnTypeRef = unwrappedElement.returnTypeReference.toFirOrErrorType()
@@ -1422,8 +1449,10 @@ open class RawFirBuilder(
else -> throw AssertionError("Unexpected type element: ${unwrappedElement.text}")
}
for (annotationEntry in typeReference.annotationEntries) {
firTypeBuilder.annotations += annotationEntry.convert<FirAnnotationCall>()
for (modifierList in allModifierLists) {
for (annotationEntry in modifierList.annotationEntries) {
firTypeBuilder.annotations += annotationEntry.convert<FirAnnotationCall>()
}
}
return firTypeBuilder.build()
}

View File

@@ -0,0 +1,27 @@
interface AnnotationsOnNullableParenthesizedTypes {
fun B<(@A C)?>.receiverArgument() {}
fun parameter(a: (@A C)?) {}
fun parameterArgument(a: B<(@A C)?>) {}
fun returnValue(): (@A C)?
fun <T> returnTypeParameterValue(): (@A T)?
fun returnArgument(): B<(@A C)?>
val lambdaType: (@A() (() -> C))?
val lambdaParameter: ((@A C)?) -> C
val lambdaReturnValue: () -> (@A C)?
val lambdaReceiver: (@A C)?.() -> C
}
@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER)
annotation class A
interface B<T>
interface C

View File

@@ -0,0 +1,37 @@
FILE: annotationsOnNullableParenthesizedTypes.kt
public? final? interface AnnotationsOnNullableParenthesizedTypes : R|kotlin/Any| {
public? final? fun B<@A() C?>.receiverArgument(): R|kotlin/Unit| { LAZY_BLOCK }
public? final? fun parameter(a: @A() C?): R|kotlin/Unit| { LAZY_BLOCK }
public? final? fun parameterArgument(a: B<@A() C?>): R|kotlin/Unit| { LAZY_BLOCK }
public? final? fun returnValue(): @A() C?
public? final? fun <T> returnTypeParameterValue(): @A() T?
public? final? fun returnArgument(): B<@A() C?>
public? final? val lambdaType: @A() ( () -> C )?
public? get(): @A() ( () -> C )?
public? final? val lambdaParameter: ( (@A() C?) -> C )
public? get(): ( (@A() C?) -> C )
public? final? val lambdaReturnValue: ( () -> @A() C? )
public? get(): ( () -> @A() C? )
public? final? val lambdaReceiver: ( @A() C?.() -> C )
public? get(): ( @A() C?.() -> C )
}
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class A : R|kotlin/Annotation| {
public? constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public? final? interface B<T> : R|kotlin/Any| {
}
public? final? interface C : R|kotlin/Any| {
}

View File

@@ -0,0 +1,40 @@
FILE: annotationsOnNullableParenthesizedTypes.kt
public? final? interface AnnotationsOnNullableParenthesizedTypes : R|kotlin/Any| {
public? final? fun B<@A() C?>.receiverArgument(): R|kotlin/Unit| {
}
public? final? fun parameter(a: @A() C?): R|kotlin/Unit| {
}
public? final? fun parameterArgument(a: B<@A() C?>): R|kotlin/Unit| {
}
public? final? fun returnValue(): @A() C?
public? final? fun <T> returnTypeParameterValue(): @A() T?
public? final? fun returnArgument(): B<@A() C?>
public? final? val lambdaType: @A() ( () -> C )?
[ContainingClassKey=AnnotationsOnNullableParenthesizedTypes] public? get(): @A() ( () -> C )?
public? final? val lambdaParameter: ( (@A() C?) -> C )
[ContainingClassKey=AnnotationsOnNullableParenthesizedTypes] public? get(): ( (@A() C?) -> C )
public? final? val lambdaReturnValue: ( () -> @A() C? )
[ContainingClassKey=AnnotationsOnNullableParenthesizedTypes] public? get(): ( () -> @A() C? )
public? final? val lambdaReceiver: ( @A() C?.() -> C )
[ContainingClassKey=AnnotationsOnNullableParenthesizedTypes] public? get(): ( @A() C?.() -> C )
}
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class A : R|kotlin/Annotation| {
public? [ContainingClassKey=A] constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public? final? interface B<T> : R|kotlin/Any| {
}
public? final? interface C : R|kotlin/Any| {
}

View File

@@ -0,0 +1,29 @@
interface AnnotationsOnParenthesizedTypes {
fun B<(@A C)>.receiverArgument() {}
fun parameter(a: (@A C)) {}
fun parameterArgument(a: B<(@A C)>) {}
fun returnValue(): (@A C)
fun <T> returnTypeParameterValue(): (@A T)
fun returnArgument(): B<(@A C)>
val lambdaType: (@A() (() -> C))
val lambdaParameter: ((@A C)) -> C
val lambdaReturnValue: () -> (@A C)
val lambdaReceiver: (@A C).() -> C
val lambdaParameterNP: (@A C) -> C
}
@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER)
annotation class A
interface B<T>
interface C

View File

@@ -0,0 +1,40 @@
FILE: annotationsOnParenthesizedTypes.kt
public? final? interface AnnotationsOnParenthesizedTypes : R|kotlin/Any| {
public? final? fun B<@A() C>.receiverArgument(): R|kotlin/Unit| { LAZY_BLOCK }
public? final? fun parameter(a: @A() C): R|kotlin/Unit| { LAZY_BLOCK }
public? final? fun parameterArgument(a: B<@A() C>): R|kotlin/Unit| { LAZY_BLOCK }
public? final? fun returnValue(): @A() C
public? final? fun <T> returnTypeParameterValue(): @A() T
public? final? fun returnArgument(): B<@A() C>
public? final? val lambdaType: @A() ( () -> C )
public? get(): @A() ( () -> C )
public? final? val lambdaParameter: ( (@A() C) -> C )
public? get(): ( (@A() C) -> C )
public? final? val lambdaReturnValue: ( () -> @A() C )
public? get(): ( () -> @A() C )
public? final? val lambdaReceiver: ( @A() C.() -> C )
public? get(): ( @A() C.() -> C )
public? final? val lambdaParameterNP: ( (@A() C) -> C )
public? get(): ( (@A() C) -> C )
}
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class A : R|kotlin/Annotation| {
public? constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public? final? interface B<T> : R|kotlin/Any| {
}
public? final? interface C : R|kotlin/Any| {
}

View File

@@ -0,0 +1,43 @@
FILE: annotationsOnParenthesizedTypes.kt
public? final? interface AnnotationsOnParenthesizedTypes : R|kotlin/Any| {
public? final? fun B<@A() C>.receiverArgument(): R|kotlin/Unit| {
}
public? final? fun parameter(a: @A() C): R|kotlin/Unit| {
}
public? final? fun parameterArgument(a: B<@A() C>): R|kotlin/Unit| {
}
public? final? fun returnValue(): @A() C
public? final? fun <T> returnTypeParameterValue(): @A() T
public? final? fun returnArgument(): B<@A() C>
public? final? val lambdaType: @A() ( () -> C )
[ContainingClassKey=AnnotationsOnParenthesizedTypes] public? get(): @A() ( () -> C )
public? final? val lambdaParameter: ( (@A() C) -> C )
[ContainingClassKey=AnnotationsOnParenthesizedTypes] public? get(): ( (@A() C) -> C )
public? final? val lambdaReturnValue: ( () -> @A() C )
[ContainingClassKey=AnnotationsOnParenthesizedTypes] public? get(): ( () -> @A() C )
public? final? val lambdaReceiver: ( @A() C.() -> C )
[ContainingClassKey=AnnotationsOnParenthesizedTypes] public? get(): ( @A() C.() -> C )
public? final? val lambdaParameterNP: ( (@A() C) -> C )
[ContainingClassKey=AnnotationsOnParenthesizedTypes] public? get(): ( (@A() C) -> C )
}
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class A : R|kotlin/Annotation| {
public? [ContainingClassKey=A] constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
public? final? interface B<T> : R|kotlin/Any| {
}
public? final? interface C : R|kotlin/Any| {
}

View File

@@ -0,0 +1,16 @@
@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER)
annotation class A
@Target(AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER)
annotation class B
typealias Test0 = @A @B Int
typealias Test1 = @A() (@A Int)
typealias Test2 = @A() (@B Int)
typealias Test3 = @A() (@A Int) -> Int
typealias Test4 = @A() (@B Int)?
typealias Test5 = @A() ( (@B Int)? )
typealias Test6 = (@A @B Int)
typealias Test7 = (@A @B Int)?
typealias Test8 = (@A() (@B Int)? )
typealias Test9 = (@A() (@B Int) )?

View File

@@ -0,0 +1,23 @@
FILE: splitModifierList.kt
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class A : R|kotlin/Annotation| {
public? constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class B : R|kotlin/Annotation| {
public? constructor(): R|B| {
super<R|kotlin/Any|>()
}
}
public? final typealias Test0 = @A() @B() Int
public? final typealias Test1 = @A() @A() Int
public? final typealias Test2 = @A() @B() Int
public? final typealias Test3 = @A() ( (@A() Int) -> Int )
public? final typealias Test4 = @A() @B() Int?
public? final typealias Test5 = @A() @B() Int?
public? final typealias Test6 = @A() @B() Int
public? final typealias Test7 = @A() @B() Int?
public? final typealias Test8 = @A() @B() Int?
public? final typealias Test9 = @A() @B() Int?

View File

@@ -0,0 +1,23 @@
FILE: splitModifierList.kt
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class A : R|kotlin/Annotation| {
public? [ContainingClassKey=A] constructor(): R|A| {
super<R|kotlin/Any|>()
}
}
@Target(AnnotationTarget#.TYPE#, AnnotationTarget#.TYPE_PARAMETER#) public? final? annotation class B : R|kotlin/Annotation| {
public? [ContainingClassKey=B] constructor(): R|B| {
super<R|kotlin/Any|>()
}
}
public? final typealias Test0 = @A() @B() Int
public? final typealias Test1 = @A() @A() Int
public? final typealias Test2 = @A() @B() Int
public? final typealias Test3 = @A() ( (@A() Int) -> Int )
public? final typealias Test4 = @A() @B() Int?
public? final typealias Test5 = @A() @B() Int?
public? final typealias Test6 = @A() @B() Int
public? final typealias Test7 = @A() @B() Int?
public? final typealias Test8 = @A() @B() Int?
public? final typealias Test9 = @A() @B() Int?

View File

@@ -0,0 +1,8 @@
suspend fun <T> simpleRun(f: suspend () -> T): T = f()
suspend fun <T, R> List<T>.simpleMap(f: suspend (T) -> R): R {
}
suspend fun <T> simpleWith(t: T, f: suspend T.() -> Unit): Unit = t.f()

View File

@@ -0,0 +1,4 @@
FILE: suspendFunctionTypes.kt
public? final? suspend fun <T> simpleRun(f: ( suspend () -> T )): T { LAZY_BLOCK }
public? final? suspend fun <T, R> List<T>.simpleMap(f: ( suspend (T) -> R )): R { LAZY_BLOCK }
public? final? suspend fun <T> simpleWith(t: T, f: ( suspend T.() -> Unit )): Unit { LAZY_BLOCK }

View File

@@ -0,0 +1,9 @@
FILE: suspendFunctionTypes.kt
public? final? suspend fun <T> simpleRun(f: ( suspend () -> T )): T {
^simpleRun f#()
}
public? final? suspend fun <T, R> List<T>.simpleMap(f: ( suspend (T) -> R )): R {
}
public? final? suspend fun <T> simpleWith(t: T, f: ( suspend T.() -> Unit )): Unit {
^simpleWith t#.f#()
}

View File

@@ -46,6 +46,16 @@ public class RawFirBuilderLazyBodiesTestCaseGenerated extends AbstractRawFirBuil
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
}
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnNullableParenthesizedTypes.kt");
}
@TestMetadata("annotationsOnParenthesizedTypes.kt")
public void testAnnotationsOnParenthesizedTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnParenthesizedTypes.kt");
}
@TestMetadata("complexTypes.kt")
public void testComplexTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/complexTypes.kt");
@@ -156,6 +166,16 @@ public class RawFirBuilderLazyBodiesTestCaseGenerated extends AbstractRawFirBuil
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/simpleTypeAlias.kt");
}
@TestMetadata("splitModifierList.kt")
public void testSplitModifierList() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/splitModifierList.kt");
}
@TestMetadata("suspendFunctionTypes.kt")
public void testSuspendFunctionTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/suspendFunctionTypes.kt");
}
@TestMetadata("typeAliasWithGeneric.kt")
public void testTypeAliasWithGeneric() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/typeAliasWithGeneric.kt");

View File

@@ -46,6 +46,16 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotation.kt");
}
@TestMetadata("annotationsOnNullableParenthesizedTypes.kt")
public void testAnnotationsOnNullableParenthesizedTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnNullableParenthesizedTypes.kt");
}
@TestMetadata("annotationsOnParenthesizedTypes.kt")
public void testAnnotationsOnParenthesizedTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/annotationsOnParenthesizedTypes.kt");
}
@TestMetadata("complexTypes.kt")
public void testComplexTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/complexTypes.kt");
@@ -156,6 +166,16 @@ public class RawFirBuilderTestCaseGenerated extends AbstractRawFirBuilderTestCas
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/simpleTypeAlias.kt");
}
@TestMetadata("splitModifierList.kt")
public void testSplitModifierList() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/splitModifierList.kt");
}
@TestMetadata("suspendFunctionTypes.kt")
public void testSuspendFunctionTypes() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/suspendFunctionTypes.kt");
}
@TestMetadata("typeAliasWithGeneric.kt")
public void testTypeAliasWithGeneric() throws Exception {
runTest("compiler/fir/raw-fir/psi2fir/testData/rawBuilder/declarations/typeAliasWithGeneric.kt");

View File

@@ -634,7 +634,9 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
}
is ResolutionMode.LambdaResolution -> {
context.withAnonymousFunction(anonymousFunction, components, data) {
transformAnonymousFunctionWithLambdaResolution(anonymousFunction, data).addReturn()
withFullBodyResolve {
transformAnonymousFunctionWithLambdaResolution(anonymousFunction, data).addReturn()
}
}
}
is ResolutionMode.WithExpectedType, is ResolutionMode.ContextIndependent -> {
@@ -696,7 +698,9 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
lambda = lambda.transformValueParameters(ImplicitToErrorTypeTransformer, null)
val bodyExpectedType = returnTypeRefFromResolvedAtom ?: expectedTypeRef
context.withAnonymousFunction(lambda, components, data) {
lambda = transformFunction(lambda, withExpectedType(bodyExpectedType)) as FirAnonymousFunction
withFullBodyResolve {
lambda = transformFunction(lambda, withExpectedType(bodyExpectedType)) as FirAnonymousFunction
}
}
// To separate function and separate commit
val writer = FirCallCompletionResultsWriterTransformer(

View File

@@ -983,7 +983,11 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
}
override fun visitFunctionTypeRef(functionTypeRef: FirFunctionTypeRef) {
functionTypeRef.annotations.dropExtensionFunctionAnnotation().renderAnnotations()
print("( ")
if (functionTypeRef.isSuspend) {
print("suspend ")
}
functionTypeRef.receiverTypeRef?.let {
it.accept(this)
print(".")

View File

@@ -325,6 +325,7 @@ public interface Errors {
DiagnosticFactory0<KtTypeReference> SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> SUPERTYPE_IS_KSUSPEND_FUNCTION_TYPE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> MANY_CLASSES_IN_SUPERTYPE_LIST = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtTypeReference> SUPERTYPE_APPEARS_TWICE = DiagnosticFactory0.create(ERROR);

View File

@@ -635,6 +635,7 @@ public class DefaultErrorMessages {
MAP.put(SUPERTYPE_INITIALIZED_IN_INTERFACE, "Interfaces cannot initialize supertypes");
MAP.put(SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE, "Suspend function type is not allowed as supertypes");
MAP.put(SUPERTYPE_IS_KSUSPEND_FUNCTION_TYPE, "KSuspendFunctionN interfaces are not allowed as supertypes");
MAP.put(MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES, "Mixing suspend and non-suspend supertypes is not allowed");
MAP.put(CLASS_IN_SUPERTYPE_FOR_ENUM, "Enum class cannot inherit from classes");
MAP.put(CONSTRUCTOR_IN_INTERFACE, "An interface may not have a constructor");
MAP.put(METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE, "An interface may not implement a method of 'Any'");

View File

@@ -587,10 +587,13 @@ public class BodyResolver {
if (FunctionTypesKt.isExtensionFunctionType(supertype)) {
trace.report(SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.on(typeReference));
}
else if (FunctionTypesKt.isSuspendFunctionType(supertype)) {
else if (FunctionTypesKt.isSuspendFunctionType(supertype) &&
!languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionAsSupertype)
) {
trace.report(SUPERTYPE_IS_SUSPEND_FUNCTION_TYPE.on(typeReference));
}
else if (FunctionTypesKt.isKSuspendFunctionType(supertype)) {
else if (FunctionTypesKt.isKSuspendFunctionType(supertype) &&
!languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionAsSupertype)) {
trace.report(SUPERTYPE_IS_KSUSPEND_FUNCTION_TYPE.on(typeReference));
}

View File

@@ -44,6 +44,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
SealedInheritorInSamePackageChecker,
SealedInheritorInSameModuleChecker,
SealedInterfaceAllowedChecker,
SuspendFunctionAsSupertypeChecker,
)
private val DEFAULT_CALL_CHECKERS = listOf(

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.checkers
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.functions.FunctionClassKind
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperClassifiers
object SuspendFunctionAsSupertypeChecker : DeclarationChecker {
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.SuspendFunctionAsSupertype)) return
if (descriptor !is ClassDescriptor) return
val functionalSupertypes = descriptor.getAllSuperClassifiers().filterIsInstance<FunctionClassDescriptor>().toList()
if (functionalSupertypes.none {
it.functionKind == FunctionClassKind.SuspendFunction ||
it.functionKind == FunctionClassKind.KSuspendFunction
}
) return
if (functionalSupertypes.any {
it.functionKind == FunctionClassKind.Function ||
it.functionKind == FunctionClassKind.KFunction
}
) {
val reportOn = (declaration as? KtClassOrObject)?.getSuperTypeList() ?: declaration
context.trace.report(Errors.MIXING_SUSPEND_AND_NON_SUSPEND_SUPERTYPES.on(reportOn))
}
}
}

View File

@@ -1065,7 +1065,7 @@ private class ConstantExpressionEvaluatorVisitor(
val uInt = constantExpressionEvaluator.module.findClassAcrossModuleDependencies(StandardNames.FqNames.uInt) ?: return false
val accessibility = uInt.checkSinceKotlinVersionAccessibility(languageVersionSettings)
// Case `NotAccessibleButWasExperimental` will be checked later in `checkExperimentalityOfConstantLiteral`
return accessibility is SinceKotlinAccessibility.Accessible
return accessibility !is SinceKotlinAccessibility.NotAccessible
}
private fun <T> ConstantValue<T>.wrap(parameters: CompileTimeConstant.Parameters): TypedCompileTimeConstant<T> =

View File

@@ -100,7 +100,7 @@ class JsIrBackendContext(
override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET
override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET
}, internalPackageFragmentDescriptor).also {
}, internalPackageFragmentDescriptor, module).also {
module.files += it
}
}

View File

@@ -62,7 +62,7 @@ class MoveBodilessDeclarationsToSeparatePlaceLowering(private val context: JsIrB
val externalPackageFragment by lazy {
context.externalPackageFragment.getOrPut(irFile.symbol) {
IrFileImpl(fileEntry = irFile.fileEntry, fqName = irFile.fqName, symbol = IrFileSymbolImpl()).also {
IrFileImpl(fileEntry = irFile.fileEntry, fqName = irFile.fqName, symbol = IrFileSymbolImpl(), module = irFile.module).also {
it.annotations += irFile.annotations
}
}

View File

@@ -85,7 +85,7 @@ class Equals(val operator: IElementType) : IntrinsicMethod() {
// what comparison means. The optimization does not apply to `object == primitive` as equals
// could be overridden for the object.
if ((opToken == IrStatementOrigin.EQEQ || opToken == IrStatementOrigin.EXCLEQ) &&
((AsmUtil.isIntOrLongPrimitive(leftType) && !AsmUtil.isPrimitive(rightType)) ||
((AsmUtil.isIntOrLongPrimitive(leftType) && !isPrimitive(rightType)) ||
(AsmUtil.isIntOrLongPrimitive(rightType) && AsmUtil.isBoxedPrimitiveType(leftType)))
) {
val aValue = a.accept(codegen, data).materializedAt(leftType, a.type)

View File

@@ -27,31 +27,38 @@ import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
// TODO Implement hashCode on primitive types as a lowering.
object HashCode : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) = with(codegen) {
val receiver = expression.dispatchReceiver ?: error("No receiver for hashCode: ${expression.render()}")
val result = receiver.accept(this, data).materialized()
val receiverIrType = receiver.type
val receiverJvmType = typeMapper.mapType(receiverIrType)
val receiverValue = receiver.accept(this, data).materialized()
val receiverType = receiverValue.type
val target = context.state.target
when {
irFunction.origin == JvmLoweredDeclarationOrigin.INLINE_CLASS_GENERATED_IMPL_METHOD ||
irFunction.origin == IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER ->
DescriptorAsmUtil.genHashCode(mv, mv, result.type, target)
target == JvmTarget.JVM_1_6 || !AsmUtil.isPrimitive(result.type) -> {
result.materializeAtBoxed(receiver.type)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false)
irFunction.origin == IrDeclarationOrigin.GENERATED_DATA_CLASS_MEMBER -> {
// TODO generate or lower IR for data class / inline class 'hashCode'?
DescriptorAsmUtil.genHashCode(mv, mv, receiverType, target)
}
else -> {
val boxedType = AsmUtil.boxType(result.type)
target >= JvmTarget.JVM_1_8 && AsmUtil.isPrimitive(receiverJvmType) -> {
val boxedType = AsmUtil.boxPrimitiveType(receiverJvmType)
?: throw AssertionError("Primitive type expected: $receiverJvmType")
receiverValue.materializeAt(receiverJvmType, receiverIrType)
mv.visitMethodInsn(
Opcodes.INVOKESTATIC,
boxedType.internalName,
"hashCode",
Type.getMethodDescriptor(Type.INT_TYPE, result.type),
Type.getMethodDescriptor(Type.INT_TYPE, receiverJvmType),
false
)
}
else -> {
receiverValue.materializeAtBoxed(receiverIrType)
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I", false)
}
}
MaterialValue(codegen, Type.INT_TYPE, codegen.context.irBuiltIns.intType)
}
}

View File

@@ -13,18 +13,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
private fun ExpressionCodegen.checkTopValueForNull() {
mv.dup()
if (state.unifiedNullChecks) {
mv.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkNotNull", "(Ljava/lang/Object;)V", false)
} else {
val ifNonNullLabel = Label()
mv.ifnonnull(ifNonNullLabel)
mv.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false)
mv.mark(ifNonNullLabel)
}
}
object IrCheckNotNull : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
val arg0 = expression.getValueArgument(0)!!.accept(codegen, data)
@@ -37,4 +25,16 @@ object IrCheckNotNull : IntrinsicMethod() {
arg0.materialized().also { codegen.checkTopValueForNull() }.discard()
}
}
private fun ExpressionCodegen.checkTopValueForNull() {
mv.dup()
if (state.unifiedNullChecks) {
mv.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "checkNotNull", "(Ljava/lang/Object;)V", false)
} else {
val ifNonNullLabel = Label()
mv.ifnonnull(ifNonNullLabel)
mv.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false)
mv.mark(ifNonNullLabel)
}
}
}

View File

@@ -226,6 +226,44 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
copyMetadata = false
)
static.body = irFunction.moveBodyTo(static)
// Fixup dispatch parameter to outer class
if (irFunction.parentAsClass.isInner) {
val movedDispatchParameter = static.valueParameters[0]
assert(movedDispatchParameter.origin == IrDeclarationOrigin.MOVED_DISPATCH_RECEIVER) {
"MOVED_DISPATCH_RECEIVER should be the first parameter in ${static.render()}"
}
static.body!!.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitGetValue(expression: IrGetValue): IrExpression {
val owner = expression.symbol.owner
if (owner is IrValueParameter && isInstanceReceiverOfOuterClass(owner)) {
// If inner class has inner classes, we need to traverse this$0 chain to get to captured dispatch receivers
var cursor = irFunction.parentAsClass
var value: IrExpression = IrGetValueImpl(expression.startOffset, expression.endOffset, movedDispatchParameter.symbol)
while (cursor != owner.parent) {
val outerThisField = context.innerClassesSupport.getOuterThisField(cursor)
value = IrGetFieldImpl(
expression.startOffset, expression.endOffset, outerThisField.symbol, outerThisField.type, value
)
cursor = cursor.parentAsClass
}
return value
}
return super.visitGetValue(expression)
}
private fun isInstanceReceiverOfOuterClass(param: IrValueParameter): Boolean {
if (param.origin != IrDeclarationOrigin.INSTANCE_RECEIVER) return false
if (param.parent !is IrClass) return false
var cursor = irFunction.parentAsClass.parent
while (cursor is IrClass) {
if (cursor == param.parent) return true
cursor = (cursor as IrClass).parent
}
return false
}
})
}
static.copyAttributes(irFunction)
// Rewrite the body of the original suspend method to forward to the new static method.
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {

View File

@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
import org.jetbrains.kotlin.config.JvmAnalysisFlags
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.ir.*
import org.jetbrains.kotlin.ir.builders.*
@@ -57,7 +56,7 @@ internal val generateMultifileFacadesPhase = makeCustomPhase<JvmBackendContext,
// we construct an inheritance chain such that all part members are present as fake overrides in the facade.
val shouldGeneratePartHierarchy = context.state.languageVersionSettings.getFlag(JvmAnalysisFlags.inheritMultifileParts)
input.files.addAll(
generateMultifileFacades(input.descriptor, context, shouldGeneratePartHierarchy, functionDelegates)
generateMultifileFacades(input, context, shouldGeneratePartHierarchy, functionDelegates)
)
UpdateFunctionCallSites(functionDelegates).lower(input)
@@ -90,7 +89,7 @@ class MultifileFacadeFileEntry(
}
private fun generateMultifileFacades(
module: ModuleDescriptor,
module: IrModuleFragment,
context: JvmBackendContext,
shouldGeneratePartHierarchy: Boolean,
functionDelegates: MutableMap<IrSimpleFunction, IrSimpleFunction>
@@ -108,7 +107,7 @@ private fun generateMultifileFacades(
}
val fileEntry = MultifileFacadeFileEntry(jvmClassName, partClasses.map(IrClass::fileParent))
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module, kotlinPackageFqName))
val file = IrFileImpl(fileEntry, EmptyPackageFragmentDescriptor(module.descriptor, kotlinPackageFqName), module)
context.log {
"Multifile facade $jvmClassName:\n ${partClasses.joinToString("\n ") { it.fqNameWhenAvailable!!.asString() }}\n"

View File

@@ -10,16 +10,17 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.codegen.intrinsics.Not
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.irGetField
import org.jetbrains.kotlin.ir.builders.irSetField
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrPublicSymbolBase
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.*
@@ -64,6 +65,42 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
else -> null
}
private class SafeCallInfo(
val scopeSymbol: IrSymbol,
val tmpVal: IrVariable,
val ifNullBranch: IrBranch,
val ifNotNullBranch: IrBranch
)
private fun parseSafeCall(expression: IrExpression): SafeCallInfo? {
val block = expression as? IrBlock ?: return null
if (block.origin != IrStatementOrigin.SAFE_CALL) return null
if (block.statements.size != 2) return null
val tmpVal = block.statements[0] as? IrVariable ?: return null
val scopeOwner = tmpVal.parent as? IrDeclaration ?: return null
val scopeSymbol = scopeOwner.symbol
val whenExpr = block.statements[1] as? IrWhen ?: return null
if (whenExpr.branches.size != 2) return null
val ifNullBranch = whenExpr.branches[0]
val ifNullBranchCondition = ifNullBranch.condition
if (ifNullBranchCondition !is IrCall) return null
if (ifNullBranchCondition.symbol != context.irBuiltIns.eqeqSymbol) return null
val arg0 = ifNullBranchCondition.getValueArgument(0)
if (arg0 !is IrGetValue || arg0.symbol != tmpVal.symbol) return null
val arg1 = ifNullBranchCondition.getValueArgument(1)
if (arg1 !is IrConst<*> || arg1.value != null) return null
val ifNullBranchResult = ifNullBranch.result
if (ifNullBranchResult !is IrConst<*> || ifNullBranchResult.value != null) return null
val ifNotNullBranch = whenExpr.branches[1]
return SafeCallInfo(scopeSymbol, tmpVal, ifNullBranch, ifNotNullBranch)
}
private fun IrType.isJvmPrimitive(): Boolean =
// TODO get rid of type mapper (take care of '@EnhancedNullability', maybe some other stuff).
AsmUtil.isPrimitive(context.typeMapper.mapType(this))
override fun lower(irFile: IrFile) {
val transformer = object : IrElementTransformer<IrClass?> {
@@ -105,20 +142,93 @@ class JvmOptimizationLowering(val context: JvmBackendContext) : FileLoweringPass
}
getOperandsIfCallToEQEQOrEquals(expression)?.let { (left, right) ->
return when {
left.isNullConst() && right.isNullConst() ->
IrConstImpl.constTrue(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType)
if (left.isNullConst() && right.isNullConst())
return IrConstImpl.constTrue(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType)
left.isNullConst() && right is IrConst<*> || right.isNullConst() && left is IrConst<*> ->
IrConstImpl.constFalse(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType)
if (left.isNullConst() && right is IrConst<*> || right.isNullConst() && left is IrConst<*>)
return IrConstImpl.constFalse(expression.startOffset, expression.endOffset, context.irBuiltIns.booleanType)
else -> expression
val safeCallLeft = parseSafeCall(left)
if (safeCallLeft != null && right.type.isJvmPrimitive()) {
return rewriteSafeCallEqeqPrimitive(safeCallLeft, right, expression)
}
val safeCallRight = parseSafeCall(right)
if (safeCallRight != null && left.type.isJvmPrimitive()) {
return rewritePrimitiveEqeqSafeCall(left, safeCallRight, expression)
}
return expression
}
return expression
}
private fun rewriteSafeCallEqeqPrimitive(safeCall: SafeCallInfo, primitive: IrExpression, eqeqCall: IrCall): IrExpression =
context.createJvmIrBuilder(safeCall.scopeSymbol).run {
// Fuze safe call with primitive equality to avoid boxing the primitive.
// 'a?.<...> == p' becomes:
// {
// val tmp = a
// when {
// tmp == null -> false
// else -> tmp == p
// }
// }
irBlock {
+safeCall.tmpVal
+irWhen(
eqeqCall.type,
listOf(
irBranch(safeCall.ifNullBranch.condition, irFalse()),
irElseBranch(
irCall(eqeqCall.symbol).apply {
putValueArgument(0, safeCall.ifNotNullBranch.result)
putValueArgument(1, primitive)
}
)
)
)
}
}
private fun rewritePrimitiveEqeqSafeCall(primitive: IrExpression, safeCall: SafeCallInfo, eqeqCall: IrCall): IrExpression =
context.createJvmIrBuilder(safeCall.scopeSymbol).run {
// Fuze safe call with primitive equality to avoid boxing the primitive.
// 'p == a?.<...>' becomes:
// {
// val tmp_p = p // should evaluate 'p' before 'a'
// val tmp = a
// when {
// tmp == null -> false
// else -> tmp_p == tmp
// }
// }
// 'tmp_p' above could be elided if 'p' is a variable or a constant.
irBlock {
val lhs =
if (primitive.isTrivial())
primitive
else {
val tmp = irTemporary(primitive)
irGet(tmp)
}
+safeCall.tmpVal
+irWhen(
eqeqCall.type,
listOf(
irBranch(safeCall.ifNullBranch.condition, irFalse()),
irElseBranch(
irCall(eqeqCall.symbol).apply {
putValueArgument(0, lhs)
putValueArgument(1, safeCall.ifNotNullBranch.result)
}
)
)
)
}
}
private fun IrType.isByteOrShort() = isByte() || isShort()
// For `==` and `!=`, get rid of safe calls to convert `Byte?` or `Short?` to `Int?`.

View File

@@ -76,7 +76,7 @@ class WasmBackendContext(
override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET
override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET
}, internalPackageFragmentDescriptor).also {
}, internalPackageFragmentDescriptor, irModuleFragment).also {
irModuleFragment.files += it
}
}

View File

@@ -47,7 +47,7 @@ class ModuleGenerator(
IrModuleFragmentImpl(context.moduleDescriptor, context.irBuiltIns).also { irModule ->
val irDeclarationGenerator = DeclarationGenerator(context)
ktFiles.toSet().mapTo(irModule.files) { ktFile ->
generateSingleFile(irDeclarationGenerator, ktFile)
generateSingleFile(irDeclarationGenerator, ktFile, irModule)
}
}
@@ -69,8 +69,8 @@ class ModuleGenerator(
.generateUnboundSymbolsAsDependencies()
}
private fun generateSingleFile(irDeclarationGenerator: DeclarationGenerator, ktFile: KtFile): IrFileImpl {
val irFile = createEmptyIrFile(ktFile)
private fun generateSingleFile(irDeclarationGenerator: DeclarationGenerator, ktFile: KtFile, module: IrModuleFragment): IrFileImpl {
val irFile = createEmptyIrFile(ktFile, module)
for (ktAnnotationEntry in ktFile.annotationEntries) {
val annotationDescriptor = getOrFail(BindingContext.ANNOTATION, ktAnnotationEntry)
@@ -101,10 +101,10 @@ class ModuleGenerator(
return irFile
}
private fun createEmptyIrFile(ktFile: KtFile): IrFileImpl {
private fun createEmptyIrFile(ktFile: KtFile, module: IrModuleFragment): IrFileImpl {
val fileEntry = PsiIrFileEntry(ktFile)
val packageFragmentDescriptor = context.moduleDescriptor.findPackageFragmentForFile(ktFile)!!
return IrFileImpl(fileEntry, packageFragmentDescriptor).apply {
return IrFileImpl(fileEntry, packageFragmentDescriptor, module).apply {
metadata = DescriptorMetadataSource.File(CodegenUtil.getMemberDescriptorsToGenerate(ktFile, context.bindingContext))
}
}

View File

@@ -42,6 +42,8 @@ abstract class IrExternalPackageFragment : IrPackageFragment() {
abstract class IrFile : IrPackageFragment(), IrMutableAnnotationContainer, IrMetadataSourceOwner {
abstract override val symbol: IrFileSymbol
abstract val module: IrModuleFragment
abstract val fileEntry: IrFileEntry
override fun <D> transform(transformer: IrElementTransformer<D>, data: D): IrFile =

View File

@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.IrFileEntry
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.MetadataSource
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
@@ -39,10 +40,27 @@ class IrFileImpl(
packageFragmentDescriptor: PackageFragmentDescriptor
) : this(fileEntry, IrFileSymbolImpl(packageFragmentDescriptor), packageFragmentDescriptor.fqName)
constructor(
fileEntry: IrFileEntry,
packageFragmentDescriptor: PackageFragmentDescriptor,
module: IrModuleFragment,
) : this(fileEntry, IrFileSymbolImpl(packageFragmentDescriptor), packageFragmentDescriptor.fqName, module)
constructor(
fileEntry: IrFileEntry,
symbol: IrFileSymbol,
fqName: FqName,
module: IrModuleFragment
) : this(fileEntry, symbol, fqName) {
this.module = module
}
init {
symbol.bind(this)
}
override lateinit var module: IrModuleFragment
override val startOffset: Int
get() = 0

View File

@@ -53,6 +53,8 @@ open class DeepCopyIrTreeWithSymbols(
private val symbolRenamer: SymbolRenamer
) : IrElementTransformerVoid() {
private var transformedModule: IrModuleFragment? = null
constructor(symbolRemapper: SymbolRemapper, typeRemapper: TypeRemapper) : this(symbolRemapper, typeRemapper, SymbolRenamer.DEFAULT)
init {
@@ -82,12 +84,16 @@ open class DeepCopyIrTreeWithSymbols(
override fun visitElement(element: IrElement): IrElement =
throw IllegalArgumentException("Unsupported element type: $element")
override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment =
IrModuleFragmentImpl(
override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment {
val result = IrModuleFragmentImpl(
declaration.descriptor,
declaration.irBuiltins,
declaration.files.transform()
)
transformedModule = result
result.files += declaration.files.transform()
transformedModule = null
return result
}
override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment): IrExternalPackageFragment =
IrExternalPackageFragmentImpl(
@@ -101,7 +107,8 @@ open class DeepCopyIrTreeWithSymbols(
IrFileImpl(
declaration.fileEntry,
symbolRemapper.getDeclaredFile(declaration.symbol),
symbolRenamer.getFileName(declaration.symbol)
symbolRenamer.getFileName(declaration.symbol),
transformedModule ?: declaration.module
).apply {
transformAnnotations(declaration)
declaration.transformDeclarationsTo(this)

View File

@@ -103,7 +103,7 @@ abstract class BasicIrModuleDeserializer(
private fun deserializeIrFile(fileProto: ProtoFile, fileIndex: Int, moduleDeserializer: IrModuleDeserializer, allowErrorNodes: Boolean): IrFile {
val fileReader = IrLibraryFileFromKlib(moduleDeserializer.klib, fileIndex)
val file = fileReader.createFile(moduleDescriptor, fileProto)
val file = fileReader.createFile(moduleFragment, fileProto)
val fileDeserializationState = FileDeserializationState(
linker,

View File

@@ -7,8 +7,7 @@ package org.jetbrains.kotlin.backend.common.serialization
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrFileSymbolImpl
import org.jetbrains.kotlin.ir.util.IdSignature
@@ -154,11 +153,11 @@ internal fun IrLibraryFile.deserializeString(index: Int): String = WobblyTF8.dec
internal fun IrLibraryFile.deserializeFqName(fqn: List<Int>): String =
fqn.joinToString(".", transform = ::deserializeString)
internal fun IrLibraryFile.createFile(moduleDescriptor: ModuleDescriptor, fileProto: ProtoFile): IrFile {
internal fun IrLibraryFile.createFile(module: IrModuleFragment, fileProto: ProtoFile): IrFile {
val fileName = fileProto.fileEntry.name
val fileEntry = NaiveSourceBasedFileEntryImpl(fileName, fileProto.fileEntry.lineStartOffsetsList.toIntArray())
val fqName = FqName(deserializeFqName(fileProto.fqNameList))
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(moduleDescriptor, fqName)
val packageFragmentDescriptor = EmptyPackageFragmentDescriptor(module.descriptor, fqName)
val symbol = IrFileSymbolImpl(packageFragmentDescriptor)
return IrFileImpl(fileEntry, symbol, fqName)
return IrFileImpl(fileEntry, symbol, fqName, module)
}

View File

@@ -1,3 +1,6 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
compiler/testData/cli/jvm/conflictingProjection.kt:10:15: error: projection is conflicting with variance of the corresponding type parameter of Out<in kotlin/Int>. Remove the projection or replace it with '*'
fun a8(value: Out<in Int>) {}
^

View File

@@ -1,3 +1,6 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
compiler/testData/cli/jvm/extendedCheckers.kt:2:12: warning: redundant explicit type
val i: Int = 1
^

View File

@@ -1 +1,4 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
OK

View File

@@ -1,3 +1,6 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
compiler/testData/cli/jvm/firError.kt:5:13: error: x must be initialized before access
println(x)
^

View File

@@ -1 +1,4 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
OK

View File

@@ -1,3 +1,6 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
compiler/testData/cli/jvm/inapplicableLateinitModifier.kt:6:1: error: 'lateinit' modifier is not allowed on delegated properties
lateinit var kest by Delegate
^

View File

@@ -1,3 +1,6 @@
warning: ATTENTION!
This build uses in-dev FIR:
-Xuse-fir
compiler/testData/cli/jvm/instanceAccessBeforeSuperCall.kt:2:26: error: unresolved reference: getSomeInt
constructor(x: Int = getSomeInt(), other: A = this, header: String = keker) {}
^

View File

@@ -0,0 +1,23 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: COROUTINES
// !LANGUAGE: +SuspendConversion
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
fun runSuspend(c: (suspend () -> Unit)?) {
c?.startCoroutine(EmptyContinuation)
}
var test = "failed"
fun foo() { test = "OK" }
fun box(): String {
runSuspend(::foo)
return test
}

View File

@@ -0,0 +1,47 @@
// WITH_RUNTIME
import kotlin.coroutines.*
class B {
val value: Long = 10L
open inner class C : A<Unit> {
override suspend fun getTotalFrames(): Long? = this@B.value
open inner class D : A<Unit> {
override suspend fun getTotalFrames(): Long? = this@B.value
}
suspend fun getInnerTotalFrames(): Long? = D().getTotalFrames()
}
suspend fun get1(): Long? {
return C().getTotalFrames()
}
suspend fun get2(): Long? = C().getInnerTotalFrames()
}
interface A<T> {
suspend fun getTotalFrames(): Long? = null
}
fun builder(c: suspend () -> Unit) {
c.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
}
fun box(): String {
var res = "FAIL"
builder {
res = if (B().get1() == 10L) "OK" else "FAIL 1 ${B().get1()}"
}
if (res != "OK") return res
res = "FAIL 2"
builder {
res = if (B().get2() == 10L) "OK" else "FAIL 2 ${B().get2()}"
}
return res
}

View File

@@ -0,0 +1,25 @@
// WITH_RUNTIME
// WITH_COROUTINES
import helpers.*
import kotlin.coroutines.*
import kotlin.coroutines.intrinsics.*
suspend fun suspendHere(): String = suspendCoroutineUninterceptedOrReturn { x ->
x.resume("OK")
COROUTINE_SUSPENDED
}
fun builder(c: (suspend () -> Unit)?) {
c?.startCoroutine(EmptyContinuation)
}
fun box(): String {
var result = ""
builder(null)
builder {
result = suspendHere()
}
return result
}

View File

@@ -0,0 +1,31 @@
// WITH_RUNTIME
// IGNORE_BACKEND: JS, JS_IR, JVM
// !LANGUAGE: +SuspendFunctionAsSupertype
import kotlin.coroutines.*
var res = "FAIL"
class C: suspend () -> Unit {
override suspend fun invoke() {
res = "OK"
}
}
fun box(): String {
val o: suspend () -> Unit = object : suspend () -> Unit {
override suspend fun invoke() {
res = "OK"
}
}
o.startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
if (res != "OK") return "FAIL 1: $res"
res = "FAIL 2"
C().startCoroutine(Continuation(EmptyCoroutineContext) {
it.getOrThrow()
})
return res
}

View File

@@ -0,0 +1,12 @@
// !API_VERSION: 1.4
// KJS_WITH_FULL_RUNTIME
// WITH_RUNTIME
val x = 0u
val y = 0uL
fun box(): String {
if (x != 0u) return "Fail 1"
if (y != 0uL) return "Fail 2"
return "OK"
}

View File

@@ -1,11 +1,58 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_FIR: JVM_IR
fun foo() {
val x: Int? = 6
val hc = x!!.hashCode()
fun testBoolean(): Int {
val b: Boolean? = true
return b!!.hashCode()
}
fun testByte(): Int {
val b: Byte? = 1.toByte()
return b!!.hashCode()
}
fun testChar(): Int {
val c: Char? = 'x'
return c!!.hashCode()
}
fun testShort(): Int {
val s: Short? = 1.toShort()
return s!!.hashCode()
}
fun testInt(): Int {
val i: Int? = 42
return i!!.hashCode()
}
fun testLong(): Int {
val l: Long? = 42L
return l!!.hashCode()
}
fun testFloat(): Int {
val f: Float? = 0.0f
return f!!.hashCode()
}
fun testDouble(): Int {
val d: Double? = 0.0
return d!!.hashCode()
}
// 1 java/lang/Boolean.hashCode \(Z\)I
// 1 java/lang/Character.hashCode \(C\)I
// 1 java/lang/Byte.hashCode \(B\)I
// 1 java/lang/Short.hashCode \(S\)I
// 1 java/lang/Integer.hashCode \(I\)I
// 0 java/lang/Integer.valueOf
// 1 java/lang/Long.hashCode \(J\)I
// 1 java/lang/Float.hashCode \(F\)I
// 1 java/lang/Double.hashCode \(D\)I
// 0 valueOf
// 0 byteValue
// 0 shortValue
// 0 intValue
// 0 longValue
// 0 floatValue
// 0 doubleValue
// 0 charValue

View File

@@ -1,7 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// TODO KT-36646 Don't box primitive values in equality comparison with nullable primitive values in JVM_IR
fun Long.id() = this
fun String.drop2() = if (length >= 2) subSequence(2, length) else null

View File

@@ -1,7 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// IGNORE_BACKEND: JVM_IR
// TODO KT-36637 Trivial closure optimizatin in JVM_IR
fun test() {
fun local(){
@@ -21,6 +17,12 @@ fun test() {
(::local)()
}
// JVM_TEMPLATES
// 3 GETSTATIC ConstClosureOptimizationKt\$test\$1\.INSTANCE
// 1 GETSTATIC ConstClosureOptimizationKt\$test\$2\.INSTANCE
// 1 GETSTATIC ConstClosureOptimizationKt\$test\$3\.INSTANCE
// JVM_IR_TEMPLATES
// 1 GETSTATIC ConstClosureOptimizationKt\$test\$1.INSTANCE
// 1 GETSTATIC ConstClosureOptimizationKt\$test\$2.INSTANCE
// 1 GETSTATIC ConstClosureOptimizationKt\$test\$local\$1.INSTANCE

View File

@@ -1,4 +1,3 @@
// KOTLIN_CONFIGURATION_FLAGS: STRING_CONCAT=indy-with-constants
// JVM_TARGET: 9
class A

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