[FIR] Resolve array literals in independent context

This commit is contained in:
Dmitriy Novozhilov
2021-04-15 17:12:41 +03:00
parent cc0f28b698
commit 564de2790f
10 changed files with 66 additions and 26 deletions
@@ -73,6 +73,9 @@ val ConeKotlinType.isArrayType: Boolean
val ConeKotlinType.isNonPrimitiveArray: Boolean
get() = this is ConeClassLikeType && lookupTag.classId == StandardClassIds.Array
val ConeKotlinType.isPrimitiveArray: Boolean
get() = this is ConeClassLikeType && lookupTag.classId in StandardClassIds.primitiveArrayTypeByElementType.values
private val builtinUnsignedTypes = setOf(StandardClassIds.UInt, StandardClassIds.UByte, StandardClassIds.ULong, StandardClassIds.UShort)
val ConeKotlinType.isUnsignedTypeOrNullableUnsignedType: Boolean get() = isAnyOfBuiltinType(builtinUnsignedTypes)
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.fir.types.builder.buildStarProjection
import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.types.AbstractTypeApproximator
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.runIf
@@ -44,7 +43,7 @@ class FirCallCompletionResultsWriterTransformer(
override val session: FirSession,
private val finalSubstitutor: ConeSubstitutor,
private val typeCalculator: ReturnTypeCalculator,
private val typeApproximator: AbstractTypeApproximator,
private val typeApproximator: ConeTypeApproximator,
private val dataFlowAnalyzer: FirDataFlowAnalyzer<*>,
private val mode: Mode = Mode.Normal
) : FirAbstractTreeTransformer<ExpectedArgumentType?>(phase = FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE) {
@@ -287,7 +286,7 @@ class FirCallCompletionResultsWriterTransformer(
val substitutedType = finalSubstitutor.substituteOrNull(initialType)
val finalType = typeApproximator.approximateToSuperType(
type = substitutedType ?: initialType, TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference,
) as ConeKotlinType? ?: substitutedType
) ?: substitutedType
return withReplacedConeType(finalType)
}
@@ -475,7 +474,7 @@ class FirCallCompletionResultsWriterTransformer(
finalSubstitutor.substituteOrSelf(it).let { substitutedType ->
typeApproximator.approximateToSuperType(
substitutedType, TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference,
) as ConeKotlinType? ?: substitutedType
) ?: substitutedType
}
}
}
@@ -537,7 +536,8 @@ class FirCallCompletionResultsWriterTransformer(
}
if (needUpdateLambdaType) {
val resolvedTypeRef = anonymousFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true)
val resolvedTypeRef =
anonymousFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true)
anonymousFunction.replaceTypeRef(resolvedTypeRef)
session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, null)
}
@@ -558,7 +558,8 @@ class FirCallCompletionResultsWriterTransformer(
val newReturnTypeRef = resultFunction.returnTypeRef.withReplacedConeType(lastExpressionType)
resultFunction.replaceReturnTypeRef(newReturnTypeRef)
val resolvedTypeRef = resultFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true)
val resolvedTypeRef =
resultFunction.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true)
resultFunction.replaceTypeRef(resolvedTypeRef)
session.lookupTracker?.let {
it.recordTypeResolveAsLookup(newReturnTypeRef, anonymousFunction.source, null)
@@ -710,9 +711,14 @@ class FirCallCompletionResultsWriterTransformer(
val expectedArrayType = data?.getExpectedType(arrayOfCall)
val expectedArrayElementType = expectedArrayType?.arrayElementType()
arrayOfCall.transformChildren(this, expectedArrayElementType?.toExpectedType())
val arrayElementType = session.inferenceComponents.ctx.commonSuperTypeOrNull(arrayOfCall.arguments.map { it.typeRef.coneType })
?: session.builtinTypes.nullableAnyType.type
arrayOfCall.resultType = arrayOfCall.typeRef.resolvedTypeFromPrototype(arrayElementType.createArrayType())
val arrayElementType =
session.inferenceComponents.ctx.commonSuperTypeOrNull(arrayOfCall.arguments.map { it.typeRef.coneType })?.let {
typeApproximator.approximateToSuperType(it, TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference)
?: it
} ?: expectedArrayElementType ?: session.builtinTypes.nullableAnyType.type
arrayOfCall.resultType = arrayOfCall.typeRef.resolvedTypeFromPrototype(
arrayElementType.createArrayType(createPrimitiveArrayType = expectedArrayType?.isPrimitiveArray == true)
)
return arrayOfCall
}
@@ -127,6 +127,22 @@ class FirSyntheticCallGenerator(
return elvisExpression.transformCalleeReference(UpdateReference, reference)
}
fun generateSyntheticCallForArrayOfCall(arrayOfCall: FirArrayOfCall, context: ResolutionContext): FirFunctionCall {
val argumentList = buildArgumentList {
arguments += arrayOfCall
}
return buildFunctionCall {
this.argumentList = argumentList
calleeReference = generateCalleeReferenceWithCandidate(
arrayOfCall,
idFunction,
argumentList,
SyntheticCallableId.ID.callableName,
context = context
)
}
}
fun resolveCallableReferenceWithSyntheticOuterCall(
callableReferenceAccess: FirCallableReferenceAccess,
expectedTypeRef: FirTypeRef?,
@@ -224,6 +224,10 @@ open class FirBodyResolveTransformer(
return expressionsTransformer.transformCheckedSafeCallSubject(checkedSafeCallSubject, data)
}
override fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: ResolutionMode): FirStatement {
return expressionsTransformer.transformArrayOfCall(arrayOfCall, data)
}
// ------------------------------------- Declarations -------------------------------------
override fun transformDeclaration(declaration: FirDeclaration, data: ResolutionMode): FirDeclaration {
@@ -968,6 +968,17 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
return result
}
override fun transformArrayOfCall(arrayOfCall: FirArrayOfCall, data: ResolutionMode): FirStatement {
if (data is ResolutionMode.ContextDependent) {
arrayOfCall.transformChildren(transformer, data)
return arrayOfCall
}
val syntheticIdCall = components.syntheticCallGenerator.generateSyntheticCallForArrayOfCall(arrayOfCall, resolutionContext)
arrayOfCall.transformChildren(transformer, ResolutionMode.ContextDependent)
callCompleter.completeCall(syntheticIdCall, data.expectedType ?: components.noExpectedType)
return arrayOfCall
}
// ------------------------------------------------------------------------------------------------
internal fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
@@ -10,12 +10,12 @@ import org.jetbrains.kotlin.name.StandardClassIds
val ConeKotlinType.isArrayOrPrimitiveArray: Boolean
get() = arrayElementType() != null
fun ConeKotlinType.createOutArrayType(nullable: Boolean = false): ConeKotlinType {
return ConeKotlinTypeProjectionOut(this).createArrayType(nullable)
fun ConeKotlinType.createOutArrayType(nullable: Boolean = false, createPrimitiveArrayType: Boolean = true): ConeKotlinType {
return ConeKotlinTypeProjectionOut(this).createArrayType(nullable, createPrimitiveArrayType)
}
fun ConeTypeProjection.createArrayType(nullable: Boolean = false): ConeClassLikeType {
if (this is ConeKotlinTypeProjection) {
fun ConeTypeProjection.createArrayType(nullable: Boolean = false, createPrimitiveArrayType: Boolean = true): ConeClassLikeType {
if (this is ConeKotlinTypeProjection && createPrimitiveArrayType) {
val type = type.lowerBoundIfFlexible()
if (type is ConeClassLikeType && type.nullability != ConeNullability.NULLABLE) {
val classId = type.lookupTag.classId
@@ -7,18 +7,18 @@ fun test() {
val b: Array<Int> = []
val c = [1, 2]
val d: Array<Int> = [1, 2]
val e: Array<String> = [1]
val e: Array<String> = <!INITIALIZER_TYPE_MISMATCH!>[1]<!>
val f: IntArray = [1, 2]
val g = [f]
}
fun check() {
[1, 2] <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><Array<Int>>() }
[""] <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><Array<String>>() }
[1, 2] checkType { _<Array<Int>>() }
[""] checkType { _<Array<String>>() }
val f: IntArray = [1]
[f] <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><Array<IntArray>>() }
[f] checkType { _<Array<IntArray>>() }
[1, ""] <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!INAPPLICABLE_CANDIDATE!>_<!><Array<Any>>() }
[1, ""] checkType { <!INAPPLICABLE_CANDIDATE!>_<!><Array<Any>>() }
}
@@ -12,7 +12,7 @@ fun basicTypes() {
}
fun basicTypesWithErrors() {
val a: IntArray = [1.0]
val b: ShortArray = [1.0]
val c: CharArray = ["a"]
}
val a: IntArray = <!INITIALIZER_TYPE_MISMATCH!>[1.0]<!>
val b: ShortArray = <!INITIALIZER_TYPE_MISMATCH!>[1.0]<!>
val c: CharArray = <!INITIALIZER_TYPE_MISMATCH!>["a"]<!>
}
@@ -10,7 +10,7 @@ fun test() {
takeArray([""])
val v = [""]
[""]
[1, 2, 3].<!UNRESOLVED_REFERENCE!>size<!>
[1, 2, 3].size
}
fun baz(arg: Array<Int> = []) {
@@ -1,12 +1,12 @@
// !WITH_NEW_INFERENCE
fun test(): Array<Int> {
[1, 2]
[1, 2]<!NO_GET_METHOD!>[0]<!>
[1, 2].<!UNRESOLVED_REFERENCE!>get<!>(0)
[1, 2][0]
[1, 2].get(0)
foo([""])
val p = [1, 2] + [3, 4]
val p = [1, 2] <!UNRESOLVED_REFERENCE!>+<!> [3, 4]
return [1, 2]
}