diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt index bb9860361d5..146c46de40c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/Arguments.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe import org.jetbrains.kotlin.fir.resolve.withNullability import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder @@ -37,7 +38,8 @@ fun resolveArgumentExpression( typeProvider: (FirExpression) -> FirTypeRef? ) { return when (argument) { - is FirQualifiedAccessExpression, is FirFunctionCall -> resolvePlainExpressionArgument( + is FirFunctionCall -> resolveSubCallArgument(csBuilder, argument, expectedType, sink, isReceiver, isSafeCall, typeProvider) + is FirQualifiedAccessExpression -> resolvePlainExpressionArgument( csBuilder, argument, expectedType, @@ -78,6 +80,21 @@ fun resolveArgumentExpression( } } +fun resolveSubCallArgument( + csBuilder: ConstraintSystemBuilder, + argument: FirFunctionCall, + expectedType: ConeKotlinType, + sink: CheckerSink, + isReceiver: Boolean, + isSafeCall: Boolean, + typeProvider: (FirExpression) -> FirTypeRef? +) { + val candidate = argument.candidate() ?: return resolvePlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, isSafeCall, typeProvider) + val type = sink.components.returnTypeCalculator.tryCalculateReturnType(candidate.symbol.firUnsafe()).coneTypeUnsafe() + val argumentType = candidate.substitutor.substituteOrSelf(type) + resolvePlainArgumentType(csBuilder, argumentType, expectedType, sink, isReceiver, isSafeCall) +} + fun resolvePlainExpressionArgument( csBuilder: ConstraintSystemBuilder, argument: FirExpression, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index db10af18edc..ee99193c61d 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt @@ -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.FirWrappedArgumentExpression import org.jetbrains.kotlin.fir.symbols.ConeSymbol import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage @@ -40,6 +41,7 @@ class CandidateFactory( fun PostponedArgumentsAnalyzer.Context.addSubsystemFromExpression(expression: FirExpression) { when (expression) { is FirFunctionCall -> expression.candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) } + is FirWrappedArgumentExpression -> addSubsystemFromExpression(expression.expression) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceCompletion.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceCompletion.kt index 03f105fcb3b..4f8dd5ab062 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceCompletion.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceCompletion.kt @@ -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.FirWrappedArgumentExpression import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter @@ -36,23 +37,41 @@ fun Candidate.computeCompletionMode( return when { // Consider call foo(bar(x)), if return type of bar is a proper one, then we can complete resolve for bar => full completion mode // Otherwise, we shouldn't complete bar until we process call foo - system.getBuilder().isProperType(currentReturnType) -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL + csBuilder.isProperType(currentReturnType) -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL // Nested call is connected with the outer one through the UPPER constraint (returnType <: expectedOuterType) // This means that there will be no new LOWER constraints => // it's possible to complete call now if there are proper LOWER constraints - system.getBuilder().isTypeVariable(currentReturnType) -> + csBuilder.isTypeVariable(currentReturnType) -> if (hasProperNonTrivialLowerConstraints(components, currentReturnType)) KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL else KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL + // Return type has proper equal constraints => there is no need in the outer call + containsTypeVariablesWithProperEqualConstraints(components, currentReturnType) -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL + else -> KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL } } val Candidate.csBuilder get() = system.getBuilder() +private fun Candidate.containsTypeVariablesWithProperEqualConstraints(components: InferenceComponents, type: ConeKotlinType): Boolean = + with(components.ctx){ + for ((variableConstructor, variableWithConstraints) in csBuilder.currentStorage().notFixedTypeVariables) { + if (!type.contains { it.typeConstructor() == variableConstructor }) continue + + val constraints = variableWithConstraints.constraints + val onlyProperEqualConstraints = + constraints.isNotEmpty() && constraints.all { it.kind.isEqual() && csBuilder.isProperType(it.type) } + + if (!onlyProperEqualConstraints) return false + } + + return true + } + private fun Candidate.hasProperNonTrivialLowerConstraints(components: InferenceComponents, typeVariable: ConeKotlinType): Boolean { assert(csBuilder.isTypeVariable(typeVariable)) { "$typeVariable is not a type variable" } @@ -162,6 +181,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) { } this.arguments.forEach { it.process(to) } } + is FirWrappedArgumentExpression -> this.expression.process(to) // TOOD: WTF? } // if (analyzed) { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceUtil.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceUtil.kt index cda03ac283b..bf57c000110 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceUtil.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/InferenceUtil.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.resolve.calls import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.resolve.* +import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator import org.jetbrains.kotlin.fir.symbols.* import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol import org.jetbrains.kotlin.fir.types.* @@ -45,7 +46,7 @@ open class ConeTypeVariable(name: String) : TypeVariableMarker { val defaultType = ConeTypeVariableType(ConeNullability.NOT_NULL, typeConstructor) } -class InferenceComponents(val ctx: TypeSystemInferenceExtensionContextDelegate, val session: FirSession) { +class InferenceComponents(val ctx: TypeSystemInferenceExtensionContextDelegate, val session: FirSession, val returnTypeCalculator: ReturnTypeCalculator) { private val approximator = object : AbstractTypeApproximator(ctx) { override fun createErrorType(message: String): SimpleTypeMarker { return ConeClassErrorType(message) @@ -59,5 +60,6 @@ class InferenceComponents(val ctx: TypeSystemInferenceExtensionContextDelegate, fun createConstraintSystem(): NewConstraintSystemImpl { return NewConstraintSystemImpl(injector, ctx) } + } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index aa46a19451d..9ca4df21a7e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -255,7 +255,7 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker { return this } - }, session) + }, session, jump) private var qualifierStack = mutableListOf() private var qualifierPartsToDrop = 0 diff --git a/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.kt b/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.kt new file mode 100644 index 00000000000..3e97c622ef1 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.kt @@ -0,0 +1,16 @@ +fun testPlus() { + val x = 1 + 2 + val y = 3.0 + 4.0 + val z = 5 + 6.0 + val w = 7.0 + 8 + val c = 'a' + 1 + val s = "." + ".." + val ss = "" + 1 + val list = listOf(1, 2, 3) + 4 + val listAndList = listOf(4, 5, 6) + listOf(7, 8) + val mutableList = mutableListOf(9, 10) + listOf(11, 12, 13) + val setAndList = setOf(0) + listOf(1, 2) + val stringAndList = "" + emptyList() + val map = mapOf("" to 1, "." to 2) + (".." to 3) + val mapAndMap = mapOf("-" to 4) + mapOf("_" to 5) +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt b/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt new file mode 100644 index 00000000000..70ec9d44799 --- /dev/null +++ b/compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.txt @@ -0,0 +1,17 @@ +FILE: topLevelResolve.kt + public final fun testPlus(): R|kotlin/Unit| { + lval x: R|kotlin/Int| = Int(1).R|kotlin/Int.plus|(Int(2)) + lval y: R|kotlin/Double| = Double(3.0).R|kotlin/Double.plus|(Double(4.0)) + lval z: R|kotlin/Double| = Int(5).R|kotlin/Int.plus|(Double(6.0)) + lval w: R|kotlin/Double| = Double(7.0).R|kotlin/Double.plus|(Int(8)) + lval c: R|kotlin/Char| = Char(a).R|kotlin/Char.plus|(Int(1)) + lval s: R|kotlin/String| = String(.).R|kotlin/String.plus|(String(..)) + lval ss: R|kotlin/String| = String().R|kotlin/String.plus|(Int(1)) + lval list: R|kotlin/collections/List| = R|kotlin/collections/listOf|(Int(1), Int(2), Int(3)).R|kotlin/collections/plus|(Int(4)) + lval listAndList: R|kotlin/collections/List| = R|kotlin/collections/listOf|(Int(4), Int(5), Int(6)).R|kotlin/collections/plus|(R|kotlin/collections/listOf|(Int(7), Int(8))) + lval mutableList: R|kotlin/collections/List| = R|kotlin/collections/mutableListOf|(Int(9), Int(10)).R|kotlin/collections/plus|(R|kotlin/collections/listOf|(Int(11), Int(12), Int(13))) + lval setAndList: R|kotlin/collections/Set| = R|kotlin/collections/setOf|(Int(0)).R|kotlin/collections/plus|(R|kotlin/collections/listOf|(Int(1), Int(2))) + lval stringAndList: R|kotlin/String| = String().R|kotlin/String.plus|(R|kotlin/collections/emptyList|()) + lval map: R|kotlin/collections/Map| = R|kotlin/collections/mapOf|(String().R|kotlin/to|(Int(1)), String(.).R|kotlin/to|(Int(2))).R|kotlin/collections/plus|(String(..).R|kotlin/to|(Int(3))) + lval mapAndMap: = #(String(-).R|kotlin/to|(Int(4))).#(#(String(_).R|kotlin/to|(Int(5)))) + } diff --git a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java index 7e4d8999ab1..08c86d070bb 100644 --- a/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java +++ b/compiler/fir/resolve/tests/org/jetbrains/kotlin/fir/FirResolveTestCaseWithStdlibGenerated.java @@ -79,6 +79,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt"); } + @TestMetadata("topLevelResolve.kt") + public void testTopLevelResolve() throws Exception { + runTest("compiler/fir/resolve/testData/resolve/stdlib/topLevelResolve.kt"); + } + @TestMetadata("typeAliasDeserialization.kt") public void testTypeAliasDeserialization() throws Exception { runTest("compiler/fir/resolve/testData/resolve/stdlib/typeAliasDeserialization.kt"); diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt index fdff56af3b9..379b4084f64 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/NewConstraintSystemImpl.kt @@ -179,8 +179,8 @@ class NewConstraintSystemImpl( return !type.contains { val capturedType = it.asSimpleType()?.asCapturedType() // TODO: change NewCapturedType to markered one for FE-IR - val typeToCheck = if (capturedType is NewCapturedType && capturedType.captureStatus() == CaptureStatus.FROM_EXPRESSION) - capturedType.constructor.projection.type + val typeToCheck = if (capturedType is CapturedTypeMarker && capturedType.captureStatus() == CaptureStatus.FROM_EXPRESSION) + capturedType.typeConstructorProjection().getType() else it diff --git a/compiler/testData/ir/irText/types/intersectionType1.fir.txt b/compiler/testData/ir/irText/types/intersectionType1.fir.txt index b2757bcda01..8a7d3e684ad 100644 --- a/compiler/testData/ir/irText/types/intersectionType1.fir.txt +++ b/compiler/testData/ir/irText/types/intersectionType1.fir.txt @@ -43,14 +43,15 @@ FILE fqName: fileName:/intersectionType1.kt GET_VAR 'y: kotlin.Any? declared in .ofType' type=kotlin.Any? origin=null FUN name:test visibility:public modality:FINAL <> () returnType:kotlin.Unit BLOCK_BODY - VAR name:a1 type:kotlin.Array [val] - CALL 'public final fun arrayOf (elements: kotlin.Array>): kotlin.Array> [inline] declared in kotlin' type=kotlin.Array origin=null + VAR name:a1 type:kotlin.Array<.In> [val] + CALL 'public final fun arrayOf (elements: kotlin.Array>): kotlin.Array> [inline] declared in kotlin' type=kotlin.Array<.In> origin=null elements: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .In' type=.In origin=null : - VAR name:a2 type:kotlin.Array [val] - CALL 'public final fun arrayOf (elements: kotlin.Array>): kotlin.Array> [inline] declared in kotlin' type=kotlin.Array origin=null + VAR name:a2 type:kotlin.Array<.In> [val] + CALL 'public final fun arrayOf (elements: kotlin.Array>): kotlin.Array> [inline] declared in kotlin' type=kotlin.Array<.In> origin=null elements: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .In' type=.In origin=null : - ERROR_CALL 'Unresolved reference: #' type=IrErrorType - GET_VAR 'val a1: kotlin.Array [val] declared in .test' type=kotlin.Array origin=null - GET_VAR 'val a2: kotlin.Array [val] declared in .test' type=kotlin.Array origin=null + CALL 'public final fun foo (a: kotlin.Array<.In.foo>>, b: kotlin.Array<.In>): kotlin.Boolean declared in ' type=kotlin.Boolean origin=null + : + a: GET_VAR 'val a1: kotlin.Array<.In> [val] declared in .test' type=kotlin.Array<.In> origin=null + b: GET_VAR 'val a2: kotlin.Array<.In> [val] declared in .test' type=kotlin.Array<.In> origin=null