diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 8ac16c5742f..900ddf807b4 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -24181,6 +24181,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt"); } + @Test + @TestMetadata("noTypeArgumentsForRawScopedMembers.kt") + public void testNoTypeArgumentsForRawScopedMembers() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt"); + } + @Test @TestMetadata("nonGenericRawMember.kt") public void testNonGenericRawMember() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index b02e2fbbd9b..d30ee9e31ec 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -24181,6 +24181,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt"); } + @Test + @TestMetadata("noTypeArgumentsForRawScopedMembers.kt") + public void testNoTypeArgumentsForRawScopedMembers() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt"); + } + @Test @TestMetadata("nonGenericRawMember.kt") public void testNonGenericRawMember() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index c4376c68088..b760f24eecb 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -24181,6 +24181,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt"); } + @Test + @TestMetadata("noTypeArgumentsForRawScopedMembers.kt") + public void testNoTypeArgumentsForRawScopedMembers() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt"); + } + @Test @TestMetadata("nonGenericRawMember.kt") public void testNonGenericRawMember() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt index 3eb0c6594c9..8c4d3671ebe 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/TypeArgumentMapping.kt @@ -5,11 +5,17 @@ package org.jetbrains.kotlin.fir.resolve.calls +import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRefsOwner +import org.jetbrains.kotlin.fir.types.ConeTypeIntersector import org.jetbrains.kotlin.fir.types.FirTypeProjection import org.jetbrains.kotlin.fir.types.builder.buildPlaceholderProjection +import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance +import org.jetbrains.kotlin.fir.types.isRaw +import org.jetbrains.kotlin.fir.types.toFirResolvedTypeRef +import org.jetbrains.kotlin.types.Variance sealed class TypeArgumentMapping { abstract operator fun get(typeParameterIndex: Int): FirTypeProjection @@ -28,13 +34,17 @@ sealed class TypeArgumentMapping { internal object MapTypeArguments : ResolutionStage() { override suspend fun check(candidate: Candidate, callInfo: CallInfo, sink: CheckerSink, context: ResolutionContext) { val typeArguments = callInfo.typeArguments + val owner = candidate.symbol.fir as FirTypeParameterRefsOwner + if (typeArguments.isEmpty()) { - candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments + if (owner is FirCallableDeclaration && owner.dispatchReceiverType?.isRaw() == true) { + candidate.typeArgumentMapping = computeDefaultMappingForRawTypeMember(owner, context) + } else { + candidate.typeArgumentMapping = TypeArgumentMapping.NoExplicitArguments + } return } - val owner = candidate.symbol.fir as FirTypeParameterRefsOwner - if ( typeArguments.size == owner.typeParameters.size || callInfo.callKind == CallKind.DelegatingConstructorCall || @@ -46,6 +56,28 @@ internal object MapTypeArguments : ResolutionStage() { sink.yieldDiagnostic(InapplicableCandidate) } } + + private fun computeDefaultMappingForRawTypeMember( + owner: FirTypeParameterRefsOwner, + context: ResolutionContext + ): TypeArgumentMapping.Mapped { + // There might be some minor inconsistencies where in K2, there might be a raw type, while in K1, there was a regular flexible type + // And in that case for K2 we would start a regular inference process leads to TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER because raw scopes + // don't leave type variables there (see KT-54526) + // Also, it might be a separate feature of K2, because even in cases where both compilers had a raw type, it's convenient not to + // require explicit type arguments for the places where it doesn't make sense + // (See `generic1.foo(w)` call in testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.fir.kt) + val resultArguments = owner.typeParameters.map { typeParameterRef -> + buildTypeProjectionWithVariance { + typeRef = + ConeTypeIntersector.intersectTypes( + context.typeContext, typeParameterRef.symbol.resolvedBounds.map { it.type } + ).toFirResolvedTypeRef() + variance = Variance.INVARIANT + } + } + return TypeArgumentMapping.Mapped(resultArguments) + } } internal object NoTypeArguments : ResolutionStage() { diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.fir.kt new file mode 100644 index 00000000000..42068527ad4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.fir.kt @@ -0,0 +1,23 @@ +// SKIP_TXT +// FILE: Generic.java +public class Generic { + public static class ML {} + public static Generic create() { return null; } + public void foo(ML w) { } +} + +// FILE: main.kt +import Generic.ML + +fun main(w: ML) { + val generic1 = Generic.create() + val generic2 = Generic.create() ?: return + + // Not enough information to infer E (both K1 and K2 after KT-41794 is done) + // Because generic information is erased from the raw type scope of `generic1` + // But the parameter E is still there (that is a questionable behavior) + generic1.foo(w) + + // `generic2` does have just non-raw type `Generic..Generic<*>?` + generic2.foo(w) // OK in K1, fails in K2 after KT-41794 is done +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt new file mode 100644 index 00000000000..32b6463d8c5 --- /dev/null +++ b/compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt @@ -0,0 +1,23 @@ +// SKIP_TXT +// FILE: Generic.java +public class Generic { + public static class ML {} + public static Generic create() { return null; } + public void foo(ML w) { } +} + +// FILE: main.kt +import Generic.ML + +fun main(w: ML) { + val generic1 = Generic.create() + val generic2 = Generic.create() ?: return + + // Not enough information to infer E (both K1 and K2 after KT-41794 is done) + // Because generic information is erased from the raw type scope of `generic1` + // But the parameter E is still there (that is a questionable behavior) + generic1.foo(w) + + // `generic2` does have just non-raw type `Generic..Generic<*>?` + generic2.foo(w) // OK in K1, fails in K2 after KT-41794 is done +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index d7acdf3d690..2c13a959e54 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -24187,6 +24187,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/kt47459.kt"); } + @Test + @TestMetadata("noTypeArgumentsForRawScopedMembers.kt") + public void testNoTypeArgumentsForRawScopedMembers() throws Exception { + runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/noTypeArgumentsForRawScopedMembers.kt"); + } + @Test @TestMetadata("nonGenericRawMember.kt") public void testNonGenericRawMember() throws Exception {