FIR: Support safe-calls new format in body resolution
^KT-38444 In Progress
This commit is contained in:
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
interface A
|
||||||
|
|
||||||
|
fun test_1(a: A?, convert: A.() -> String) {
|
||||||
|
val s = a?.convert()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test_2(a: A, convert: A.() -> String) {
|
||||||
|
val s = a.convert()
|
||||||
|
}
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
FILE: extensionInvokeAfterSafeCall.kt
|
||||||
|
public abstract interface A : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public final fun test_1(a: R|A?|, convert: R|A.() -> kotlin/String|): R|kotlin/Unit| {
|
||||||
|
lval s: R|kotlin/String?| = R|<local>/a|?.{ R|<local>/convert|.R|FakeOverride<kotlin/Function1.invoke: R|kotlin/String|>|($subj$) }
|
||||||
|
}
|
||||||
|
public final fun test_2(a: R|A|, convert: R|A.() -> kotlin/String|): R|kotlin/Unit| {
|
||||||
|
lval s: R|kotlin/String| = R|<local>/convert|.R|FakeOverride<kotlin/Function1.invoke: R|kotlin/String|>|(R|<local>/a|)
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
typealias MyTypeAlias = (() -> String?)?
|
||||||
|
fun foo(x: MyTypeAlias) {
|
||||||
|
|
||||||
|
x?.let { y -> y()?.let { result -> bar(result) } }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar(x: String) = x
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
FILE: safeCallOnTypeAlias.kt
|
||||||
|
public final typealias MyTypeAlias = R|() -> kotlin/String?|
|
||||||
|
public final fun foo(x: R|MyTypeAlias|): R|kotlin/Unit| {
|
||||||
|
R|<local>/x|?.{ $subj$.R|kotlin/let|<R|() -> kotlin/String?|, R|kotlin/String|>(<L> = let@fun <anonymous>(y: R|() -> kotlin/String?|): R|kotlin/String| <kind=EXACTLY_ONCE> {
|
||||||
|
^ R|<local>/y|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/String?|>|()?.{ $subj$.R|kotlin/let|<R|kotlin/String|, R|kotlin/String|>(<L> = let@fun <anonymous>(result: R|kotlin/String|): R|kotlin/String| <kind=EXACTLY_ONCE> {
|
||||||
|
^ R|/bar|(R|<local>/result|)
|
||||||
|
}
|
||||||
|
) }
|
||||||
|
}
|
||||||
|
) }
|
||||||
|
}
|
||||||
|
public final fun bar(x: R|kotlin/String|): R|kotlin/String| {
|
||||||
|
^bar R|<local>/x|
|
||||||
|
}
|
||||||
Generated
+10
@@ -604,6 +604,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/debugInfoCall.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/debugInfoCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||||
|
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("invokeAmbiguity.kt")
|
@TestMetadata("invokeAmbiguity.kt")
|
||||||
public void testInvokeAmbiguity() throws Exception {
|
public void testInvokeAmbiguity() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt");
|
||||||
@@ -613,6 +618,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
public void testObjectInvoke() throws Exception {
|
public void testObjectInvoke() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("safeCallOnTypeAlias.kt")
|
||||||
|
public void testSafeCallOnTypeAlias() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/safeCallOnTypeAlias.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
|
||||||
|
|||||||
+10
@@ -604,6 +604,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/debugInfoCall.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/debugInfoCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("extensionInvokeAfterSafeCall.kt")
|
||||||
|
public void testExtensionInvokeAfterSafeCall() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/extensionInvokeAfterSafeCall.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("invokeAmbiguity.kt")
|
@TestMetadata("invokeAmbiguity.kt")
|
||||||
public void testInvokeAmbiguity() throws Exception {
|
public void testInvokeAmbiguity() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/invokeAmbiguity.kt");
|
||||||
@@ -613,6 +618,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
public void testObjectInvoke() throws Exception {
|
public void testObjectInvoke() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/objectInvoke.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("safeCallOnTypeAlias.kt")
|
||||||
|
public void testSafeCallOnTypeAlias() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/callResolution/safeCallOnTypeAlias.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
|
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/cfg")
|
||||||
|
|||||||
@@ -55,7 +55,11 @@ class Fir2IrVisitor(
|
|||||||
fakeOverrideMode: FakeOverrideMode
|
fakeOverrideMode: FakeOverrideMode
|
||||||
) : Fir2IrComponents by components, FirDefaultVisitor<IrElement, Any?>(), IrGeneratorContextInterface {
|
) : Fir2IrComponents by components, FirDefaultVisitor<IrElement, Any?>(), IrGeneratorContextInterface {
|
||||||
|
|
||||||
private val integerApproximator = IntegerLiteralTypeApproximationTransformer(session.firSymbolProvider, session.inferenceContext)
|
private val integerApproximator = IntegerLiteralTypeApproximationTransformer(
|
||||||
|
session.firSymbolProvider,
|
||||||
|
session.inferenceContext,
|
||||||
|
session
|
||||||
|
)
|
||||||
|
|
||||||
private val conversionScope = Fir2IrConversionScope()
|
private val conversionScope = Fir2IrConversionScope()
|
||||||
|
|
||||||
|
|||||||
@@ -439,4 +439,38 @@ fun CallableId.isIterator() =
|
|||||||
fun FirAnnotationCall.fqName(session: FirSession): FqName? {
|
fun FirAnnotationCall.fqName(session: FirSession): FqName? {
|
||||||
val symbol = session.firSymbolProvider.getSymbolByTypeRef<FirRegularClassSymbol>(annotationTypeRef) ?: return null
|
val symbol = session.firSymbolProvider.getSymbolByTypeRef<FirRegularClassSymbol>(annotationTypeRef) ?: return null
|
||||||
return symbol.classId.asSingleFqName()
|
return symbol.classId.asSingleFqName()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirCheckedSafeCallSubject.propagateTypeFromOriginalReceiver(nullableReceiverExpression: FirExpression, session: FirSession) {
|
||||||
|
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
|
|
||||||
|
val expandedReceiverType = if (receiverType is ConeClassLikeType) receiverType.fullyExpandedType(session) else receiverType
|
||||||
|
|
||||||
|
replaceTypeRef(typeRef.resolvedTypeFromPrototype(expandedReceiverType.makeConeTypeDefinitelyNotNullOrNotNull()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun FirSafeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(
|
||||||
|
nullableReceiverExpression: FirExpression,
|
||||||
|
session: FirSession,
|
||||||
|
) {
|
||||||
|
val receiverType = nullableReceiverExpression.typeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
|
val typeAfterNullCheck = regularQualifiedAccess.expressionTypeOrUnitForAssignment() ?: return
|
||||||
|
val isReceiverActuallyNullable = receiverType != null && session.inferenceContext.run { receiverType.isNullableType() }
|
||||||
|
|
||||||
|
val resultingType =
|
||||||
|
if (isReceiverActuallyNullable)
|
||||||
|
typeAfterNullCheck.withNullability(ConeNullability.NULLABLE, session.inferenceContext)
|
||||||
|
else
|
||||||
|
typeAfterNullCheck
|
||||||
|
|
||||||
|
replaceTypeRef(typeRef.resolvedTypeFromPrototype(resultingType))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirQualifiedAccess.expressionTypeOrUnitForAssignment(): ConeKotlinType? {
|
||||||
|
if (this is FirExpression) return typeRef.coneTypeSafe()
|
||||||
|
|
||||||
|
require(this is FirVariableAssignment) {
|
||||||
|
"The only non-expression FirQualifiedAccess is FirVariableAssignment, but ${this::class} was found"
|
||||||
|
}
|
||||||
|
return StandardClassIds.Unit.constructClassLikeType(emptyArray(), isNullable = false)
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.returnExpressions
|
|||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirILTTypeRefPlaceHolder
|
import org.jetbrains.kotlin.fir.scopes.impl.FirILTTypeRefPlaceHolder
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
@@ -32,21 +33,13 @@ import org.jetbrains.kotlin.types.model.CaptureStatus
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
fun Candidate.resolveArgumentExpression(
|
fun Candidate.resolveArgumentExpression(
|
||||||
/*
|
|
||||||
csBuilder: ConstraintSystemBuilder,
|
|
||||||
argument: KotlinCallArgument,
|
|
||||||
expectedType: UnwrappedType?,
|
|
||||||
diagnosticsHolder: KotlinDiagnosticsHolder,
|
|
||||||
isReceiver: Boolean
|
|
||||||
*/
|
|
||||||
csBuilder: ConstraintSystemBuilder,
|
csBuilder: ConstraintSystemBuilder,
|
||||||
argument: FirExpression,
|
argument: FirExpression,
|
||||||
expectedType: ConeKotlinType,
|
expectedType: ConeKotlinType,
|
||||||
expectedTypeRef: FirTypeRef,
|
expectedTypeRef: FirTypeRef,
|
||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isDispatch: Boolean,
|
isDispatch: Boolean
|
||||||
isSafeCall: Boolean
|
|
||||||
) {
|
) {
|
||||||
when (argument) {
|
when (argument) {
|
||||||
is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall -> resolveSubCallArgument(
|
is FirFunctionCall, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall -> resolveSubCallArgument(
|
||||||
@@ -55,9 +48,39 @@ fun Candidate.resolveArgumentExpression(
|
|||||||
expectedType,
|
expectedType,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
isDispatch,
|
isDispatch
|
||||||
isSafeCall
|
|
||||||
)
|
)
|
||||||
|
// x?.bar() is desugared to `x SAFE-CALL-OPERATOR { $not-null-receiver$.bar() }`
|
||||||
|
//
|
||||||
|
// If we have a safe-call as argument like in a call "foo(x SAFE-CALL-OPERATOR { $not-null-receiver$.bar() })"
|
||||||
|
// we obtain argument type (and argument's constraint system) from "$not-null-receiver$.bar()" (argument.regularQualifiedAccess)
|
||||||
|
// and then add constraint: typeOf(`$not-null-receiver$.bar()`).makeNullable() <: EXPECTED_TYPE
|
||||||
|
// NB: argument.regularQualifiedAccess is either a call or a qualified access
|
||||||
|
is FirSafeCallExpression -> {
|
||||||
|
val nestedQualifier = argument.regularQualifiedAccess
|
||||||
|
if (nestedQualifier is FirExpression) {
|
||||||
|
resolveSubCallArgument(
|
||||||
|
csBuilder,
|
||||||
|
nestedQualifier,
|
||||||
|
expectedType,
|
||||||
|
sink,
|
||||||
|
isReceiver,
|
||||||
|
isDispatch,
|
||||||
|
useNullableArgumentType = true
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Assignment
|
||||||
|
checkApplicabilityForArgumentType(
|
||||||
|
csBuilder,
|
||||||
|
StandardClassIds.Unit.constructClassLikeType(emptyArray(), isNullable = false),
|
||||||
|
expectedType.type,
|
||||||
|
SimpleConstraintSystemConstraintPosition,
|
||||||
|
isReceiver = false,
|
||||||
|
isDispatch = false,
|
||||||
|
sink = sink
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
is FirCallableReferenceAccess ->
|
is FirCallableReferenceAccess ->
|
||||||
if (argument.calleeReference is FirResolvedNamedReference)
|
if (argument.calleeReference is FirResolvedNamedReference)
|
||||||
resolvePlainExpressionArgument(
|
resolvePlainExpressionArgument(
|
||||||
@@ -66,8 +89,7 @@ fun Candidate.resolveArgumentExpression(
|
|||||||
expectedType,
|
expectedType,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
isDispatch,
|
isDispatch
|
||||||
isSafeCall
|
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
preprocessCallableReference(argument, expectedType)
|
preprocessCallableReference(argument, expectedType)
|
||||||
@@ -82,8 +104,7 @@ fun Candidate.resolveArgumentExpression(
|
|||||||
expectedTypeRef,
|
expectedTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
isDispatch,
|
isDispatch
|
||||||
isSafeCall
|
|
||||||
)
|
)
|
||||||
is FirBlock -> resolveBlockArgument(
|
is FirBlock -> resolveBlockArgument(
|
||||||
csBuilder,
|
csBuilder,
|
||||||
@@ -92,10 +113,9 @@ fun Candidate.resolveArgumentExpression(
|
|||||||
expectedTypeRef,
|
expectedTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
isDispatch,
|
isDispatch
|
||||||
isSafeCall
|
|
||||||
)
|
)
|
||||||
else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, isDispatch, isSafeCall)
|
else -> resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, isDispatch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +126,7 @@ private fun Candidate.resolveBlockArgument(
|
|||||||
expectedTypeRef: FirTypeRef,
|
expectedTypeRef: FirTypeRef,
|
||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isDispatch: Boolean,
|
isDispatch: Boolean
|
||||||
isSafeCall: Boolean
|
|
||||||
) {
|
) {
|
||||||
val returnArguments = block.returnExpressions()
|
val returnArguments = block.returnExpressions()
|
||||||
if (returnArguments.isEmpty()) {
|
if (returnArguments.isEmpty()) {
|
||||||
@@ -118,7 +137,6 @@ private fun Candidate.resolveBlockArgument(
|
|||||||
SimpleConstraintSystemConstraintPosition,
|
SimpleConstraintSystemConstraintPosition,
|
||||||
isReceiver = false,
|
isReceiver = false,
|
||||||
isDispatch = false,
|
isDispatch = false,
|
||||||
nullableExpectedType = expectedType.type.withNullability(ConeNullability.NULLABLE, sink.components.session.inferenceContext),
|
|
||||||
sink = sink
|
sink = sink
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -131,8 +149,7 @@ private fun Candidate.resolveBlockArgument(
|
|||||||
expectedTypeRef,
|
expectedTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
isDispatch,
|
isDispatch
|
||||||
isSafeCall
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,7 +161,7 @@ fun Candidate.resolveSubCallArgument(
|
|||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isDispatch: Boolean,
|
isDispatch: Boolean,
|
||||||
isSafeCall: Boolean
|
useNullableArgumentType: Boolean = false
|
||||||
) {
|
) {
|
||||||
val candidate = argument.candidate() ?: return resolvePlainExpressionArgument(
|
val candidate = argument.candidate() ?: return resolvePlainExpressionArgument(
|
||||||
csBuilder,
|
csBuilder,
|
||||||
@@ -153,7 +170,7 @@ fun Candidate.resolveSubCallArgument(
|
|||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
isDispatch,
|
isDispatch,
|
||||||
isSafeCall
|
useNullableArgumentType
|
||||||
)
|
)
|
||||||
/*
|
/*
|
||||||
* It's important to extract type from argument neither from symbol, because of symbol contains
|
* It's important to extract type from argument neither from symbol, because of symbol contains
|
||||||
@@ -165,7 +182,7 @@ fun Candidate.resolveSubCallArgument(
|
|||||||
sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).coneTypeUnsafe()
|
sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).coneTypeUnsafe()
|
||||||
}
|
}
|
||||||
val argumentType = candidate.substitutor.substituteOrSelf(type)
|
val argumentType = candidate.substitutor.substituteOrSelf(type)
|
||||||
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, isSafeCall)
|
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, useNullableArgumentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Candidate.resolvePlainExpressionArgument(
|
fun Candidate.resolvePlainExpressionArgument(
|
||||||
@@ -175,11 +192,11 @@ fun Candidate.resolvePlainExpressionArgument(
|
|||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isDispatch: Boolean,
|
isDispatch: Boolean,
|
||||||
isSafeCall: Boolean
|
useNullableArgumentType: Boolean = false
|
||||||
) {
|
) {
|
||||||
if (expectedType == null) return
|
if (expectedType == null) return
|
||||||
val argumentType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
val argumentType = argument.typeRef.coneTypeSafe<ConeKotlinType>() ?: return
|
||||||
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, isSafeCall)
|
resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isDispatch, useNullableArgumentType)
|
||||||
checkApplicabilityForIntegerOperatorCall(sink, argument)
|
checkApplicabilityForIntegerOperatorCall(sink, argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,22 +214,22 @@ fun Candidate.resolvePlainArgumentType(
|
|||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isDispatch: Boolean,
|
isDispatch: Boolean,
|
||||||
isSafeCall: Boolean
|
useNullableArgumentType: Boolean = false
|
||||||
) {
|
) {
|
||||||
val position = SimpleConstraintSystemConstraintPosition //TODO
|
val position = SimpleConstraintSystemConstraintPosition //TODO
|
||||||
|
|
||||||
val session = sink.components.session
|
val session = sink.components.session
|
||||||
val capturedType = prepareCapturedType(argumentType)
|
val capturedType = prepareCapturedType(argumentType)
|
||||||
|
|
||||||
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE, session.inferenceContext)
|
val argumentTypeForApplicabilityCheck =
|
||||||
if (isReceiver && isSafeCall) {
|
if (useNullableArgumentType)
|
||||||
if (!isDispatch && !csBuilder.addSubtypeConstraintIfCompatible(capturedType, nullableExpectedType, position)) {
|
capturedType.withNullability(ConeNullability.NULLABLE, session.inferenceContext)
|
||||||
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
|
else
|
||||||
}
|
capturedType
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
checkApplicabilityForArgumentType(csBuilder, capturedType, expectedType, position, isReceiver, isDispatch, nullableExpectedType, sink)
|
checkApplicabilityForArgumentType(
|
||||||
|
csBuilder, argumentTypeForApplicabilityCheck, expectedType, position, isReceiver, isDispatch, sink
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Candidate.prepareCapturedType(argumentType: ConeKotlinType): ConeKotlinType {
|
fun Candidate.prepareCapturedType(argumentType: ConeKotlinType): ConeKotlinType {
|
||||||
@@ -238,7 +255,6 @@ private fun checkApplicabilityForArgumentType(
|
|||||||
position: SimpleConstraintSystemConstraintPosition,
|
position: SimpleConstraintSystemConstraintPosition,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
isDispatch: Boolean,
|
isDispatch: Boolean,
|
||||||
nullableExpectedType: ConeKotlinType,
|
|
||||||
sink: CheckerSink
|
sink: CheckerSink
|
||||||
) {
|
) {
|
||||||
if (isReceiver && isDispatch) {
|
if (isReceiver && isDispatch) {
|
||||||
@@ -252,6 +268,9 @@ private fun checkApplicabilityForArgumentType(
|
|||||||
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val nullableExpectedType = expectedType.withNullability(ConeNullability.NULLABLE, sink.components.session.inferenceContext)
|
||||||
|
|
||||||
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
|
if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, nullableExpectedType, position)) {
|
||||||
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
|
sink.reportApplicability(CandidateApplicability.WRONG_RECEIVER) // TODO
|
||||||
} else {
|
} else {
|
||||||
@@ -277,8 +296,7 @@ internal fun Candidate.resolveArgument(
|
|||||||
parameter.returnTypeRef,
|
parameter.returnTypeRef,
|
||||||
sink,
|
sink,
|
||||||
isReceiver,
|
isReceiver,
|
||||||
false,
|
false
|
||||||
isSafeCall
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(statement: Fir
|
|||||||
when (statement) {
|
when (statement) {
|
||||||
is FirFunctionCall, is FirQualifiedAccessExpression, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, is FirCallableReferenceAccess ->
|
is FirFunctionCall, is FirQualifiedAccessExpression, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, is FirCallableReferenceAccess ->
|
||||||
(statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
(statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) }
|
||||||
|
is FirSafeCallExpression -> addSubsystemFromExpression(statement.regularQualifiedAccess)
|
||||||
is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression)
|
is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression)
|
||||||
is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) }
|
||||||
else -> {}
|
else -> {}
|
||||||
|
|||||||
@@ -133,8 +133,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
|||||||
expectedTypeRef = explicitReceiverExpression.typeRef,
|
expectedTypeRef = explicitReceiverExpression.typeRef,
|
||||||
sink = sink,
|
sink = sink,
|
||||||
isReceiver = true,
|
isReceiver = true,
|
||||||
isDispatch = this is Dispatch,
|
isDispatch = this is Dispatch
|
||||||
isSafeCall = callInfo.isSafeCall
|
|
||||||
)
|
)
|
||||||
sink.yieldIfNeed()
|
sink.yieldIfNeed()
|
||||||
} else {
|
} else {
|
||||||
@@ -146,8 +145,7 @@ internal sealed class CheckReceivers : ResolutionStage() {
|
|||||||
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type),
|
expectedType = candidate.substitutor.substituteOrSelf(expectedReceiverType.type),
|
||||||
sink = sink,
|
sink = sink,
|
||||||
isReceiver = true,
|
isReceiver = true,
|
||||||
isDispatch = this is Dispatch,
|
isDispatch = this is Dispatch
|
||||||
isSafeCall = callInfo.isSafeCall
|
|
||||||
)
|
)
|
||||||
sink.yieldIfNeed()
|
sink.yieldIfNeed()
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -259,6 +259,10 @@ class ConstraintSystemCompleter(private val components: BodyResolveComponents) {
|
|||||||
this.arguments.forEach { it.processAllContainingCallCandidates(processBlocks, processor) }
|
this.arguments.forEach { it.processAllContainingCallCandidates(processBlocks, processor) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is FirSafeCallExpression -> {
|
||||||
|
this.regularQualifiedAccess.processAllContainingCallCandidates(processBlocks, processor)
|
||||||
|
}
|
||||||
|
|
||||||
is FirWhenExpression -> {
|
is FirWhenExpression -> {
|
||||||
processCandidateIfApplicable(processor, processBlocks)
|
processCandidateIfApplicable(processor, processBlocks)
|
||||||
this.branches.forEach { it.result.processAllContainingCallCandidates(processBlocks, processor) }
|
this.branches.forEach { it.result.processAllContainingCallCandidates(processBlocks, processor) }
|
||||||
|
|||||||
+2
-3
@@ -145,8 +145,7 @@ class PostponedArgumentsAnalyzer(
|
|||||||
lambda.atom.returnTypeRef, // TODO: proper ref
|
lambda.atom.returnTypeRef, // TODO: proper ref
|
||||||
checkerSink,
|
checkerSink,
|
||||||
isReceiver = false,
|
isReceiver = false,
|
||||||
isDispatch = false,
|
isDispatch = false
|
||||||
isSafeCall = false
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,4 +192,4 @@ fun LambdaWithTypeVariableAsExpectedTypeAtom.transformToResolvedLambda(
|
|||||||
) as ResolvedLambdaAtom
|
) as ResolvedLambdaAtom
|
||||||
analyzed = true
|
analyzed = true
|
||||||
return resolvedAtom
|
return resolvedAtom
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-2
@@ -5,13 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildVarargArgumentsExpression
|
import org.jetbrains.kotlin.fir.expressions.builder.buildVarargArgumentsExpression
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedCallableReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
|
import org.jetbrains.kotlin.fir.resolve.calls.varargElementType
|
||||||
@@ -19,8 +21,10 @@ import org.jetbrains.kotlin.fir.resolve.constructFunctionalTypeRef
|
|||||||
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
|
import org.jetbrains.kotlin.fir.resolve.inference.isSuspendFunctionType
|
||||||
import org.jetbrains.kotlin.fir.resolve.inference.returnType
|
import org.jetbrains.kotlin.fir.resolve.inference.returnType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.propagateTypeFromQualifiedAccessAfterNullCheck
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperatorCall
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
@@ -59,7 +63,8 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
val typeRef = if (declaration is FirTypedDeclaration) {
|
val typeRef = if (declaration is FirTypedDeclaration) {
|
||||||
typeCalculator.tryCalculateReturnType(declaration).let {
|
typeCalculator.tryCalculateReturnType(declaration).let {
|
||||||
if (qualifiedAccess.safe) {
|
if (qualifiedAccess.safe) {
|
||||||
val nullableType = it.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE, session.inferenceContext)
|
val nullableType =
|
||||||
|
it.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE, session.inferenceContext)
|
||||||
it.withReplacedConeType(nullableType)
|
it.withReplacedConeType(nullableType)
|
||||||
} else {
|
} else {
|
||||||
it
|
it
|
||||||
@@ -205,6 +210,22 @@ class FirCallCompletionResultsWriterTransformer(
|
|||||||
return withReplacedConeType(finalType)
|
return withReplacedConeType(finalType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformSafeCallExpression(
|
||||||
|
safeCallExpression: FirSafeCallExpression,
|
||||||
|
data: ExpectedArgumentType?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
safeCallExpression.transformRegularQualifiedAccess(
|
||||||
|
this,
|
||||||
|
data?.getExpectedType(
|
||||||
|
safeCallExpression
|
||||||
|
)?.toExpectedType()
|
||||||
|
)
|
||||||
|
|
||||||
|
safeCallExpression.propagateTypeFromQualifiedAccessAfterNullCheck(safeCallExpression.receiver, session)
|
||||||
|
|
||||||
|
return safeCallExpression.compose()
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformCallableReferenceAccess(
|
override fun transformCallableReferenceAccess(
|
||||||
callableReferenceAccess: FirCallableReferenceAccess,
|
callableReferenceAccess: FirCallableReferenceAccess,
|
||||||
data: ExpectedArgumentType?,
|
data: ExpectedArgumentType?,
|
||||||
|
|||||||
+15
-2
@@ -7,12 +7,14 @@ package org.jetbrains.kotlin.fir.resolve.transformers
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirImplementationDetail
|
import org.jetbrains.kotlin.fir.FirImplementationDetail
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.propagateTypeFromOriginalReceiver
|
||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||||
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator
|
||||||
@@ -31,7 +33,8 @@ import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|||||||
|
|
||||||
class IntegerLiteralTypeApproximationTransformer(
|
class IntegerLiteralTypeApproximationTransformer(
|
||||||
private val symbolProvider: FirSymbolProvider,
|
private val symbolProvider: FirSymbolProvider,
|
||||||
private val inferenceContext: ConeInferenceContext
|
private val inferenceContext: ConeInferenceContext,
|
||||||
|
private val session: FirSession
|
||||||
) : FirTransformer<ConeKotlinType?>() {
|
) : FirTransformer<ConeKotlinType?>() {
|
||||||
override fun <E : FirElement> transformElement(element: E, data: ConeKotlinType?): CompositeTransformResult<E> {
|
override fun <E : FirElement> transformElement(element: E, data: ConeKotlinType?): CompositeTransformResult<E> {
|
||||||
return element.compose()
|
return element.compose()
|
||||||
@@ -127,6 +130,16 @@ class IntegerLiteralTypeApproximationTransformer(
|
|||||||
typeOperatorCall.argumentList.transformArguments(this, null)
|
typeOperatorCall.argumentList.transformArguments(this, null)
|
||||||
return typeOperatorCall.compose()
|
return typeOperatorCall.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformCheckedSafeCallSubject(
|
||||||
|
checkedSafeCallSubject: FirCheckedSafeCallSubject,
|
||||||
|
data: ConeKotlinType?
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
val newReceiver =
|
||||||
|
checkedSafeCallSubject.originalReceiverReference.value.transform<FirExpression, ConeKotlinType?>(this, data).single
|
||||||
|
checkedSafeCallSubject.propagateTypeFromOriginalReceiver(newReceiver, session)
|
||||||
|
return super.transformCheckedSafeCallSubject(checkedSafeCallSubject, data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration<*>? {
|
fun FirFunctionCall.getOriginalFunction(): FirCallableDeclaration<*>? {
|
||||||
@@ -217,4 +230,4 @@ private fun FirFunctionCall.toOperatorCall(): FirIntegerOperatorCall {
|
|||||||
argumentList,
|
argumentList,
|
||||||
calleeReference,
|
calleeReference,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -289,7 +289,7 @@ abstract class FirAbstractBodyResolveTransformer(phase: FirResolvePhase) : FirAb
|
|||||||
FirDataFlowAnalyzer.createFirDataFlowAnalyzer(this, context.dataFlowAnalyzerContext)
|
FirDataFlowAnalyzer.createFirDataFlowAnalyzer(this, context.dataFlowAnalyzerContext)
|
||||||
override val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this)
|
override val syntheticCallGenerator: FirSyntheticCallGenerator = FirSyntheticCallGenerator(this)
|
||||||
override val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer =
|
override val integerLiteralTypeApproximator: IntegerLiteralTypeApproximationTransformer =
|
||||||
IntegerLiteralTypeApproximationTransformer(symbolProvider, inferenceComponents.ctx)
|
IntegerLiteralTypeApproximationTransformer(symbolProvider, inferenceComponents.ctx, inferenceComponents.session)
|
||||||
override val doubleColonExpressionResolver: FirDoubleColonExpressionResolver =
|
override val doubleColonExpressionResolver: FirDoubleColonExpressionResolver =
|
||||||
FirDoubleColonExpressionResolver(session, integerLiteralTypeApproximator)
|
FirDoubleColonExpressionResolver(session, integerLiteralTypeApproximator)
|
||||||
override val integerOperatorsTypeUpdater: IntegerOperatorsTypeUpdater = IntegerOperatorsTypeUpdater(integerLiteralTypeApproximator)
|
override val integerOperatorsTypeUpdater: IntegerOperatorsTypeUpdater = IntegerOperatorsTypeUpdater(integerLiteralTypeApproximator)
|
||||||
|
|||||||
+14
@@ -189,6 +189,20 @@ open class FirBodyResolveTransformer(
|
|||||||
return expressionsTransformer.transformAugmentedArraySetCall(augmentedArraySetCall, data)
|
return expressionsTransformer.transformAugmentedArraySetCall(augmentedArraySetCall, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformSafeCallExpression(
|
||||||
|
safeCallExpression: FirSafeCallExpression,
|
||||||
|
data: ResolutionMode
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
return expressionsTransformer.transformSafeCallExpression(safeCallExpression, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformCheckedSafeCallSubject(
|
||||||
|
checkedSafeCallSubject: FirCheckedSafeCallSubject,
|
||||||
|
data: ResolutionMode
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
return expressionsTransformer.transformCheckedSafeCallSubject(checkedSafeCallSubject, data)
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------- Declarations -------------------------------------
|
// ------------------------------------- Declarations -------------------------------------
|
||||||
|
|
||||||
override fun transformDeclaration(declaration: FirDeclaration, data: ResolutionMode): CompositeTransformResult<FirDeclaration> {
|
override fun transformDeclaration(declaration: FirDeclaration, data: ResolutionMode): CompositeTransformResult<FirDeclaration> {
|
||||||
|
|||||||
+31
-1
@@ -13,7 +13,9 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
|||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.*
|
import org.jetbrains.kotlin.fir.expressions.builder.buildErrorExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.builder.buildVariableAssignment
|
||||||
import org.jetbrains.kotlin.fir.references.*
|
import org.jetbrains.kotlin.fir.references.*
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference
|
import org.jetbrains.kotlin.fir.references.builder.buildExplicitSuperReference
|
||||||
@@ -164,6 +166,34 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
|||||||
return result.compose()
|
return result.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformSafeCallExpression(
|
||||||
|
safeCallExpression: FirSafeCallExpression,
|
||||||
|
data: ResolutionMode
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
safeCallExpression.transformReceiver(this, ResolutionMode.ContextIndependent)
|
||||||
|
|
||||||
|
val receiver = safeCallExpression.receiver
|
||||||
|
|
||||||
|
dataFlowAnalyzer.enterSafeCallAfterNullCheck(safeCallExpression)
|
||||||
|
|
||||||
|
safeCallExpression.apply {
|
||||||
|
checkedSubject.value.propagateTypeFromOriginalReceiver(receiver, components.session)
|
||||||
|
transformRegularQualifiedAccess(this@FirExpressionsResolveTransformer, data)
|
||||||
|
propagateTypeFromQualifiedAccessAfterNullCheck(receiver, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataFlowAnalyzer.exitSafeCall(safeCallExpression)
|
||||||
|
|
||||||
|
return safeCallExpression.compose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformCheckedSafeCallSubject(
|
||||||
|
checkedSafeCallSubject: FirCheckedSafeCallSubject,
|
||||||
|
data: ResolutionMode
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
return checkedSafeCallSubject.compose()
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformFunctionCall(functionCall: FirFunctionCall, data: ResolutionMode): CompositeTransformResult<FirStatement> {
|
override fun transformFunctionCall(functionCall: FirFunctionCall, data: ResolutionMode): CompositeTransformResult<FirStatement> {
|
||||||
if (functionCall.calleeReference is FirResolvedNamedReference && functionCall.resultType is FirImplicitTypeRef) {
|
if (functionCall.calleeReference is FirResolvedNamedReference && functionCall.resultType is FirImplicitTypeRef) {
|
||||||
storeTypeFromCallee(functionCall)
|
storeTypeFromCallee(functionCall)
|
||||||
|
|||||||
Reference in New Issue
Block a user