From 4d29d6e3b4dc5cf48716dbf116fb343a05ae8ec9 Mon Sep 17 00:00:00 2001 From: Dmitrii Gridin Date: Tue, 10 Oct 2023 15:05:34 +0200 Subject: [PATCH] [LL FIR] FileStructure: accurate processing of generated declarations inside classes We should process generated property as a part of the primary constructor. This was already implemented in 8387ea8a, but some parts were missed. ClassDiagnosticRetriever: * dropped relation to properties generated from constructor parameters as they should belong to the primary constructor only * accurate logic to fully visit an implicit primary constructor to be able to process nested declarations (e.g., inside a super type call) SingleNonLocalDeclarationDiagnosticRetriever: * add relation to generated properties as now they fully belong to the constructor FileElementFactory: * dropped explicit resolution of generated properties from a constructor * added explicit resolution of generated enum members for consistency. Effectively, this is not required because we don't have compiler checkers for such generated enum member declarations ClassDeclarationStructureElement: * do not collect mapping for generated properties from constructor * explicitly declare that we should process only ClassDelegationField ^KT-62437 Fixed --- ...onsOnPropertyFromParameter.descriptors.txt | 19 -------- ...lvedAnnotationsOnPropertyFromParameter.txt | 15 ++++++ ...InsideSuperConstructorCall.descriptors.txt | 4 -- ...vedReferenceInsideSuperConstructorCall.txt | 3 ++ ...uctorCallWithLocalFunction.descriptors.txt | 4 -- ...eSuperConstructorCallWithLocalFunction.txt | 3 ++ ...FileStructureElementDiagnosticRetriever.kt | 46 ++++++++++++++----- .../fir/file/structure/FileElementFactory.kt | 5 +- .../file/structure/FileStructureElement.kt | 30 ++++++------ .../types/superTypeOnEnumClass.txt | 10 ++-- .../getOrBuildFir/wholeDeclaration/enum.txt | 18 ++++---- 11 files changed, 89 insertions(+), 68 deletions(-) delete mode 100644 analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.descriptors.txt delete mode 100644 analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.descriptors.txt delete mode 100644 analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.descriptors.txt diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.descriptors.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.descriptors.txt deleted file mode 100644 index 179b9f44125..00000000000 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.descriptors.txt +++ /dev/null @@ -1,19 +0,0 @@ -Diagnostics from elements: - for PSI element of type KtNameReferenceExpression at (2,15-27) - UNRESOLVED_REFERENCE text ranges: [(23,35)] - PSI: KtNameReferenceExpression at (2,15-27) - for PSI element of type KtNameReferenceExpression at (3,10-20) - UNRESOLVED_REFERENCE text ranges: [(45,55)] - PSI: KtNameReferenceExpression at (3,10-20) - for PSI element of type KtNameReferenceExpression at (4,10-20) - UNRESOLVED_REFERENCE text ranges: [(65,75)] - PSI: KtNameReferenceExpression at (4,10-20) - for PSI element of type KtNameReferenceExpression at (5,15-30) - UNRESOLVED_REFERENCE text ranges: [(90,105)] - PSI: KtNameReferenceExpression at (5,15-30) - for PSI element of type KtNameReferenceExpression at (6,12-21) - UNRESOLVED_REFERENCE text ranges: [(117,126)] - PSI: KtNameReferenceExpression at (6,12-21) - for PSI element of type KtNameReferenceExpression at (7,12-21) - UNRESOLVED_REFERENCE text ranges: [(138,147)] - PSI: KtNameReferenceExpression at (7,12-21) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.txt index b363e28d561..179b9f44125 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.txt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedAnnotationsOnPropertyFromParameter.txt @@ -1,4 +1,19 @@ Diagnostics from elements: + for PSI element of type KtNameReferenceExpression at (2,15-27) + UNRESOLVED_REFERENCE text ranges: [(23,35)] + PSI: KtNameReferenceExpression at (2,15-27) + for PSI element of type KtNameReferenceExpression at (3,10-20) + UNRESOLVED_REFERENCE text ranges: [(45,55)] + PSI: KtNameReferenceExpression at (3,10-20) + for PSI element of type KtNameReferenceExpression at (4,10-20) + UNRESOLVED_REFERENCE text ranges: [(65,75)] + PSI: KtNameReferenceExpression at (4,10-20) + for PSI element of type KtNameReferenceExpression at (5,15-30) + UNRESOLVED_REFERENCE text ranges: [(90,105)] + PSI: KtNameReferenceExpression at (5,15-30) + for PSI element of type KtNameReferenceExpression at (6,12-21) + UNRESOLVED_REFERENCE text ranges: [(117,126)] + PSI: KtNameReferenceExpression at (6,12-21) for PSI element of type KtNameReferenceExpression at (7,12-21) UNRESOLVED_REFERENCE text ranges: [(138,147)] PSI: KtNameReferenceExpression at (7,12-21) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.descriptors.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.descriptors.txt deleted file mode 100644 index 2faa9dd12f0..00000000000 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.descriptors.txt +++ /dev/null @@ -1,4 +0,0 @@ -Diagnostics from elements: - for PSI element of type KtNameReferenceExpression at (4,5-15) - UNRESOLVED_REFERENCE text ranges: [(90,100)] - PSI: KtNameReferenceExpression at (4,5-15) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.txt index 9f370a89565..2faa9dd12f0 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.txt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCall.txt @@ -1 +1,4 @@ Diagnostics from elements: + for PSI element of type KtNameReferenceExpression at (4,5-15) + UNRESOLVED_REFERENCE text ranges: [(90,100)] + PSI: KtNameReferenceExpression at (4,5-15) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.descriptors.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.descriptors.txt deleted file mode 100644 index 1aa52c2bc6f..00000000000 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.descriptors.txt +++ /dev/null @@ -1,4 +0,0 @@ -Diagnostics from elements: - for PSI element of type KtNameReferenceExpression at (6,17-27) - UNRESOLVED_REFERENCE text ranges: [(147,157)] - PSI: KtNameReferenceExpression at (6,17-27) diff --git a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.txt b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.txt index 9f370a89565..1aa52c2bc6f 100644 --- a/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.txt +++ b/analysis/analysis-api/testData/components/diagnosticsProvider/diagnostics/unresolvedReferenceInsideSuperConstructorCallWithLocalFunction.txt @@ -1 +1,4 @@ Diagnostics from elements: + for PSI element of type KtNameReferenceExpression at (6,17-27) + UNRESOLVED_REFERENCE text ranges: [(147,157)] + PSI: KtNameReferenceExpression at (6,17-27) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/FileStructureElementDiagnosticRetriever.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/FileStructureElementDiagnosticRetriever.kt index 22895d22177..f071c6cf16d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/FileStructureElementDiagnosticRetriever.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostics/FileStructureElementDiagnosticRetriever.kt @@ -13,12 +13,13 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.visitScrip import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContextForProvider import org.jetbrains.kotlin.fir.analysis.collectors.DiagnosticCollectorComponents +import org.jetbrains.kotlin.fir.correspondingProperty +import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirScript -import org.jetbrains.kotlin.fir.declarations.FirValueParameter -import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor +import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor import org.jetbrains.kotlin.fir.resolve.SessionHolderImpl import org.jetbrains.kotlin.util.withSourceCodeAnalysisExceptionUnwrapping @@ -50,16 +51,27 @@ internal class ClassDiagnosticRetriever( private class Visitor( private val structureElementDeclaration: FirRegularClass, context: CheckerContextForProvider, - components: DiagnosticCollectorComponents + components: DiagnosticCollectorComponents, ) : LLFirDiagnosticVisitor(context, components) { + override fun shouldVisitDeclaration(declaration: FirDeclaration): Boolean = when { + declaration === structureElementDeclaration -> true + insideFakeDeclaration -> true + declaration.isImplicitConstructor -> true + else -> false + } - override fun shouldVisitDeclaration(declaration: FirDeclaration): Boolean { - return when { - declaration == structureElementDeclaration -> true - shouldDiagnosticsAlwaysBeCheckedOn(declaration) -> true - declaration is FirDefaultPropertyAccessor -> shouldVisitDeclaration(declaration.propertySymbol.fir) - declaration is FirValueParameter -> shouldVisitDeclaration(declaration.containingFunctionSymbol.fir) - else -> false + private var insideFakeDeclaration: Boolean = false + + override fun visitNestedElements(element: FirElement) { + if (element.isImplicitConstructor) { + insideFakeDeclaration = true + try { + super.visitNestedElements(element) + } finally { + insideFakeDeclaration = false + } + } else { + super.visitNestedElements(element) } } } @@ -73,6 +85,9 @@ internal class ClassDiagnosticRetriever( } } +internal val FirElement.isImplicitConstructor: Boolean + get() = this is FirConstructor && source?.kind == KtFakeSourceElementKind.ImplicitConstructor + internal class SingleNonLocalDeclarationDiagnosticRetriever( private val structureElementDeclaration: FirDeclaration ) : FileStructureElementDiagnosticRetriever() { @@ -94,9 +109,16 @@ internal class SingleNonLocalDeclarationDiagnosticRetriever( context: CheckerContextForProvider, components: DiagnosticCollectorComponents ) : LLFirDiagnosticVisitor(context, components) { + override fun visitConstructor(constructor: FirConstructor, data: Nothing?) { + super.visitConstructor(constructor, data) - override fun shouldVisitDeclaration(declaration: FirDeclaration): Boolean { - return true + if (constructor is FirPrimaryConstructor) { + for (valueParameter in constructor.valueParameters) { + valueParameter.correspondingProperty?.let { + visitProperty(it, data) + } + } + } } } } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt index 552d5d3b12a..2a9b56bbc1d 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileElementFactory.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.KtFakeSourceElementKind import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveComponents import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDesignationWithFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets.LLFirClassWithSpecificMembersResolveTarget +import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.isImplicitConstructor import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.impl.FirPrimaryConstructor @@ -35,11 +36,11 @@ internal object FileElementFactory { add(member) } - member is FirPrimaryConstructor && member.source?.kind == KtFakeSourceElementKind.ImplicitConstructor -> { + member.source?.kind == KtFakeSourceElementKind.EnumGeneratedDeclaration -> { add(member) } - member is FirProperty && member.source?.kind == KtFakeSourceElementKind.PropertyFromParameter -> { + member.isImplicitConstructor -> { add(member) } diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt index 0b161bf6304..c791669363c 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/FileStructureElement.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileDiagnosti import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.FileStructureElementDiagnostics import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.ScriptDiagnosticRetriever import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.SingleNonLocalDeclarationDiagnosticRetriever +import org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.isImplicitConstructor import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isScriptStatement import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.correspondingProperty @@ -160,32 +161,35 @@ internal class ClassDeclarationStructureElement( class Recorder(private val firClass: FirRegularClass) : FirElementsRecorder() { override fun visitProperty(property: FirProperty, data: MutableMap) { - if (property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter) { - super.visitProperty(property, data) - } } override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableMap) { } override fun visitConstructor(constructor: FirConstructor, data: MutableMap) { - if ( - (constructor is FirPrimaryConstructor || constructor is FirErrorPrimaryConstructor) && - constructor.source?.kind == KtFakeSourceElementKind.ImplicitConstructor - ) { + if (constructor.isImplicitConstructor) { DeclarationStructureElement.Recorder.visitConstructor(constructor, data) } } - override fun visitErrorPrimaryConstructor(errorPrimaryConstructor: FirErrorPrimaryConstructor, data: MutableMap) = - visitConstructor(errorPrimaryConstructor, data) + override fun visitField(field: FirField, data: MutableMap) { + if (field.source?.kind == KtFakeSourceElementKind.ClassDelegationField) { + DeclarationStructureElement.Recorder.visitField(field, data) + } + } + + override fun visitErrorPrimaryConstructor( + errorPrimaryConstructor: FirErrorPrimaryConstructor, + data: MutableMap, + ) = visitConstructor(errorPrimaryConstructor, data) override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: MutableMap) { } override fun visitRegularClass(regularClass: FirRegularClass, data: MutableMap) { - if (regularClass != firClass) return - super.visitRegularClass(regularClass, data) + if (regularClass === firClass) { + super.visitRegularClass(regularClass, data) + } } override fun visitTypeAlias(typeAlias: FirTypeAlias, data: MutableMap) { @@ -206,6 +210,8 @@ internal class DeclarationStructureElement( object Recorder : FirElementsRecorder() { override fun visitConstructor(constructor: FirConstructor, data: MutableMap) { + super.visitConstructor(constructor, data) + if (constructor is FirPrimaryConstructor) { constructor.valueParameters.forEach { parameter -> parameter.correspondingProperty?.let { property -> @@ -213,8 +219,6 @@ internal class DeclarationStructureElement( } } } - - super.visitConstructor(constructor, data) } } } diff --git a/analysis/low-level-api-fir/testData/getOrBuildFir/types/superTypeOnEnumClass.txt b/analysis/low-level-api-fir/testData/getOrBuildFir/types/superTypeOnEnumClass.txt index 95fa50cc097..21504ed02e9 100644 --- a/analysis/low-level-api-fir/testData/getOrBuildFir/types/superTypeOnEnumClass.txt +++ b/analysis/low-level-api-fir/testData/getOrBuildFir/types/superTypeOnEnumClass.txt @@ -19,16 +19,16 @@ FILE: [ResolvedTo(IMPORTS)] superTypeOnEnumClass.kt public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] enum entry ENTRY2: R|MyClass| = LAZY_EXPRESSION public final [ResolvedTo(STATUS)] fun boo([ResolvedTo(STATUS)] a: R|kotlin/String|): R|kotlin/Unit| { LAZY_BLOCK } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] fun values(): R|kotlin/Array| { + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] fun values(): R|kotlin/Array| { } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] fun valueOf([ResolvedTo(STATUS)] value: R|kotlin/String|): R|MyClass| { + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] fun valueOf([ResolvedTo(BODY_RESOLVE)] value: R|kotlin/String|): R|MyClass| { } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] val entries: R|kotlin/enums/EnumEntries| - public [ResolvedTo(STATUS)] get(): R|kotlin/enums/EnumEntries| + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] val entries: R|kotlin/enums/EnumEntries| + public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/enums/EnumEntries| } public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] fun foo(): R|kotlin/Int| { ^foo Int(42) - } + } \ No newline at end of file diff --git a/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/enum.txt b/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/enum.txt index e2e32b7607c..3eb493b2c72 100644 --- a/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/enum.txt +++ b/analysis/low-level-api-fir/testData/getOrBuildFir/wholeDeclaration/enum.txt @@ -15,14 +15,14 @@ public final [ResolvedTo(BODY_RESOLVE)] enum class MyClass : | { + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] fun values(): R|kotlin/Array| { } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] fun valueOf([ResolvedTo(STATUS)] value: R|kotlin/String|): R|MyClass| { + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] fun valueOf([ResolvedTo(BODY_RESOLVE)] value: R|kotlin/String|): R|MyClass| { } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] val entries: R|kotlin/enums/EnumEntries| - public [ResolvedTo(STATUS)] get(): R|kotlin/enums/EnumEntries| + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] val entries: R|kotlin/enums/EnumEntries| + public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/enums/EnumEntries| } @@ -40,16 +40,16 @@ FILE: [ResolvedTo(IMPORTS)] enum.kt public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] enum entry ENTRY2: R|MyClass| = LAZY_EXPRESSION public final [ResolvedTo(STATUS)] fun boo([ResolvedTo(STATUS)] a: R|kotlin/String|): R|kotlin/Unit| { LAZY_BLOCK } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] fun values(): R|kotlin/Array| { + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] fun values(): R|kotlin/Array| { } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] fun valueOf([ResolvedTo(STATUS)] value: R|kotlin/String|): R|MyClass| { + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] fun valueOf([ResolvedTo(BODY_RESOLVE)] value: R|kotlin/String|): R|MyClass| { } - public final static [ResolvedTo(STATUS)] [ContainingClassKey=MyClass] val entries: R|kotlin/enums/EnumEntries| - public [ResolvedTo(STATUS)] get(): R|kotlin/enums/EnumEntries| + public final static [ResolvedTo(BODY_RESOLVE)] [ContainingClassKey=MyClass] val entries: R|kotlin/enums/EnumEntries| + public [ResolvedTo(BODY_RESOLVE)] get(): R|kotlin/enums/EnumEntries| } public final [ResolvedTo(IMPLICIT_TYPES_BODY_RESOLVE)] fun foo(): R|kotlin/Int| { ^foo Int(42) - } \ No newline at end of file + }