[FIR] Support the simple case of java field interpretation
#KT-57802
This commit is contained in:
@@ -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(
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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(
|
||||
|
||||
+19
-1
@@ -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"
|
||||
}
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user