FIR: support type inference for assignments, fix related lambda inference

This commit is contained in:
Mikhail Glukhikh
2019-06-18 18:03:09 +03:00
parent 48cea4b800
commit d41c50d6cf
15 changed files with 156 additions and 88 deletions
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
@@ -49,9 +47,8 @@ fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: Fi
}
}
internal fun FirFunctionCall.candidate(): Candidate? {
val callee = this.calleeReference
return when (callee) {
internal fun FirQualifiedAccess.candidate(): Candidate? {
return when (val callee = this.calleeReference) {
is FirNamedReferenceWithCandidate -> return callee.candidate
else -> null
}
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
@@ -92,7 +93,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
fun complete(
c: KotlinConstraintSystemCompleter.Context,
completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode,
topLevelAtoms: List<FirExpression>,
topLevelAtoms: List<FirStatement>,
candidateReturnType: ConeKotlinType,
analyze: (PostponedResolvedAtomMarker) -> Unit
) {
@@ -159,7 +160,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
private fun analyzePostponeArgumentIfPossible(
c: KotlinConstraintSystemCompleter.Context,
topLevelAtoms: List<FirExpression>,
topLevelAtoms: List<FirStatement>,
analyze: (PostponedResolvedAtomMarker) -> Unit
): Boolean {
for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)) {
@@ -171,8 +172,8 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
return false
}
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirExpression>): List<PostponedResolvedAtomMarker> {
fun FirExpression.process(to: MutableList<PostponedResolvedAtomMarker>) {
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirStatement>): List<PostponedResolvedAtomMarker> {
fun FirStatement.process(to: MutableList<PostponedResolvedAtomMarker>) {
when (this) {
is FirFunctionCall -> {
val candidate = (this.calleeReference as? FirNamedReferenceWithCandidate)?.candidate
@@ -198,7 +198,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
access.resultType = typeFromCallee(access)
}
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess, T : FirExpression {
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess {
return when (val newCallee = access.calleeReference) {
is FirErrorNamedReference ->
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
@@ -232,6 +232,12 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
error("WTF ! $symbol")
}
}
is FirThisReference -> {
val labelName = newCallee.labelName
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
FirResolvedTypeRefImpl(session, null, type, emptyList())
}
else -> error("Failed to extract type from: $newCallee")
}
}
@@ -402,8 +408,15 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
variableAssignment: FirVariableAssignment,
data: Any?
): CompositeTransformResult<FirStatement> {
val variableAssignment = variableAssignment.transformRValue(this, null)
return transformCallee(variableAssignment).compose()
val resolvedAssignment = transformCallee(variableAssignment)
return if (resolvedAssignment is FirVariableAssignment) {
val completeAssignment = completeTypeInference(resolvedAssignment, noExpectedType)
val expectedType = typeFromCallee(completeAssignment)
completeAssignment.transformRValue(this, expectedType).compose()
} else {
// This can happen in erroneous code only
resolvedAssignment.compose()
}
}
override fun transformAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): CompositeTransformResult<FirDeclaration> {
@@ -592,13 +605,15 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
data class LambdaResolution(val expectedReturnTypeRef: FirResolvedTypeRef?)
private fun completeTypeInference(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
val typeRef = typeFromCallee(functionCall)
private fun <T : FirQualifiedAccess> completeTypeInference(qualifiedAccess: T, expectedTypeRef: FirTypeRef?): T {
val typeRef = typeFromCallee(qualifiedAccess)
if (typeRef.type is ConeKotlinErrorType) {
functionCall.resultType = typeRef
return functionCall
if (qualifiedAccess is FirExpression) {
qualifiedAccess.resultType = typeRef
}
return qualifiedAccess
}
val candidate = functionCall.candidate() ?: return functionCall
val candidate = qualifiedAccess.candidate() ?: return qualifiedAccess
val initialSubstitutor = candidate.substitutor
val initialType = initialSubstitutor.substituteOrSelf(typeRef.type)
@@ -637,16 +652,18 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
else -> null
}
val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) }
val newLambdaExpression = lambdaArgument.copy(
receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) },
valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter ->
parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index]))
parameter
} + listOfNotNull(itParam),
returnTypeRef = lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(rawReturnType)
returnTypeRef = expectedReturnTypeRef ?: noExpectedType
)
val expectedReturnTypeRef = expectedReturnType?.let { newLambdaExpression.returnTypeRef.resolvedTypeFromPrototype(it) }
replacements[lambdaArgument] =
newLambdaExpression.transformSingle(this@FirBodyResolveTransformer, LambdaResolution(expectedReturnTypeRef))
@@ -656,7 +673,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
}, { it.resultType }, inferenceComponents)
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(functionCall), initialType) {
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(qualifiedAccess), initialType) {
analyzer.analyze(
candidate.system.asPostponedArgumentsAnalyzerContext(),
it
@@ -664,18 +681,18 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
)
}
functionCall.transformChildren(ReplaceInArguments, replacements.toMap())
qualifiedAccess.transformChildren(ReplaceInArguments, replacements.toMap())
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
val finalSubstitutor =
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
return functionCall.transformSingle(
return qualifiedAccess.transformSingle(
FirCallCompleterTransformer(session, finalSubstitutor, jump),
null
)
}
return functionCall
return qualifiedAccess
}
override fun transformTryExpression(tryExpression: FirTryExpression, data: Any?): CompositeTransformResult<FirStatement> {
@@ -5,13 +5,13 @@
package org.jetbrains.kotlin.fir.resolve.transformers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.copy
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef
@@ -23,15 +23,45 @@ import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
import org.jetbrains.kotlin.fir.types.impl.FirTypeProjectionWithVarianceImpl
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.compose
import org.jetbrains.kotlin.types.Variance
object StoreCalleeReference : FirTransformer<FirResolvedCallableReference>() {
override fun <E : FirElement> transformElement(element: E, data: FirResolvedCallableReference): CompositeTransformResult<E> {
return element.compose()
}
override fun transformResolvedCallableReference(
resolvedCallableReference: FirResolvedCallableReference,
data: FirResolvedCallableReference
): CompositeTransformResult<FirNamedReference> {
return data.compose()
}
}
class FirCallCompleterTransformer(
val session: FirSession,
private val finalSubstitutor: ConeSubstitutor,
private val typeCalculator: ReturnTypeCalculator
) : FirAbstractTreeTransformer() {
override fun transformVariableAssignment(
variableAssignment: FirVariableAssignment,
data: Nothing?
): CompositeTransformResult<FirStatement> {
val calleeReference = variableAssignment.calleeReference as? FirNamedReferenceWithCandidate
?: return variableAssignment.compose()
return variableAssignment.transformCalleeReference(
StoreCalleeReference,
FirResolvedCallableReferenceImpl(
calleeReference.session,
calleeReference.psi,
calleeReference.name,
calleeReference.coneSymbol
)
).compose()
}
override fun transformFunctionCall(functionCall: FirFunctionCall, data: Nothing?): CompositeTransformResult<FirStatement> {
val calleeReference = functionCall.calleeReference as? FirNamedReferenceWithCandidate ?: return functionCall.compose()
@@ -7,7 +7,14 @@ var b: MutableSet<String>? = null
field = HashSet()
}
var <T> MutableSet<T>.d: T? get() = null
set(_) {}
fun <T> produce(): T = TODO()
fun foo() {
var c: MutableSet<String>? = null
c = HashSet()
c!!.d = produce()
}
+20 -2
View File
@@ -4,9 +4,27 @@ FILE: hashSet.kt
public final var b: R|kotlin/collections/MutableSet<kotlin/String>|? = Null(null)
public get(): R|kotlin/collections/MutableSet<kotlin/String>|?
public set(_: R|kotlin/collections/MutableSet<kotlin/String>|?): R|kotlin/Unit| {
F|/b| = R|java/util/HashSet.HashSet|()
F|/b| = R|java/util/HashSet.HashSet|<R|kotlin/String|>()
}
public final var <T> R|kotlin/collections/MutableSet<T>|.d: R|T|?
public get(): R|T|? {
^ Null(null)
}
public set(_: R|T|?): R|kotlin/Unit| {
}
public final fun <T> produce(): R|T| {
^produce R|kotlin/TODO|()
}
public final fun foo(): R|kotlin/Unit| {
lvar c: R|kotlin/collections/MutableSet<kotlin/String>|? = Null(null)
R|<local>/c| = R|java/util/HashSet.HashSet|()
R|<local>/c| = R|java/util/HashSet.HashSet|<R|kotlin/String|>()
when (lval <bangbang>: R|kotlin/collections/MutableSet<kotlin/String>|? = R|<local>/c|) {
==($subj$, Null(null)) -> {
throw R|kotlin/KotlinNullPointerException.KotlinNullPointerException|()
}
else -> {
R|<local>/<bangbang>|!
}
}
.R|/d| = R|/produce|<R|T|?>()
}