[FIR] Record & use type arguments of FirQualifiedAccessExpression

This commit is contained in:
Mikhail Glukhikh
2020-02-25 19:30:40 +03:00
parent f53b059410
commit 50abb07245
26 changed files with 108 additions and 61 deletions
@@ -785,13 +785,13 @@ class Fir2IrVisitor(
}
}
private fun IrExpression.applyTypeArguments(call: FirFunctionCall): IrExpression {
private fun IrExpression.applyTypeArguments(access: FirQualifiedAccess): IrExpression {
return when (this) {
is IrCallWithIndexedArgumentsBase -> {
val argumentsCount = call.typeArguments.size
val argumentsCount = access.typeArguments.size
if (argumentsCount <= typeArgumentsCount) {
apply {
for ((index, argument) in call.typeArguments.withIndex()) {
for ((index, argument) in access.typeArguments.withIndex()) {
val argumentIrType = (argument as FirTypeProjectionWithVariance).typeRef.toIrType(
session,
declarationStorage
@@ -904,7 +904,8 @@ class Fir2IrVisitor(
}
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any?): IrElement {
return qualifiedAccessExpression.toIrExpression(qualifiedAccessExpression.typeRef).applyReceivers(qualifiedAccessExpression)
return qualifiedAccessExpression.toIrExpression(qualifiedAccessExpression.typeRef)
.applyTypeArguments(qualifiedAccessExpression).applyReceivers(qualifiedAccessExpression)
}
override fun visitThisReceiverExpression(thisReceiverExpression: FirThisReceiverExpression, data: Any?): IrElement {
@@ -53,6 +53,7 @@ class FirCallCompletionResultsWriterTransformer(
qualifiedAccessExpression.calleeReference as? FirNamedReferenceWithCandidate ?: return qualifiedAccessExpression.compose()
val candidateFir = calleeReference.candidateSymbol.phasedFir
val typeArguments = computeTypeArguments(qualifiedAccessExpression, calleeReference.candidate)
val typeRef = (candidateFir as? FirTypedDeclaration)?.let {
typeCalculator.tryCalculateReturnType(it)
} ?: buildErrorTypeRef {
@@ -60,7 +61,7 @@ class FirCallCompletionResultsWriterTransformer(
diagnostic = FirSimpleDiagnostic("Callee reference to candidate without return type: ${candidateFir.render()}")
}
qualifiedAccessExpression.replaceTypeRefWithSubstituted(calleeReference, typeRef)
qualifiedAccessExpression.replaceTypeRefWithSubstituted(calleeReference, typeRef).replaceTypeArguments(typeArguments)
return qualifiedAccessExpression.transformCalleeReference(
StoreCalleeReference,
@@ -69,7 +70,9 @@ class FirCallCompletionResultsWriterTransformer(
name = calleeReference.name
resolvedSymbol = calleeReference.candidateSymbol
},
).compose()
).apply {
replaceTypeArguments(typeArguments)
}.compose()
}
private fun <D : FirExpression> D.replaceTypeRefWithSubstituted(
@@ -115,7 +118,7 @@ class FirCallCompletionResultsWriterTransformer(
source = calleeReference.source
name = calleeReference.name
resolvedSymbol = calleeReference.candidateSymbol
inferredTypeArguments.addAll(computeTypeArguments(calleeReference.candidate))
inferredTypeArguments.addAll(computeTypeArgumentTypes(calleeReference.candidate))
},
).compose()
}
@@ -141,29 +144,7 @@ class FirCallCompletionResultsWriterTransformer(
val subCandidate = calleeReference.candidate
val declaration = subCandidate.symbol.phasedFir as FirCallableMemberDeclaration<*>
val typeArguments = computeTypeArguments(subCandidate)
.mapIndexed { index, type ->
when (val argument = functionCall.typeArguments.getOrNull(index)) {
is FirTypeProjectionWithVariance -> {
val typeRef = argument.typeRef as FirResolvedTypeRef
buildTypeProjectionWithVariance {
source = argument.source
this.typeRef = typeRef.withReplacedConeType(type)
variance = argument.variance
}
}
else -> {
buildTypeProjectionWithVariance {
source = argument?.source
typeRef = buildResolvedTypeRef {
this.type = type
}
variance = Variance.INVARIANT
}
}
}
}
val typeArguments = computeTypeArguments(functionCall, subCandidate)
val typeRef = typeCalculator.tryCalculateReturnType(declaration).let {
if (functionCall.safe) {
val nullableType = it.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE, session.inferenceContext)
@@ -262,6 +243,34 @@ class FirCallCompletionResultsWriterTransformer(
}
private fun computeTypeArguments(
access: FirQualifiedAccess,
candidate: Candidate
): List<FirTypeProjectionWithVariance> {
return computeTypeArgumentTypes(candidate)
.mapIndexed { index, type ->
when (val argument = access.typeArguments.getOrNull(index)) {
is FirTypeProjectionWithVariance -> {
val typeRef = argument.typeRef as FirResolvedTypeRef
buildTypeProjectionWithVariance {
source = argument.source
this.typeRef = typeRef.withReplacedConeType(type)
variance = argument.variance
}
}
else -> {
buildTypeProjectionWithVariance {
source = argument?.source
typeRef = buildResolvedTypeRef {
this.type = type
}
variance = Variance.INVARIANT
}
}
}
}
}
private fun computeTypeArgumentTypes(
candidate: Candidate,
): List<ConeKotlinType> {
val declaration = candidate.symbol.phasedFir as? FirCallableMemberDeclaration<*> ?: return emptyList()
@@ -20,7 +20,7 @@ FILE: extensionPropertyInLambda.kt
}
public final fun test1(): R|kotlin/Unit| {
R|/use|(<L> = use@fun <anonymous>(): R|kotlin/String| {
^ R|/C.C|<R|kotlin/String|>(String(abc)).R|/y|
^ R|/C.C|<R|kotlin/String|>(String(abc)).R|/y|<R|kotlin/String|>
}
)
R|/use|(R|/C.C|<R|kotlin/String|>(String(abc))::R|/y<kotlin/String>|)
@@ -21,8 +21,8 @@ FILE: simpleCapturedTypes.kt
private final fun getSetterInfos(kc: R|KC<out Ann>|): R|kotlin/Unit| {
R|/id|<R|CapturedType(out Ann)|>(R|<local>/kc|).R|FakeOverride</KC.x: R|Ann|>|.R|/Ann.foo|()
R|<local>/kc|.R|/idR|<R|CapturedType(out Ann)|>().R|FakeOverride</KC.x: R|Ann|>|.R|/Ann.foo|()
R|<local>/kc|.R|/idP|.R|FakeOverride</KC.x: R|Ann|>|.R|/Ann.foo|()
R|<local>/kc|.R|/idP|<R|CapturedType(out Ann)|>.R|FakeOverride</KC.x: R|Ann|>|.R|/Ann.foo|()
lval x1: R|KC<out Ann>| = R|/id|<R|CapturedType(out Ann)|>(R|<local>/kc|)
lval x2: R|KC<out Ann>| = R|<local>/kc|.R|/idR|<R|CapturedType(out Ann)|>()
lval x3: R|KC<out Ann>| = R|<local>/kc|.R|/idP|
lval x3: R|KC<out Ann>| = R|<local>/kc|.R|/idP|<R|CapturedType(out Ann)|>
}
@@ -1,5 +1,5 @@
FILE: classLiteralForParameter.kt
public final inline fun <reified T : R|kotlin/Any|> foo(t: R|T|): R|T| {
lval klass: R|java/lang/Class<T>| = <getClass>(R|T|).R|kotlin/jvm/java|
lval klass: R|java/lang/Class<T>| = <getClass>(R|T|).R|kotlin/jvm/java|<R|T|>
^foo R|<local>/t|
}
@@ -7,7 +7,7 @@ FILE: test.kt
super<R|kotlin/Any|>()
}
private final val klass: R|java/lang/Class<MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|
private final val klass: R|java/lang/Class<MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|MyTest|>
private get(): R|java/lang/Class<MyTest>|
private final val logger: R|ft<Logger, Logger?>!| = Q|Logger|.R|/Logger.getInstance|(this@R|/MyTest|.R|/MyTest.klass|)
@@ -13,7 +13,7 @@ FILE: User.kt
protected abstract fun createSettings(): R|T|
public final fun foo(): R|kotlin/Unit| {
this@R|/User|.R|/User.settings| = Q|StaticOwner|.R|/StaticOwner.newInstance|<R|ft<T, T?>!|>(this@R|/User|.R|/User.settings|.R|kotlin/jvm/javaClass|)
this@R|/User|.R|/User.settings| = Q|StaticOwner|.R|/StaticOwner.newInstance|<R|ft<T, T?>!|>(this@R|/User|.R|/User.settings|.R|kotlin/jvm/javaClass|<R|ft<T, T?>!|>)
}
}
@@ -1,9 +1,9 @@
FILE: reflectionClass.kt
public final val javaClass: R|java/lang/Class<kotlin/String>| = <getClass>(Q|kotlin/String|).R|kotlin/jvm/java|
public final val javaClass: R|java/lang/Class<kotlin/String>| = <getClass>(Q|kotlin/String|).R|kotlin/jvm/java|<R|kotlin/String|>
public get(): R|java/lang/Class<kotlin/String>|
public final val kotlinClass: R|kotlin/reflect/KClass<kotlin/String>| = <getClass>(Q|kotlin/String|)
public get(): R|kotlin/reflect/KClass<kotlin/String>|
public final fun foo(): R|kotlin/Unit| {
lval stringClass: R|java/lang/Class<kotlin/String>| = <getClass>(Q|kotlin/String|).R|kotlin/jvm/java|
lval arrayStringClass: R|java/lang/Class<kotlin/Array<*>>| = <getClass>(Q|kotlin/Array|).R|kotlin/jvm/java|
lval stringClass: R|java/lang/Class<kotlin/String>| = <getClass>(Q|kotlin/String|).R|kotlin/jvm/java|<R|kotlin/String|>
lval arrayStringClass: R|java/lang/Class<kotlin/Array<*>>| = <getClass>(Q|kotlin/Array|).R|kotlin/jvm/java|<R|kotlin/Array<*>|>
}
@@ -25,6 +25,8 @@ interface FirQualifiedAccessWithoutCallee : FirStatement {
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitQualifiedAccessWithoutCallee(this, data)
fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
fun <D> transformTypeArguments(transformer: FirTransformer<D>, data: D): FirQualifiedAccessWithoutCallee
fun <D> transformExplicitReceiver(transformer: FirTransformer<D>, data: D): FirQualifiedAccessWithoutCallee
@@ -33,5 +33,7 @@ abstract class FirResolvedQualifier : FirExpression() {
abstract fun replaceSafe(newSafe: Boolean)
abstract fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
abstract fun <D> transformTypeArguments(transformer: FirTransformer<D>, data: D): FirResolvedQualifier
}
@@ -109,4 +109,9 @@ internal class FirArraySetCallImpl(
indexes.transformInplace(transformer, data)
return this
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -88,4 +88,9 @@ internal class FirCallableReferenceAccessImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -95,4 +95,9 @@ internal class FirComponentCallImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -97,4 +97,9 @@ open class FirFunctionCallImpl @FirImplementationDetail constructor(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -35,4 +35,6 @@ interface FirModifiableQualifiedAccess : FirQualifiedAccessWithoutCallee {
override fun <D> transformDispatchReceiver(transformer: FirTransformer<D>, data: D): FirModifiableQualifiedAccess
override fun <D> transformExtensionReceiver(transformer: FirTransformer<D>, data: D): FirModifiableQualifiedAccess
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
}
@@ -88,4 +88,9 @@ internal class FirQualifiedAccessExpressionImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -59,4 +59,9 @@ internal class FirResolvedQualifierImpl(
override fun replaceSafe(newSafe: Boolean) {
safe = newSafe
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -90,4 +90,9 @@ internal class FirThisReceiverExpressionImpl(
override fun replaceTypeRef(newTypeRef: FirTypeRef) {
typeRef = newTypeRef
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -94,4 +94,9 @@ internal class FirVariableAssignmentImpl(
rValue = rValue.transformSingle(transformer, data)
return this
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
typeArguments.clear()
typeArguments.addAll(newTypeArguments)
}
}
@@ -67,5 +67,9 @@ internal class FirExpressionWithSmartcastImpl(
throw IllegalStateException()
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
throw IllegalStateException()
}
override fun replaceTypeRef(newTypeRef: FirTypeRef) {}
}
@@ -29,7 +29,7 @@ object FieldSets {
)
val typeArguments =
fieldList("typeArguments", typeProjection)
fieldList("typeArguments", typeProjection, withReplace = true)
val arguments =
fieldList("arguments", expression)
@@ -24,9 +24,5 @@ FILE fqName:<root> fileName:/classReference.kt
GET_OBJECT 'CLASS CLASS name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
GET_CLASS type=kotlin.reflect.KClass<<root>.A>
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.A' type=<root>.A origin=null
CALL 'public final fun <get-java> (): java.lang.Class<T of <uninitialized parent>> declared in kotlin.jvm' type=java.lang.Class<<root>.A> origin=null
$receiver: GET_CLASS type=kotlin.reflect.KClass<<root>.A>
GET_OBJECT 'CLASS CLASS name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit
CALL 'public final fun <get-java> (): java.lang.Class<T of <uninitialized parent>> declared in kotlin.jvm' type=java.lang.Class<<root>.A> origin=null
$receiver: GET_CLASS type=kotlin.reflect.KClass<<root>.A>
CONSTRUCTOR_CALL 'public constructor <init> () [primary] declared in <root>.A' type=<root>.A origin=null
ERROR_EXPR 'Cannot bind 1 type arguments to <get-java> call with 0 type parameters' type=java.lang.Class<<root>.A>
ERROR_EXPR 'Cannot bind 1 type arguments to <get-java> call with 0 type parameters' type=java.lang.Class<<root>.A>
@@ -9,8 +9,7 @@ FILE fqName:<root> fileName:/genericPropertyCall.kt
PROPERTY name:test visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:test type:kotlin.String visibility:private [final,static]
EXPRESSION_BODY
CALL 'public final fun <get-id> (): T of <uninitialized parent> declared in <root>' type=kotlin.String origin=null
$receiver: CONST String type=kotlin.String value="abc"
ERROR_EXPR 'Cannot bind 1 type arguments to <get-id> call with 0 type parameters' type=kotlin.String
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test> visibility:public modality:FINAL <> () returnType:kotlin.String
correspondingProperty: PROPERTY name:test visibility:public modality:FINAL [val]
BLOCK_BODY
@@ -22,6 +22,4 @@ FILE fqName:<root> fileName:/objectClassReference.kt
BLOCK_BODY
GET_CLASS type=kotlin.reflect.KClass<<root>.A>
GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.A
CALL 'public final fun <get-java> (): java.lang.Class<T of <uninitialized parent>> declared in kotlin.jvm' type=java.lang.Class<<root>.A> origin=null
$receiver: GET_CLASS type=kotlin.reflect.KClass<<root>.A>
GET_OBJECT 'CLASS OBJECT name:A modality:FINAL visibility:public superTypes:[kotlin.Any]' type=<root>.A
ERROR_EXPR 'Cannot bind 1 type arguments to <get-java> call with 0 type parameters' type=java.lang.Class<<root>.A>
@@ -229,9 +229,7 @@ FILE fqName:<root> fileName:/useImportedMember.kt
BRANCH
if: CALL 'public final fun not (): kotlin.Boolean [operator] declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
arg0: CALL 'public final fun <get-g2> (): T of <uninitialized parent> declared in <root>.C' type=kotlin.String origin=null
$this: CONST String type=kotlin.String value="8"
$receiver: CONST String type=kotlin.String value="8"
arg0: ERROR_EXPR 'Cannot bind 1 type arguments to <get-g2> call with 0 type parameters' type=kotlin.String
arg1: CONST String type=kotlin.String value="8"
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
CONST String type=kotlin.String value="8"
@@ -250,9 +248,7 @@ FILE fqName:<root> fileName:/useImportedMember.kt
BRANCH
if: CALL 'public final fun not (): kotlin.Boolean [operator] declared in kotlin.Boolean' type=kotlin.Boolean origin=EXCLEQ
$this: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EXCLEQ
arg0: CALL 'public final fun <get-fromClass> (): T of <uninitialized parent> declared in <root>.BaseClass' type=kotlin.String origin=null
$this: CONST String type=kotlin.String value="10"
$receiver: CONST String type=kotlin.String value="10"
arg0: ERROR_EXPR 'Cannot bind 1 type arguments to <get-fromClass> call with 0 type parameters' type=kotlin.String
arg1: CONST String type=kotlin.String value="10"
then: RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in <root>'
CONST String type=kotlin.String value="10"
@@ -15,8 +15,7 @@ FILE fqName:<root> fileName:/variableAsFunctionCallWithGenerics.kt
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun testGeneric1 (x: kotlin.String): T of <uninitialized parent> declared in <root>'
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of <uninitialized parent> origin=INVOKE
$this: CALL 'public final fun <get-gk> (): kotlin.Function0<T of <uninitialized parent>> declared in <root>' type=kotlin.Function0<kotlin.String> origin=null
$receiver: GET_VAR 'x: kotlin.String declared in <root>.testGeneric1' type=kotlin.String origin=null
$this: ERROR_EXPR 'Cannot bind 1 type arguments to <get-gk> call with 0 type parameters' type=kotlin.Function0<kotlin.String>
PROPERTY name:kt26531Val visibility:public modality:FINAL [val]
FUN name:<get-kt26531Val> visibility:public modality:FINAL <> ($receiver:T of <uninitialized parent>) returnType:kotlin.Function0<T of <uninitialized parent>>
correspondingProperty: PROPERTY name:kt26531Val visibility:public modality:FINAL [val]
@@ -32,5 +31,4 @@ FILE fqName:<root> fileName:/variableAsFunctionCallWithGenerics.kt
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun kt26531 (): T of <uninitialized parent> declared in <root>'
CALL 'public abstract fun invoke (): R of kotlin.Function0 [operator] declared in kotlin.Function0' type=T of <uninitialized parent> origin=INVOKE
$this: CALL 'public final fun <get-kt26531Val> (): kotlin.Function0<T of <uninitialized parent>> declared in <root>' type=kotlin.Function0<kotlin.Int> origin=null
$receiver: CONST Int type=kotlin.Int value=7
$this: ERROR_EXPR 'Cannot bind 1 type arguments to <get-kt26531Val> call with 0 type parameters' type=kotlin.Function0<kotlin.Int>