[FIR] Support the simple case of java field interpretation

#KT-57802
This commit is contained in:
Ivan Kylchik
2023-09-04 16:18:27 +02:00
committed by Space Team
parent 2af73c2b13
commit 886ef1a4b4
11 changed files with 148 additions and 6 deletions
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.backend.common.actualizer.FakeOverrideRebuilder
import org.jetbrains.kotlin.backend.common.sourceElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.*
@@ -31,28 +30,32 @@ import org.jetbrains.kotlin.fir.extensions.declarationGenerators
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.generatedMembers
import org.jetbrains.kotlin.fir.extensions.generatedNestedClassifiers
import org.jetbrains.kotlin.fir.java.javaElementFinder
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
import org.jetbrains.kotlin.fir.types.resolvedType
import org.jetbrains.kotlin.ir.PsiIrFileEntry
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.PsiIrFileEntry
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.interpreter.IrInterpreter
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterConfiguration
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
import org.jetbrains.kotlin.ir.interpreter.checker.EvaluationMode
import org.jetbrains.kotlin.ir.interpreter.transformer.evaluate
import org.jetbrains.kotlin.ir.interpreter.transformer.transformConst
import org.jetbrains.kotlin.ir.overrides.IrFakeOverrideBuilder
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionPublicSymbolImpl
import org.jetbrains.kotlin.ir.types.IrTypeSystemContext
import org.jetbrains.kotlin.ir.util.KotlinMangler
import org.jetbrains.kotlin.ir.util.NaiveSourceBasedFileEntryImpl
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fileOrNull
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
@@ -107,7 +110,7 @@ class Fir2IrConverter(
}
}
evaluateConstants(irModuleFragment, configuration)
evaluateConstants(irModuleFragment, components)
}
fun bindFakeOverridesOrPostpone(declarations: List<IrDeclaration>) {
@@ -528,7 +531,8 @@ class Fir2IrConverter(
}
companion object {
private fun evaluateConstants(irModuleFragment: IrModuleFragment, fir2IrConfiguration: Fir2IrConfiguration) {
private fun evaluateConstants(irModuleFragment: IrModuleFragment, components: Fir2IrComponents) {
val fir2IrConfiguration = components.configuration
val firModuleDescriptor = irModuleFragment.descriptor as? FirModuleDescriptor
val targetPlatform = firModuleDescriptor?.platform
val languageVersionSettings = firModuleDescriptor?.session?.languageVersionSettings ?: return
@@ -538,8 +542,30 @@ class Fir2IrConverter(
platform = targetPlatform,
printOnlyExceptionMessage = true,
)
val interpreter = IrInterpreter(IrInterpreterEnvironment(irModuleFragment.irBuiltins, configuration))
val mode = if (intrinsicConstEvaluation) EvaluationMode.ONLY_INTRINSIC_CONST else EvaluationMode.ONLY_BUILTINS
components.session.javaElementFinder?.propertyEvaluator = eval@{ firProperty ->
val irProperty = components.declarationStorage.getCachedIrProperty(firProperty, fakeOverrideOwnerLookupTag = null) ?: return@eval null
fun IrProperty.tryToGetConst(): IrConst<*>? {
return (backingField?.initializer?.expression as? IrConst<*>)
}
irProperty.tryToGetConst()?.let { return@eval it.value.toString() }
val irFile = irProperty.fileOrNull ?: return@eval null
// Note: can't evaluate all expressions in given file, because we can accidentally get recursive processing and
// second call of `Fir2IrLazyField.initializer` will return null
val evaluated = irProperty.evaluate(
irFile, interpreter, mode,
evaluatedConstTracker = fir2IrConfiguration.evaluatedConstTracker,
inlineConstTracker = fir2IrConfiguration.inlineConstTracker,
)
return@eval evaluated?.tryToGetConst()?.value?.toString()
}
val ktDiagnosticReporter = KtDiagnosticReporterWithImplicitIrBasedContext(fir2IrConfiguration.diagnosticReporter, languageVersionSettings)
irModuleFragment.files.forEach {
it.transformConst(
@@ -29167,6 +29167,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57313.kt");
}
@Test
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@Test
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
@@ -29167,6 +29167,12 @@ public class FirLightTreeBlackBoxCodegenWithIrFakeOverrideGeneratorTestGenerated
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57313.kt");
}
@Test
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@Test
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
@@ -29167,6 +29167,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57313.kt");
}
@Test
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@Test
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
@@ -9,6 +9,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pair
import com.intellij.psi.*
import com.intellij.psi.impl.cache.ModifierFlags
import com.intellij.psi.impl.cache.TypeInfo
import com.intellij.psi.impl.compiled.ClsClassImpl
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.file.PsiPackageImpl
@@ -24,12 +25,14 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
@@ -48,11 +51,14 @@ import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
val FirSession.javaElementFinder: FirJavaElementFinder? by FirSession.nullableSessionComponentAccessor<FirJavaElementFinder>()
private typealias PropertyEvaluator = (FirProperty) -> String?
class FirJavaElementFinder(
private val session: FirSession,
project: Project
) : PsiElementFinder(), KotlinFinderMarker, FirSessionComponent {
private val psiManager = PsiManager.getInstance(project)
var propertyEvaluator: PropertyEvaluator? = null
private val firProviders: List<FirProvider> = buildList {
add(session.firProvider)
@@ -111,6 +117,18 @@ class FirJavaElementFinder(
)
)
val classProperties = firClass.declarations.filterIsInstance<FirProperty>()
// Note: we must store companion properties in outer clas because java resolver will not find it other way.
val companionProperties = firClass.companionObjectSymbol?.declarationSymbols?.map { it.fir }?.filterIsInstance<FirProperty>() ?: emptyList()
(classProperties + companionProperties).forEach {
// TODO correct type info
val psiField = PsiFieldStubImpl(
stub, it.name.identifier, TypeInfo.fromString("int"), propertyEvaluator?.invoke(it),
PsiFieldStubImpl.packFlags(false, false, false, false)
)
PsiModifierListStubImpl(psiField, ModifierFlags.PUBLIC_MASK + ModifierFlags.FINAL_MASK + ModifierFlags.STATIC_MASK)
}
PsiModifierListStubImpl(stub, firClass.packFlags())
newTypeParameterList(
@@ -75,6 +75,24 @@ fun IrFile.runConstOptimizations(
preprocessedFile.transform(irConstExpressionTransformer, IrConstTransformer.Data())
}
// TODO simplify
fun IrProperty.evaluate(
irFile: IrFile,
interpreter: IrInterpreter,
mode: EvaluationMode,
evaluatedConstTracker: EvaluatedConstTracker? = null,
inlineConstTracker: InlineConstTracker? = null,
onWarning: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
onError: (IrFile, IrElement, IrErrorExpression) -> Unit = { _, _, _ -> },
suppressExceptions: Boolean = false,
): IrProperty? {
val checker = IrInterpreterCommonChecker()
val irConstExpressionTransformer = IrConstAllTransformer(
interpreter, irFile, mode, checker, evaluatedConstTracker, inlineConstTracker, onWarning, onError, suppressExceptions
)
return this.transform(irConstExpressionTransformer, IrConstTransformer.Data()) as? IrProperty
}
private fun IrFile.preprocessForConstTransformer(
interpreter: IrInterpreter,
mode: EvaluationMode,
@@ -88,7 +106,7 @@ private fun IrFile.preprocessForConstTransformer(
// Note: We are using `IrElementTransformer` here instead of `IrElementTransformerVoid` to avoid conflicts with `IrTypeVisitorVoid`
// that is used later in `IrConstTypeAnnotationTransformer`.
internal abstract class IrConstTransformer(
abstract class IrConstTransformer(
protected val interpreter: IrInterpreter,
private val irFile: IrFile,
private val mode: EvaluationMode,
@@ -0,0 +1,39 @@
// TARGET_BACKEND: JVM
// FILE: Bar.java
package one.two;
public class Bar {
public static final int BAR = Doo.DOO + 1;
}
// FILE: Boo.java
package one.two;
public class Boo {
public static final int BOO = Baz.BAZ + 1;
}
// FILE: Main.kt
package one.two
class Foo {
companion object {
const val FOO = <!EVALUATED("5")!>Boo.BOO + 1<!>
}
}
class Baz {
companion object {
const val BAZ = <!EVALUATED("3")!>Bar.BAR + 1<!>
}
}
class Doo {
companion object {
const val DOO = <!EVALUATED("1")!>1<!>
}
}
fun box(): String {
return "OK"
}
@@ -27823,6 +27823,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57028.kt");
}
@Test
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@Test
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
@@ -29167,6 +29167,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57313.kt");
}
@Test
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@Test
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
@@ -29167,6 +29167,12 @@ public class IrBlackBoxCodegenWithIrInlinerTestGenerated extends AbstractIrBlack
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57313.kt");
}
@Test
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@Test
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
@@ -24625,6 +24625,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57313.kt");
}
@TestMetadata("kt57802.kt")
public void testKt57802() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt57802.kt");
}
@TestMetadata("kt58005.kt")
public void testKt58005() throws Exception {
runTest("compiler/testData/codegen/box/involvesIrInterpreter/kt58005.kt");