[FIR] Microoptimizations and clearing

This commit is contained in:
Ivan Kochurkin
2022-04-28 02:01:28 +03:00
parent ad7c213ab2
commit e69250a9fe
12 changed files with 61 additions and 157 deletions
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.utils.addToStdlib.filterIsInstanceWithChecker
object FirImportsChecker : FirFileChecker() { object FirImportsChecker : FirFileChecker() {
override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(declaration: FirFile, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -97,8 +98,7 @@ object FirImportsChecker : FirFileChecker() {
private fun checkConflictingImports(imports: List<FirImport>, context: CheckerContext, reporter: DiagnosticReporter) { private fun checkConflictingImports(imports: List<FirImport>, context: CheckerContext, reporter: DiagnosticReporter) {
val interestingImports = imports val interestingImports = imports
.filterIsInstance<FirResolvedImport>() .filterIsInstanceWithChecker<FirResolvedImport> { import ->
.filter { import ->
!import.isAllUnder && !import.isAllUnder &&
import.importedName?.identifierOrNullIfSpecial?.isNotEmpty() == true && import.importedName?.identifierOrNullIfSpecial?.isNotEmpty() == true &&
import.resolvesToClass(context) import.resolvesToClass(context)
@@ -12,9 +12,7 @@ import org.jetbrains.kotlin.fir.deserialization.AbstractAnnotationDeserializer
import org.jetbrains.kotlin.fir.expressions.FirAnnotation import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.MemberSignature
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.* import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
@@ -248,27 +246,6 @@ class JvmBinaryAnnotationDeserializer(
} }
} }
private fun getPropertySignature(
proto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable,
field: Boolean = false,
synthetic: Boolean = false,
requireHasFieldFlagForField: Boolean = true
): MemberSignature? {
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return null
if (field) {
val fieldSignature =
JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable, requireHasFieldFlagForField) ?: return null
return MemberSignature.fromJvmMemberSignature(fieldSignature)
} else if (synthetic && signature.hasSyntheticMethod()) {
return MemberSignature.fromMethod(nameResolver, signature.syntheticMethod)
}
return null
}
private fun findJvmBinaryClassAndLoadMemberAnnotations( private fun findJvmBinaryClassAndLoadMemberAnnotations(
memberSignature: MemberSignature, searchInDefaultImpls: Boolean = false memberSignature: MemberSignature, searchInDefaultImpls: Boolean = false
): List<FirAnnotation> { ): List<FirAnnotation> {
@@ -171,7 +171,7 @@ class FirSignatureEnhancement(
}.symbol }.symbol
} }
else -> { else -> {
if (original is FirPropertySymbol || original is FirSyntheticPropertySymbol) return original if (original is FirPropertySymbol) return original
error("Can't make enhancement for $original: `${firElement.render()}`") error("Can't make enhancement for $original: `${firElement.render()}`")
} }
} }
@@ -6,30 +6,13 @@
package org.jetbrains.kotlin.fir.java.enhancement package org.jetbrains.kotlin.fir.java.enhancement
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.collectEnumEntries
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildConstExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildPropertyAccessExpression
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.declarations.FirJavaField
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassifierLookupTag
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.typeEnhancement.* import org.jetbrains.kotlin.load.java.typeEnhancement.*
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.ConstantValueKind
import org.jetbrains.kotlin.utils.extractRadix
internal fun ConeKotlinType.enhance(session: FirSession, qualifiers: IndexedJavaTypeQualifiers): ConeKotlinType? = internal fun ConeKotlinType.enhance(session: FirSession, qualifiers: IndexedJavaTypeQualifiers): ConeKotlinType? =
enhanceConeKotlinType(session, qualifiers, 0, mutableListOf<Int>().apply { computeSubtreeSizes(this) }) enhanceConeKotlinType(session, qualifiers, 0, mutableListOf<Int>().apply { computeSubtreeSizes(this) })
@@ -167,54 +150,3 @@ private fun ConeClassifierLookupTag.enhanceMutability(
return this return this
} }
internal fun ConeKotlinType.lexicalCastFrom(session: FirSession, value: String): FirExpression? {
val lookupTagBasedType = when (this) {
is ConeLookupTagBasedType -> this
is ConeFlexibleType -> return lowerBound.lexicalCastFrom(session, value)
else -> return null
}
val lookupTag = lookupTagBasedType.lookupTag
val firElement = lookupTag.toSymbol(session)?.fir
if (firElement is FirRegularClass && firElement.classKind == ClassKind.ENUM_CLASS) {
val name = Name.identifier(value)
val firEnumEntry = firElement.collectEnumEntries().find { it.name == name }
return if (firEnumEntry != null) buildPropertyAccessExpression {
calleeReference = buildResolvedNamedReference {
this.name = name
resolvedSymbol = firEnumEntry.symbol
}
} else if (firElement is FirJavaClass) {
val firStaticProperty = firElement.declarations.filterIsInstance<FirJavaField>().find {
it.isStatic && it.modality == Modality.FINAL && it.name == name
}
if (firStaticProperty != null) {
buildPropertyAccessExpression {
calleeReference = buildResolvedNamedReference {
this.name = name
resolvedSymbol = firStaticProperty.symbol
}
}
} else null
} else null
}
if (lookupTag !is ConeClassLikeLookupTag) return null
val classId = lookupTag.classId
if (classId.packageFqName != FqName("kotlin")) return null
val (number, radix) = extractRadix(value)
return when (classId.relativeClassName.asString()) {
"Boolean" -> buildConstExpression(null, ConstantValueKind.Boolean, value.toBoolean())
"Char" -> buildConstExpression(null, ConstantValueKind.Char, value.singleOrNull() ?: return null)
"Byte" -> buildConstExpression(null, ConstantValueKind.Byte, number.toByteOrNull(radix) ?: return null)
"Short" -> buildConstExpression(null, ConstantValueKind.Short, number.toShortOrNull(radix) ?: return null)
"Int" -> buildConstExpression(null, ConstantValueKind.Int, number.toIntOrNull(radix) ?: return null)
"Long" -> buildConstExpression(null, ConstantValueKind.Long, number.toLongOrNull(radix) ?: return null)
"Float" -> buildConstExpression(null, ConstantValueKind.Float, value.toFloatOrNull() ?: return null)
"Double" -> buildConstExpression(null, ConstantValueKind.Double, value.toDoubleOrNull() ?: return null)
"String" -> buildConstExpression(null, ConstantValueKind.String, value)
else -> null
}
}
@@ -220,11 +220,7 @@ class FirCallResolver(
origin = origin origin = origin
) )
towerResolver.reset() towerResolver.reset()
val result = if (collector != null) { val result = towerResolver.runResolver(info, resolutionContext, collector)
towerResolver.runResolver(info, resolutionContext, collector)
} else {
towerResolver.runResolver(info, resolutionContext)
}
val bestCandidates = result.bestCandidates() val bestCandidates = result.bestCandidates()
fun chooseMostSpecific(): Set<Candidate> { fun chooseMostSpecific(): Set<Candidate> {
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.types.model.TypeConstructorMarker
import org.jetbrains.kotlin.types.model.TypeVariableMarker import org.jetbrains.kotlin.types.model.TypeVariableMarker
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.filterIsInstanceWithChecker
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class ConstraintSystemCompleter(components: BodyResolveComponents, private val context: BodyResolveContext) { class ConstraintSystemCompleter(components: BodyResolveComponents, private val context: BodyResolveContext) {
@@ -92,9 +93,10 @@ class ConstraintSystemCompleter(components: BodyResolveComponents, private val c
break break
val postponedArgumentsWithRevisableType = postponedArguments val postponedArgumentsWithRevisableType = postponedArguments
.filterIsInstance<PostponedAtomWithRevisableExpectedType>() .filterIsInstanceWithChecker<PostponedAtomWithRevisableExpectedType> {
// NB: FE 1.0 does not perform this check // NB: FE 1.0 does not perform this check
.filter { it.revisedExpectedType == null } it.revisedExpectedType == null
}
val dependencyProvider = val dependencyProvider =
TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, topLevelType, this) TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, topLevelType, this)
@@ -170,6 +170,7 @@ class PostponedArgumentsAnalyzer(
returnArguments.forEach { c.addSubsystemFromExpression(it) } returnArguments.forEach { c.addSubsystemFromExpression(it) }
val checkerSink: CheckerSink = CheckerSinkImpl(candidate) val checkerSink: CheckerSink = CheckerSinkImpl(candidate)
val builder = c.getBuilder()
val lastExpression = lambda.atom.body?.statements?.lastOrNull() as? FirExpression val lastExpression = lambda.atom.body?.statements?.lastOrNull() as? FirExpression
var hasExpressionInReturnArguments = false var hasExpressionInReturnArguments = false
@@ -183,9 +184,9 @@ class PostponedArgumentsAnalyzer(
val lastExpressionCoercedToUnit = val lastExpressionCoercedToUnit =
it == lastExpression && expectedReturnType?.isUnitOrFlexibleUnit == true && !it.typeRef.coneType.isUnitOrFlexibleUnit it == lastExpression && expectedReturnType?.isUnitOrFlexibleUnit == true && !it.typeRef.coneType.isUnitOrFlexibleUnit
// No constraint for the last expression of lambda if it will be coerced to Unit. // No constraint for the last expression of lambda if it will be coerced to Unit.
if (!lastExpressionCoercedToUnit && !c.getBuilder().hasContradiction) { if (!lastExpressionCoercedToUnit && !builder.hasContradiction) {
candidate.resolveArgumentExpression( candidate.resolveArgumentExpression(
c.getBuilder(), builder,
it, it,
lambdaReturnType, lambdaReturnType,
lambda.atom.returnTypeRef, // TODO: proper ref lambda.atom.returnTypeRef, // TODO: proper ref
@@ -198,7 +199,7 @@ class PostponedArgumentsAnalyzer(
} }
if (!hasExpressionInReturnArguments && lambdaReturnType != null) { if (!hasExpressionInReturnArguments && lambdaReturnType != null) {
c.getBuilder().addSubtypeConstraint( builder.addSubtypeConstraint(
components.session.builtinTypes.unitType.type, components.session.builtinTypes.unitType.type,
lambdaReturnType, lambdaReturnType,
ConeLambdaArgumentConstraintPosition(lambda.atom) ConeLambdaArgumentConstraintPosition(lambda.atom)
@@ -209,20 +210,19 @@ class PostponedArgumentsAnalyzer(
lambda.returnStatements = returnArguments lambda.returnStatements = returnArguments
if (inferenceSession != null) { if (inferenceSession != null) {
val constraintSystemBuilder = c.getBuilder() val postponedVariables = inferenceSession.inferPostponedVariables(lambda, builder, completionMode)
val postponedVariables = inferenceSession.inferPostponedVariables(lambda, constraintSystemBuilder, completionMode)
if (postponedVariables == null) { if (postponedVariables == null) {
c.getBuilder().removePostponedVariables() builder.removePostponedVariables()
return return
} }
for ((constructor, resultType) in postponedVariables) { for ((constructor, resultType) in postponedVariables) {
val variableWithConstraints = constraintSystemBuilder.currentStorage().notFixedTypeVariables[constructor] ?: continue val variableWithConstraints = builder.currentStorage().notFixedTypeVariables[constructor] ?: continue
val variable = variableWithConstraints.typeVariable as ConeTypeVariable val variable = variableWithConstraints.typeVariable as ConeTypeVariable
c.getBuilder().unmarkPostponedVariable(variable) builder.unmarkPostponedVariable(variable)
c.getBuilder().addSubtypeConstraint(resultType, variable.defaultType(c), BuilderInferencePosition) builder.addSubtypeConstraint(resultType, variable.defaultType(c), BuilderInferencePosition)
} }
c.removePostponedTypeVariablesFromConstraints(postponedVariables.keys) c.removePostponedTypeVariablesFromConstraints(postponedVariables.keys)
@@ -548,15 +548,15 @@ class FirCallCompletionResultsWriterTransformer(
): List<ConeKotlinType> { ): List<ConeKotlinType> {
val declaration = candidate.symbol.fir as? FirCallableDeclaration ?: return emptyList() val declaration = candidate.symbol.fir as? FirCallableDeclaration ?: return emptyList()
return declaration.typeParameters.map { ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false) } return declaration.typeParameters.map {
.map { candidate.substitutor.substituteOrSelf(it) } val typeParameter = ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false)
.map { val substitution = candidate.substitutor.substituteOrSelf(typeParameter)
finalSubstitutor.substituteOrSelf(it).let { substitutedType -> finalSubstitutor.substituteOrSelf(substitution).let { substitutedType ->
typeApproximator.approximateToSuperType( typeApproximator.approximateToSuperType(
substitutedType, TypeApproximatorConfiguration.TypeArgumentApproximation, substitutedType, TypeApproximatorConfiguration.TypeArgumentApproximation,
) ?: substitutedType ) ?: substitutedType
}
} }
}
} }
override fun transformAnonymousFunctionExpression( override fun transformAnonymousFunctionExpression(
@@ -651,17 +651,16 @@ class FirCallCompletionResultsWriterTransformer(
expression.transform<FirElement, ExpectedArgumentType?>(this, finalType?.toExpectedType()) expression.transform<FirElement, ExpectedArgumentType?>(this, finalType?.toExpectedType())
} }
val resultFunction = result if (result.returnTypeRef.coneTypeSafe<ConeIntegerLiteralType>() != null) {
if (resultFunction.returnTypeRef.coneTypeSafe<ConeIntegerLiteralType>() != null) {
val lastExpressionType = val lastExpressionType =
(returnExpressionsOfAnonymousFunction.lastOrNull() as? FirExpression) (returnExpressionsOfAnonymousFunction.lastOrNull() as? FirExpression)
?.typeRef?.coneTypeSafe<ConeKotlinType>() ?.typeRef?.coneTypeSafe<ConeKotlinType>()
val newReturnTypeRef = resultFunction.returnTypeRef.withReplacedConeType(lastExpressionType) val newReturnTypeRef = result.returnTypeRef.withReplacedConeType(lastExpressionType)
resultFunction.replaceReturnTypeRef(newReturnTypeRef) result.replaceReturnTypeRef(newReturnTypeRef)
val resolvedTypeRef = val resolvedTypeRef =
resultFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) result.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true)
resultFunction.replaceTypeRef(resolvedTypeRef) result.replaceTypeRef(resolvedTypeRef)
session.lookupTracker?.let { session.lookupTracker?.let {
it.recordTypeResolveAsLookup(newReturnTypeRef, anonymousFunction.source, context.file.source) it.recordTypeResolveAsLookup(newReturnTypeRef, anonymousFunction.source, context.file.source)
it.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, context.file.source) it.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, context.file.source)
@@ -570,18 +570,16 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor
val returnType = val returnType =
dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(result) dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(result)
.firstNotNullOfOrNull { (it as? FirExpression)?.resultType?.coneTypeSafe() } .firstNotNullOfOrNull { (it as? FirExpression)?.resultType?.coneTypeSafe() }
val resolutionMode = if (returnType != null) {
if (returnType != null) { withExpectedType(returnType)
result.transformReturnTypeRef(transformer, withExpectedType(returnType))
} else { } else {
result.transformReturnTypeRef( withExpectedType(buildErrorTypeRef {
transformer, diagnostic =
withExpectedType(buildErrorTypeRef { ConeSimpleDiagnostic("Unresolved lambda return type", DiagnosticKind.InferenceError)
diagnostic = })
ConeSimpleDiagnostic("Unresolved lambda return type", DiagnosticKind.InferenceError)
})
)
} }
result.transformReturnTypeRef(transformer, resolutionMode)
} }
return result return result
@@ -253,27 +253,6 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
return null return null
} }
protected fun getPropertySignature(
proto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable,
field: Boolean = false,
synthetic: Boolean = false,
requireHasFieldFlagForField: Boolean = true
): MemberSignature? {
val signature = proto.getExtensionOrNull(propertySignature) ?: return null
if (field) {
val fieldSignature =
JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable, requireHasFieldFlagForField) ?: return null
return MemberSignature.fromJvmMemberSignature(fieldSignature)
} else if (synthetic && signature.hasSyntheticMethod()) {
return MemberSignature.fromMethod(nameResolver, signature.syntheticMethod)
}
return null
}
protected fun getCallableSignature( protected fun getCallableSignature(
proto: MessageLite, proto: MessageLite,
nameResolver: NameResolver, nameResolver: NameResolver,
@@ -319,3 +298,24 @@ abstract class AbstractBinaryClassAnnotationLoader<A : Any, S : AbstractBinaryCl
abstract val memberAnnotations: Map<MemberSignature, List<A>> abstract val memberAnnotations: Map<MemberSignature, List<A>>
} }
} }
fun getPropertySignature(
proto: ProtoBuf.Property,
nameResolver: NameResolver,
typeTable: TypeTable,
field: Boolean = false,
synthetic: Boolean = false,
requireHasFieldFlagForField: Boolean = true
): MemberSignature? {
val signature = proto.getExtensionOrNull(propertySignature) ?: return null
if (field) {
val fieldSignature =
JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable, requireHasFieldFlagForField) ?: return null
return MemberSignature.fromJvmMemberSignature(fieldSignature)
} else if (synthetic && signature.hasSyntheticMethod()) {
return MemberSignature.fromMethod(nameResolver, signature.syntheticMethod)
}
return null
}