Add basic FIR -> IR converter with a set of text tests

Tests duplicate IrTextTestCaseGenerated
#KT-24065 Fixed
This commit is contained in:
Mikhail Glukhikh
2019-04-05 13:37:48 +03:00
parent 92adfd8946
commit 881073b1c9
305 changed files with 22829 additions and 57 deletions
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":core:descriptors"))
compileOnly(project(":compiler:fir:cones"))
compileOnly(project(":compiler:fir:resolve"))
compileOnly(project(":compiler:fir:tree"))
compileOnly(project(":compiler:ir.tree"))
compileOnly(project(":compiler:ir.psi2ir"))
compileOnly(project(":compiler:ir.backend.common"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
testCompileOnly(intellijDep()) { includeJars("openapi", "idea", "idea_rt", "util", "asm-all", rootProject = rootProject) }
testRuntime(intellijDep())
testCompile(commonDep("junit:junit"))
testCompileOnly(project(":kotlin-test:kotlin-test-jvm"))
testCompileOnly(project(":kotlin-test:kotlin-test-junit"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":compiler:fir:resolve"))
testCompileOnly(project(":kotlin-reflect-api"))
testRuntime(project(":kotlin-reflect"))
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
projectTest {
workingDir = rootDir
}
testsJar()
@@ -0,0 +1,140 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.backend
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassifierSymbol
import org.jetbrains.kotlin.fir.symbols.LibraryTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeArgument
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
import org.jetbrains.kotlin.types.Variance
internal fun <T : IrElement> FirElement.convertWithOffsets(
f: (startOffset: Int, endOffset: Int) -> T
): T {
val startOffset = psi?.startOffsetSkippingComments ?: -1
val endOffset = psi?.endOffset ?: -1
return f(startOffset, endOffset)
}
internal fun createErrorType(): IrErrorType = IrErrorTypeImpl(null, emptyList(), Variance.INVARIANT)
fun FirTypeRef.toIrType(session: FirSession, declarationStorage: Fir2IrDeclarationStorage): IrType {
if (this !is FirResolvedTypeRef) {
return createErrorType()
}
return type.toIrType(session, declarationStorage)
}
fun ConeKotlinType.toIrType(session: FirSession, declarationStorage: Fir2IrDeclarationStorage): IrType {
return when (this) {
is ConeKotlinErrorType -> createErrorType()
is ConeLookupTagBasedType -> {
val firSymbol = this.lookupTag.toSymbol(session) ?: return createErrorType()
val irSymbol = firSymbol.toIrSymbol(session, declarationStorage)
// TODO: annotations
IrSimpleTypeImpl(
irSymbol, this.isMarkedNullable,
typeArguments.map { it.toIrTypeArgument(session, declarationStorage) },
emptyList()
)
}
is ConeFlexibleType -> {
// TODO: yet we take more general type. Not quite sure it's Ok
upperBound.toIrType(session, declarationStorage)
}
is ConeCapturedType -> TODO()
}
}
fun ConeKotlinTypeProjection.toIrTypeArgument(session: FirSession, declarationStorage: Fir2IrDeclarationStorage): IrTypeArgument {
return when (this) {
ConeStarProjection -> IrStarProjectionImpl
is ConeKotlinTypeProjectionIn -> {
val irType = this.type.toIrType(session, declarationStorage)
makeTypeProjection(irType, Variance.IN_VARIANCE)
}
is ConeKotlinTypeProjectionOut -> {
val irType = this.type.toIrType(session, declarationStorage)
makeTypeProjection(irType, Variance.OUT_VARIANCE)
}
is ConeKotlinType -> {
val irType = toIrType(session, declarationStorage)
makeTypeProjection(irType, Variance.INVARIANT)
}
}
}
fun ConeClassifierSymbol.toIrSymbol(session: FirSession, declarationStorage: Fir2IrDeclarationStorage): IrClassifierSymbol {
return when (this) {
is FirTypeParameterSymbol -> {
toTypeParameterSymbol(declarationStorage)
}
is LibraryTypeParameterSymbol -> {
toTypeParameterSymbol(declarationStorage)
}
is FirTypeAliasSymbol -> {
val typeAlias = fir
val coneClassLikeType = (typeAlias.expandedTypeRef as FirResolvedTypeRef).type as ConeClassLikeType
coneClassLikeType.lookupTag.toSymbol(session)!!.toIrSymbol(session, declarationStorage)
}
is FirClassSymbol -> {
toClassSymbol(declarationStorage)
}
else -> throw AssertionError("Should not be here: $this")
}
}
fun FirReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? {
if (this is FirNamedReference) {
return toSymbol(declarationStorage)
}
return null
}
fun FirNamedReference.toSymbol(declarationStorage: Fir2IrDeclarationStorage): IrSymbol? {
if (this is FirResolvedCallableReference) {
when (val callableSymbol = this.callableSymbol) {
is FirFunctionSymbol -> return callableSymbol.toFunctionSymbol(declarationStorage)
is FirPropertySymbol -> return callableSymbol.toPropertySymbol(declarationStorage)
is FirVariableSymbol -> return callableSymbol.toValueSymbol(declarationStorage)
}
}
return null
}
fun FirClassSymbol.toClassSymbol(declarationStorage: Fir2IrDeclarationStorage): IrClassSymbol {
return declarationStorage.getIrClassSymbol(this)
}
fun FirTypeParameterSymbol.toTypeParameterSymbol(declarationStorage: Fir2IrDeclarationStorage): IrTypeParameterSymbol {
return declarationStorage.getIrTypeParameterSymbol(this)
}
fun LibraryTypeParameterSymbol.toTypeParameterSymbol(declarationStorage: Fir2IrDeclarationStorage): IrTypeParameterSymbol {
return declarationStorage.getIrTypeParameterSymbol(this)
}
fun FirFunctionSymbol.toFunctionSymbol(declarationStorage: Fir2IrDeclarationStorage): IrFunctionSymbol {
return declarationStorage.getIrFunctionSymbol(this)
}
fun FirPropertySymbol.toPropertySymbol(declarationStorage: Fir2IrDeclarationStorage): IrPropertySymbol {
return declarationStorage.getIrPropertySymbol(this)
}
fun FirVariableSymbol.toValueSymbol(declarationStorage: Fir2IrDeclarationStorage): IrValueSymbol {
return declarationStorage.getIrValueSymbol(this)
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.backend
enum class FakeOverrideMode {
// No fake overrides are generated
NONE,
// Only fake overrides with substituted signatures are generated
SUBSTITUTION,
// All fake overrides are generated, including trivial ones, explicitly declared function is specified as overridden one
NORMAL,
// All fake overrides are generated, function of direct base class (possibly also fake override) is specified as overridden one
// TODO: not supported yet (to be discussed)
FULLY_COMPATIBLE
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.backend
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirVariable
import org.jetbrains.kotlin.ir.declarations.*
class Fir2IrCallableCache {
private val parameterCache = mutableMapOf<FirValueParameter, IrValueParameter>()
private val variableCache = mutableMapOf<FirVariable, IrVariable>()
private val localClassCache = mutableMapOf<FirClass, IrClass>()
private val localFunctionCache = mutableMapOf<FirFunction, IrSimpleFunction>()
fun getParameter(parameter: FirValueParameter): IrValueParameter? = parameterCache[parameter]
fun putParameter(firParameter: FirValueParameter, irParameter: IrValueParameter) {
parameterCache[firParameter] = irParameter
}
fun getVariable(variable: FirVariable): IrVariable? = variableCache[variable]
fun putVariable(firVariable: FirVariable, irVariable: IrVariable) {
variableCache[firVariable] = irVariable
}
fun getLocalClass(localClass: FirClass): IrClass? = localClassCache[localClass]
fun putLocalClass(localClass: FirClass, irClass: IrClass) {
require(localClass !is FirRegularClass || localClass.visibility == Visibilities.LOCAL)
localClassCache[localClass] = irClass
}
fun getLocalFunction(localFunction: FirFunction): IrSimpleFunction? = localFunctionCache[localFunction]
fun putLocalFunction(localFunction: FirFunction, irFunction: IrSimpleFunction) {
require(localFunction !is FirNamedFunction || localFunction.visibility == Visibilities.LOCAL)
localFunctionCache[localFunction] = irFunction
}
fun clear() {
parameterCache.clear()
variableCache.clear()
localClassCache.clear()
localFunctionCache.clear()
}
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.backend
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.util.ConstantValueGenerator
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.TypeTranslator
object Fir2IrConverter {
fun createModuleFragment(
session: FirSession,
firFiles: List<FirFile>,
languageVersionSettings: LanguageVersionSettings,
fakeOverrideMode: FakeOverrideMode = FakeOverrideMode.NORMAL
): IrModuleFragment {
val moduleDescriptor = FirModuleDescriptor(session)
val symbolTable = SymbolTable()
val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable)
val typeTranslator = TypeTranslator(symbolTable, languageVersionSettings, moduleDescriptor.builtIns)
constantValueGenerator.typeTranslator = typeTranslator
typeTranslator.constantValueGenerator = constantValueGenerator
val builtIns = IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable)
val fir2irTransformer = Fir2IrVisitor(session, moduleDescriptor, symbolTable, builtIns, fakeOverrideMode)
val irFiles = mutableListOf<IrFile>()
for (firFile in firFiles) {
irFiles += firFile.accept(fir2irTransformer, null) as IrFile
}
val irModuleFragment = IrModuleFragmentImpl(moduleDescriptor, builtIns, irFiles)
generateUnboundSymbolsAsDependencies(irModuleFragment, symbolTable, builtIns)
return irModuleFragment
}
private fun generateUnboundSymbolsAsDependencies(
irModule: IrModuleFragment,
symbolTable: SymbolTable,
builtIns: IrBuiltIns
) {
ExternalDependenciesGenerator(irModule.descriptor, symbolTable, builtIns).generateUnboundSymbolsAsDependencies()
}
}
@@ -0,0 +1,474 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.backend
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.descriptors.FirPackageFragmentDescriptor
import org.jetbrains.kotlin.fir.expressions.FirVariable
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.fir.service
import org.jetbrains.kotlin.fir.symbols.LibraryTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.types.Variance
class Fir2IrDeclarationStorage(
private val session: FirSession,
private val irSymbolTable: SymbolTable,
private val moduleDescriptor: FirModuleDescriptor
) {
private val firSymbolProvider = session.service<FirSymbolProvider>()
private val fragmentCache = mutableMapOf<FqName, IrExternalPackageFragment>()
private val classCache = mutableMapOf<FirRegularClass, IrClass>()
private val typeParameterCache = mutableMapOf<FirTypeParameter, IrTypeParameter>()
private val libraryTypeParameterCache = mutableMapOf<LibraryTypeParameterSymbol, IrTypeParameter>()
private val functionCache = mutableMapOf<FirNamedFunction, IrSimpleFunction>()
private val constructorCache = mutableMapOf<FirConstructor, IrConstructor>()
private val propertyCache = mutableMapOf<FirProperty, IrProperty>()
private val localStorage = Fir2IrLocalStorage()
fun enterScope(descriptor: DeclarationDescriptor) {
irSymbolTable.enterScope(descriptor)
if (descriptor is WrappedSimpleFunctionDescriptor ||
descriptor is WrappedClassConstructorDescriptor ||
descriptor is WrappedPropertyDescriptor
) {
localStorage.enterCallable()
}
}
fun leaveScope(descriptor: DeclarationDescriptor) {
if (descriptor is WrappedSimpleFunctionDescriptor ||
descriptor is WrappedClassConstructorDescriptor ||
descriptor is WrappedPropertyDescriptor
) {
localStorage.leaveCallable()
}
irSymbolTable.leaveScope(descriptor)
}
private fun getIrExternalPackageFragment(fqName: FqName): IrExternalPackageFragment {
return fragmentCache.getOrPut(fqName) {
// TODO: module descriptor is wrong here
return irSymbolTable.declareExternalPackageFragment(FirPackageFragmentDescriptor(fqName, moduleDescriptor))
}
}
private fun IrClass.declareThisReceiver() {
enterScope(descriptor)
val thisOrigin = IrDeclarationOrigin.INSTANCE_RECEIVER
val thisType = IrSimpleTypeImpl(symbol, false, emptyList(), emptyList())
val parent = this
thisReceiver = irSymbolTable.declareValueParameter(
startOffset, endOffset, thisOrigin, WrappedValueParameterDescriptor(), thisType
) { symbol ->
IrValueParameterImpl(
startOffset, endOffset, thisOrigin, symbol,
Name.special("<this>"), -1, thisType,
varargElementType = null, isCrossinline = false, isNoinline = false
).apply { this.parent = parent }
}
leaveScope(descriptor)
}
fun getIrClass(regularClass: FirRegularClass, setParent: Boolean = true): IrClass {
fun create(): IrClass {
val descriptor = WrappedClassDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val modality = regularClass.modality!!
return regularClass.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality) { symbol ->
IrClassImpl(
startOffset, endOffset, origin, symbol,
regularClass.name, regularClass.classKind,
regularClass.visibility, modality,
regularClass.isCompanion, regularClass.isInner,
regularClass.isData, false, regularClass.isInline
).apply {
descriptor.bind(this)
if (setParent) {
val classId = regularClass.classId
val parentId = classId.outerClassId
if (parentId != null) {
val parentFirSymbol = firSymbolProvider.getClassLikeSymbolByFqName(parentId)
if (parentFirSymbol is FirClassSymbol) {
val parentIrSymbol = getIrClassSymbol(parentFirSymbol)
parent = parentIrSymbol.owner
}
} else {
val packageFqName = classId.packageFqName
parent = getIrExternalPackageFragment(packageFqName)
}
}
declareThisReceiver()
}
}
}
}
if (regularClass.visibility == Visibilities.LOCAL) {
val cached = localStorage.getLocalClass(regularClass)
if (cached != null) return cached
val created = create()
localStorage.putLocalClass(regularClass, created)
return created
}
return classCache.getOrPut(regularClass, ::create)
}
fun getIrAnonymousObject(anonymousObject: FirAnonymousObject): IrClass {
val descriptor = WrappedClassDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val modality = Modality.FINAL
return anonymousObject.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareClass(startOffset, endOffset, origin, descriptor, modality) { symbol ->
IrClassImpl(
startOffset, endOffset, origin, symbol,
Name.special("<no name provided>"), anonymousObject.classKind,
Visibilities.LOCAL, modality,
isCompanion = false, isInner = false, isData = false, isExternal = false, isInline = false
).apply {
descriptor.bind(this)
declareThisReceiver()
}
}
}
}
fun getIrTypeParameter(typeParameter: FirTypeParameter, index: Int = 0): IrTypeParameter {
return typeParameterCache.getOrPut(typeParameter) {
val descriptor = WrappedTypeParameterDescriptor()
val origin = IrDeclarationOrigin.DEFINED
typeParameter.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareGlobalTypeParameter(startOffset, endOffset, origin, descriptor) { symbol ->
IrTypeParameterImpl(
startOffset, endOffset, origin, symbol,
typeParameter.name, index,
typeParameter.isReified,
typeParameter.variance
).apply {
descriptor.bind(this)
}
}
}
}
}
private fun IrDeclaration.setParentByOwnFir(firMember: FirCallableMemberDeclaration) {
val firBasedSymbol = firMember.symbol
val callableId = firBasedSymbol.callableId
val parentClassId = callableId.classId
if (parentClassId != null) {
val parentFirSymbol = firSymbolProvider.getClassLikeSymbolByFqName(parentClassId)
if (parentFirSymbol is FirClassSymbol) {
val parentIrSymbol = getIrClassSymbol(parentFirSymbol)
val parentIrClass = parentIrSymbol.owner
parent = parentIrClass
// TODO: parentIrClass.declarations += this (probably needed for external stuff)
}
} else {
val packageFqName = callableId.packageName
val parentIrPackageFragment = getIrExternalPackageFragment(packageFqName)
parent = parentIrPackageFragment
parentIrPackageFragment.declarations += this
}
}
fun <T : IrFunction> T.declareParameters(function: FirFunction) {
val parent = this
for ((index, valueParameter) in function.valueParameters.withIndex()) {
valueParameters += createAndSaveIrParameter(valueParameter, index).apply { this.parent = parent }
}
}
private fun <T : IrFunction> T.bindAndDeclareParameters(
function: FirFunction,
descriptor: WrappedCallableDescriptor<T>,
setParent: Boolean,
shouldLeaveScope: Boolean
): T {
descriptor.bind(this)
if (setParent) {
setParentByOwnFir(function as FirCallableMemberDeclaration)
}
enterScope(descriptor)
declareParameters(function)
if (shouldLeaveScope) {
leaveScope(descriptor)
}
return this
}
private fun <T : IrFunction> T.enterLocalScope(function: FirFunction): T {
enterScope(descriptor)
for ((firParameter, irParameter) in function.valueParameters.zip(valueParameters)) {
irSymbolTable.introduceValueParameter(irParameter)
localStorage.putParameter(firParameter, irParameter)
}
return this
}
fun getIrFunction(
function: FirNamedFunction,
setParent: Boolean = true,
shouldLeaveScope: Boolean = false,
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
): IrSimpleFunction {
fun create(): IrSimpleFunction {
val descriptor = WrappedSimpleFunctionDescriptor()
return function.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareSimpleFunction(startOffset, endOffset, origin, descriptor) { symbol ->
IrFunctionImpl(
startOffset, endOffset, origin, symbol,
function.name, function.visibility, function.modality!!,
function.returnTypeRef.toIrType(session, this),
function.isInline, function.isExternal,
function.isTailRec, function.isSuspend
)
}
}.bindAndDeclareParameters(function, descriptor, setParent, shouldLeaveScope)
}
if (function.visibility == Visibilities.LOCAL) {
val cached = localStorage.getLocalFunction(function)
if (cached != null) {
return if (shouldLeaveScope) cached else cached.enterLocalScope(function)
}
val created = create()
localStorage.putLocalFunction(function, created)
return created
}
val cached = functionCache[function]
if (cached != null) {
return if (shouldLeaveScope) cached else cached.enterLocalScope(function)
}
val created = create()
functionCache[function] = created
return created
}
fun getIrLocalFunction(function: FirAnonymousFunction): IrSimpleFunction {
val descriptor = WrappedSimpleFunctionDescriptor()
val isLambda = function.psi is KtFunctionLiteral
val origin = if (isLambda) IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA else IrDeclarationOrigin.DEFINED
return function.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareSimpleFunction(startOffset, endOffset, origin, descriptor) { symbol ->
IrFunctionImpl(
startOffset, endOffset, origin, symbol,
if (isLambda) Name.special("<anonymous>") else Name.special("<no name provided>"),
Visibilities.LOCAL, Modality.FINAL,
function.returnTypeRef.toIrType(session, this),
isInline = false, isExternal = false, isTailrec = false,
// TODO: suspend lambda
isSuspend = false
)
}.bindAndDeclareParameters(function, descriptor, setParent = false, shouldLeaveScope = false)
}
}
fun getIrConstructor(constructor: FirConstructor, setParent: Boolean = true, shouldLeaveScope: Boolean = false): IrConstructor {
return constructorCache.getOrPut(constructor) {
val descriptor = WrappedClassConstructorDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val isPrimary = constructor.isPrimary
return constructor.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareConstructor(startOffset, endOffset, origin, descriptor) { symbol ->
IrConstructorImpl(
startOffset, endOffset, origin, symbol,
constructor.name, constructor.visibility,
constructor.returnTypeRef.toIrType(session, this),
false, false, isPrimary
).bindAndDeclareParameters(constructor, descriptor, setParent, shouldLeaveScope)
}
}
}
}
fun getIrProperty(property: FirProperty, setParent: Boolean = true): IrProperty {
return propertyCache.getOrPut(property) {
val descriptor = WrappedPropertyDescriptor()
val origin = IrDeclarationOrigin.DEFINED
property.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareProperty(
startOffset, endOffset,
origin, descriptor, property.delegate != null
) { symbol ->
IrPropertyImpl(
startOffset, endOffset, origin, symbol,
property.name, property.visibility, property.modality!!,
property.isVar, property.isConst, property.isLateInit,
property.delegate != null,
// TODO
isExternal = false
).apply {
descriptor.bind(this)
if (setParent) {
setParentByOwnFir(property)
}
}
}
}
}
}
private fun createAndSaveIrParameter(valueParameter: FirValueParameter, index: Int = -1): IrValueParameter {
val descriptor = WrappedValueParameterDescriptor()
val origin = IrDeclarationOrigin.DEFINED
val type = valueParameter.returnTypeRef.toIrType(session, this)
val irParameter = valueParameter.convertWithOffsets { startOffset, endOffset ->
irSymbolTable.declareValueParameter(
startOffset, endOffset, origin, descriptor, type
) { symbol ->
IrValueParameterImpl(
startOffset, endOffset, origin, symbol,
valueParameter.name, index, type,
null, valueParameter.isCrossinline, valueParameter.isNoinline
).apply {
descriptor.bind(this)
}
}
}
localStorage.putParameter(valueParameter, irParameter)
return irParameter
}
private var lastTemporaryIndex: Int = 0
private fun nextTemporaryIndex(): Int = lastTemporaryIndex++
private fun getNameForTemporary(nameHint: String?): String {
val index = nextTemporaryIndex()
return if (nameHint != null) "tmp${index}_$nameHint" else "tmp$index"
}
private fun declareIrVariable(
startOffset: Int, endOffset: Int,
origin: IrDeclarationOrigin, name: Name, type: IrType,
isVar: Boolean, isConst: Boolean, isLateinit: Boolean
): IrVariable {
val descriptor = WrappedVariableDescriptor()
return irSymbolTable.declareVariable(startOffset, endOffset, origin, descriptor, type) { symbol ->
IrVariableImpl(
startOffset, endOffset, origin, symbol, name, type,
isVar, isConst, isLateinit
).apply {
descriptor.bind(this)
}
}
}
fun createAndSaveIrVariable(variable: FirVariable): IrVariable {
val type = variable.returnTypeRef.toIrType(session, this)
val irVariable = variable.convertWithOffsets { startOffset, endOffset ->
declareIrVariable(
startOffset, endOffset, IrDeclarationOrigin.DEFINED,
variable.name, type, variable.isVar, isConst = false, isLateinit = false
)
}
localStorage.putVariable(variable, irVariable)
return irVariable
}
fun declareTemporaryVariable(base: IrExpression, nameHint: String? = null): IrVariable {
return declareIrVariable(
base.startOffset, base.endOffset, IrDeclarationOrigin.IR_TEMPORARY_VARIABLE,
Name.identifier(getNameForTemporary(nameHint)), base.type,
isVar = false, isConst = false, isLateinit = false
)
}
fun getIrClassSymbol(firClassSymbol: FirClassSymbol): IrClassSymbol {
val irClass = getIrClass(firClassSymbol.fir)
return irSymbolTable.referenceClass(irClass.descriptor)
}
fun getIrTypeParameterSymbol(firTypeParameterSymbol: FirTypeParameterSymbol): IrTypeParameterSymbol {
val irTypeParameter = getIrTypeParameter(firTypeParameterSymbol.fir)
return irSymbolTable.referenceTypeParameter(irTypeParameter.descriptor)
}
fun getIrTypeParameterSymbol(typeParameterSymbol: LibraryTypeParameterSymbol): IrTypeParameterSymbol {
val irTypeParameter = libraryTypeParameterCache.getOrPut(typeParameterSymbol) {
val descriptor = WrappedTypeParameterDescriptor()
val origin = IrDeclarationOrigin.DEFINED
irSymbolTable.declareGlobalTypeParameter(-1, -1, origin, descriptor) { symbol ->
IrTypeParameterImpl(
-1, -1, origin, symbol,
typeParameterSymbol.name, -1,
false,
Variance.INVARIANT
).apply {
descriptor.bind(this)
}
}
}
return irSymbolTable.referenceTypeParameter(irTypeParameter.descriptor)
}
fun getIrFunctionSymbol(firFunctionSymbol: FirFunctionSymbol): IrFunctionSymbol {
return when (val firDeclaration = firFunctionSymbol.fir) {
is FirNamedFunction -> {
val irDeclaration = getIrFunction(firDeclaration, shouldLeaveScope = true)
irSymbolTable.referenceSimpleFunction(irDeclaration.descriptor)
}
is FirConstructor -> {
val irDeclaration = getIrConstructor(firDeclaration, shouldLeaveScope = true)
irSymbolTable.referenceConstructor(irDeclaration.descriptor)
}
else -> throw AssertionError("Should not be here")
}
}
fun getIrPropertySymbol(firPropertySymbol: FirPropertySymbol): IrPropertySymbol {
val irProperty = getIrProperty(firPropertySymbol.fir as FirProperty)
return irSymbolTable.referenceProperty(irProperty.descriptor)
}
private fun getIrVariableSymbol(firVariable: FirVariable): IrVariableSymbol {
val irDeclaration = localStorage.getVariable(firVariable)
?: throw IllegalArgumentException("Cannot find variable ${firVariable.render()} in local storage")
return irSymbolTable.referenceVariable(irDeclaration.descriptor)
}
fun getIrValueSymbol(firVariableSymbol: FirVariableSymbol): IrValueSymbol {
return when (val firDeclaration = firVariableSymbol.fir) {
is FirValueParameter -> {
val irDeclaration = localStorage.getParameter(firDeclaration)
// catch parameter is FirValueParameter in FIR but IrVariable in IR
?: return getIrVariableSymbol(firDeclaration)
irSymbolTable.referenceValueParameter(irDeclaration.descriptor)
}
is FirVariable -> {
getIrVariableSymbol(firDeclaration)
}
else -> throw AssertionError("Should not be here")
}
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.backend
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirVariable
import org.jetbrains.kotlin.ir.declarations.*
class Fir2IrLocalStorage {
private val cacheStack = mutableListOf<Fir2IrCallableCache>()
fun enterCallable() {
cacheStack += Fir2IrCallableCache()
}
fun leaveCallable() {
cacheStack.last().clear()
cacheStack.removeAt(cacheStack.size - 1)
}
fun getParameter(parameter: FirValueParameter): IrValueParameter? {
for (cache in cacheStack.asReversed()) {
val local = cache.getParameter(parameter)
if (local != null) return local
}
return null
}
fun getVariable(variable: FirVariable): IrVariable? {
for (cache in cacheStack.asReversed()) {
val local = cache.getVariable(variable)
if (local != null) return local
}
return null
}
fun getLocalClass(localClass: FirClass): IrClass? {
for (cache in cacheStack.asReversed()) {
val local = cache.getLocalClass(localClass)
if (local != null) return local
}
return null
}
fun getLocalFunction(localFunction: FirFunction): IrSimpleFunction? {
for (cache in cacheStack.asReversed()) {
val local = cache.getLocalFunction(localFunction)
if (local != null) return local
}
return null
}
fun putParameter(firParameter: FirValueParameter, irParameter: IrValueParameter) {
cacheStack.last().putParameter(firParameter, irParameter)
}
fun putVariable(firVariable: FirVariable, irVariable: IrVariable) {
cacheStack.last().putVariable(firVariable, irVariable)
}
fun putLocalClass(firClass: FirClass, irClass: IrClass) {
cacheStack.last().putLocalClass(firClass, irClass)
}
fun putLocalFunction(firFunction: FirFunction, irFunction: IrSimpleFunction) {
cacheStack.last().putLocalFunction(firFunction, irFunction)
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.descriptors
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorVisitor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class FirModuleDescriptor(val session: FirSession) : ModuleDescriptor {
override val builtIns: KotlinBuiltIns
get() = DefaultBuiltIns.Instance
override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean {
return false
}
override fun getPackage(fqName: FqName): PackageViewDescriptor {
val symbolProvider = FirSymbolProvider.getInstance(session)
if (symbolProvider.getPackage(fqName) != null) {
return FirPackageViewDescriptor(fqName, this)
}
TODO("Missing package reporting")
}
override fun getSubPackagesOf(fqName: FqName, nameFilter: (Name) -> Boolean): Collection<FqName> {
TODO("not implemented")
}
override val allDependencyModules: List<ModuleDescriptor>
get() = TODO("not implemented")
override val expectedByModules: List<ModuleDescriptor>
get() = TODO("not implemented")
override fun <T> getCapability(capability: ModuleDescriptor.Capability<T>): T? {
return null
}
override val isValid: Boolean
get() = true
override fun assertValid() {
}
override fun getOriginal(): DeclarationDescriptor {
return this
}
override fun getName(): Name {
return Name.identifier("module for FIR session")
}
override val stableName: Name?
get() = name
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
TODO("not implemented")
}
override val annotations: Annotations
get() = TODO("not implemented")
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.descriptors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
class FirPackageFragmentDescriptor(override val fqName: FqName, val moduleDescriptor: ModuleDescriptor) : PackageFragmentDescriptor {
override fun getContainingDeclaration(): ModuleDescriptor {
return moduleDescriptor
}
override fun getMemberScope(): MemberScope {
TODO("not implemented")
}
override fun getOriginal(): DeclarationDescriptorWithSource {
return this
}
override fun getName(): Name {
return fqName.shortName()
}
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R {
TODO("not implemented")
}
override fun getSource(): SourceElement {
TODO("not implemented")
}
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
TODO("not implemented")
}
override val annotations: Annotations
get() = TODO("not implemented")
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.descriptors
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope
class FirPackageViewDescriptor(override val fqName: FqName, val moduleDescriptor: ModuleDescriptor) : PackageViewDescriptor {
override fun getContainingDeclaration(): PackageViewDescriptor? {
TODO("not implemented")
}
override val memberScope: MemberScope
get() = TODO("not implemented")
override val module: ModuleDescriptor
get() = moduleDescriptor
override val fragments: List<PackageFragmentDescriptor>
get() = listOf(FirPackageFragmentDescriptor(fqName, moduleDescriptor))
override fun getOriginal(): DeclarationDescriptor {
TODO("not implemented")
}
override fun getName(): Name {
TODO("not implemented")
}
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D): R {
TODO("not implemented")
}
override fun acceptVoid(visitor: DeclarationDescriptorVisitor<Void, Void>?) {
TODO("not implemented")
}
override val annotations: Annotations
get() = TODO("not implemented")
}
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.GlobalSearchScope
import junit.framework.TestCase
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.fir.backend.Fir2IrConverter
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.resolve.FirProvider
import org.jetbrains.kotlin.fir.resolve.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.resolve.transformers.FirTotalResolveTransformer
import org.jetbrains.kotlin.ir.AbstractIrTextTestCase
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import java.io.File
abstract class AbstractFir2IrTextTest : AbstractIrTextTestCase() {
private fun prepareProjectExtensions(project: Project) {
Extensions.getArea(project)
.getExtensionPoint(PsiElementFinder.EP_NAME)
.unregisterExtension(JavaElementFinder::class.java)
}
override fun doTest(filePath: String?) {
if (filePath != null) {
val originalTextPath = filePath.replace(".kt", ".txt")
val firTextPath = filePath.replace(".kt", ".fir.txt")
val originalText = File(originalTextPath)
val firText = File(firTextPath)
if (originalText.exists() && firText.exists()) {
val originalLines = originalText.readLines()
val firLines = firText.readLines()
TestCase.assertFalse(
"Dumps via FIR & via old FE are the same. Please delete .fir.txt dump and add // FIR_IDENTICAL to test source",
firLines.withIndex().all { (index, line) ->
val trimmed = line.trim()
val originalTrimmed = originalLines.getOrNull(index)?.trim()
trimmed.isEmpty() && originalTrimmed?.isEmpty() != false || trimmed == originalTrimmed
} && originalLines.withIndex().all { (index, line) ->
index < firLines.size || line.trim().isEmpty()
}
)
}
}
super.doTest(filePath)
}
override fun getExpectedTextFileName(testFile: TestFile, name: String): String {
// NB: replace with if (true) to make test against old FE results
if ("// FIR_IDENTICAL" in testFile.content.split("\n")) {
return super.getExpectedTextFileName(testFile, name)
}
return name.replace(".txt", ".fir.txt").replace(".kt", ".fir.txt")
}
override fun generateIrModule(ignoreErrors: Boolean): IrModuleFragment {
val psiFiles = myFiles.psiFiles
val project = psiFiles.first().project
prepareProjectExtensions(project)
val scope = GlobalSearchScope.filesScope(project, psiFiles.map { it.virtualFile })
.uniteWith(TopDownAnalyzerFacadeForJVM.AllJavaSourcesInProjectScope(project))
val session = createSession(myEnvironment, scope)
val builder = RawFirBuilder(session, stubMode = false)
val resolveTransformer = FirTotalResolveTransformer()
val firFiles = psiFiles.map {
val firFile = builder.buildFirFile(it)
(session.service<FirProvider>() as FirProviderImpl).recordFile(firFile)
firFile
}.also {
try {
resolveTransformer.processFiles(it)
} catch (e: Exception) {
throw e
}
}
return Fir2IrConverter.createModuleFragment(session, firFiles, myEnvironment.configuration.languageVersionSettings)
}
}
File diff suppressed because it is too large Load Diff
@@ -90,7 +90,7 @@ class FirClassSubstitutionScope(
override fun processFunctionsByName(name: Name, processor: (ConeFunctionSymbol) -> ProcessorAction): ProcessorAction {
useSiteScope.processFunctionsByName(name) process@{ original ->
val function = fakeOverrides.getOrPut(original) { createFakeOverride(original, name) }
val function = fakeOverrides.getOrPut(original) { createFakeOverride(original) }
processor(function as ConeFunctionSymbol)
}
@@ -104,10 +104,7 @@ class FirClassSubstitutionScope(
private val typeCalculator by lazy { ReturnTypeCalculatorWithJump(session) }
private fun createFakeOverride(
original: ConeFunctionSymbol,
name: Name
): FirFunctionSymbol {
private fun createFakeOverride(original: ConeFunctionSymbol): FirFunctionSymbol {
val member = original.firUnsafe<FirFunction>()
if (member is FirConstructor) return original as FirFunctionSymbol // TODO: substitution for constructors
@@ -123,32 +120,45 @@ class FirClassSubstitutionScope(
it.returnTypeRef.coneTypeUnsafe().substitute()
}
val symbol = FirFunctionSymbol(original.callableId, true)
with(member) {
// TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl
// As second alternative, we can invent some light-weight kind of FirRegularClass
FirMemberFunctionImpl(
this@FirClassSubstitutionScope.session,
psi,
symbol,
name,
member.receiverTypeRef?.withReplacedConeType(this@FirClassSubstitutionScope.session, newReceiverType),
member.returnTypeRef.withReplacedConeType(this@FirClassSubstitutionScope.session, newReturnType)
).apply {
status = member.status as FirDeclarationStatusImpl
valueParameters += member.valueParameters.zip(newParameterTypes) { valueParameter, newType ->
with(valueParameter) {
FirValueParameterImpl(
this@FirClassSubstitutionScope.session, psi,
name, this.returnTypeRef.withReplacedConeType(this@FirClassSubstitutionScope.session, newType),
defaultValue, isCrossinline, isNoinline, isVararg,
FirVariableSymbol(valueParameter.symbol.callableId)
)
return createFakeOverride(session, member, original as FirFunctionSymbol, newReceiverType, newReturnType, newParameterTypes)
}
companion object {
fun createFakeOverride(
session: FirSession,
baseFunction: FirNamedFunction,
baseSymbol: FirFunctionSymbol,
newReceiverType: ConeKotlinType? = null,
newReturnType: ConeKotlinType? = null,
newParameterTypes: List<ConeKotlinType?>? = null
): FirFunctionSymbol {
val symbol = FirFunctionSymbol(baseSymbol.callableId, true, baseSymbol)
with(baseFunction) {
// TODO: consider using here some light-weight functions instead of pseudo-real FirMemberFunctionImpl
// As second alternative, we can invent some light-weight kind of FirRegularClass
FirMemberFunctionImpl(
session,
psi, symbol, name,
baseFunction.receiverTypeRef?.withReplacedConeType(session, newReceiverType),
baseFunction.returnTypeRef.withReplacedConeType(session, newReturnType)
).apply {
status = baseFunction.status as FirDeclarationStatusImpl
valueParameters += baseFunction.valueParameters.zip(
newParameterTypes ?: List(baseFunction.valueParameters.size) { null }
) { valueParameter, newType ->
with(valueParameter) {
FirValueParameterImpl(
session, psi,
name, this.returnTypeRef.withReplacedConeType(session, newType),
defaultValue, isCrossinline, isNoinline, isVararg,
FirVariableSymbol(valueParameter.symbol.callableId)
)
}
}
}
}
return symbol
}
return symbol
}
}
@@ -41,5 +41,7 @@ enum class FirOperation(val operator: String = "???") {
val BOOLEANS: Set<FirOperation> = EnumSet.of(
EQ, NOT_EQ, IDENTITY, NOT_IDENTITY, LT, GT, LT_EQ, GT_EQ, IS, NOT_IS
)
val COMPARISONS: Set<FirOperation> = EnumSet.of(LT, GT, LT_EQ, GT_EQ)
}
}
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
class FirFunctionSymbol(
override val callableId: CallableId,
val isFakeOverride: Boolean = false
val isFakeOverride: Boolean = false,
// Actual for fake override only
val overriddenSymbol: FirFunctionSymbol? = null
) : ConeFunctionSymbol, FirCallableSymbol() {
override val parameters: List<ConeKotlinType>
get() = emptyList()
@@ -57,3 +57,9 @@ class FirImplicitBooleanTypeRef(
session: FirSession,
psi: PsiElement?
) : FirImplicitBuiltinTypeRef(session, psi, StandardClassIds.Boolean)
class FirImplicitNothingTypeRef(
session: FirSession,
psi: PsiElement?
) : FirImplicitBuiltinTypeRef(session, psi, StandardClassIds.Nothing)