From 14108011eefff320696313a9972c54e8d083627c Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Wed, 20 Jan 2021 14:03:14 +0300 Subject: [PATCH] [FIR] Fix inferring arguments of bare types in different situations - argument type is flexible - supertype has flexible type argument - type of expression is more specific than bare type --- ...TouchedTilContractsPhaseTestGenerated.java | 10 ++++++ .../testData/resolve/bareTypes2.fir.txt | 32 +++++++++++++++++++ .../testData/resolve/bareTypes2.kt | 25 +++++++++++++++ .../bareTypesWithFlexibleArguments.fir.txt | 11 +++++++ .../resolve/bareTypesWithFlexibleArguments.kt | 10 ++++++ .../runners/FirDiagnosticTestGenerated.java | 12 +++++++ ...DiagnosticsWithLightTreeTestGenerated.java | 12 +++++++ .../FirExpressionsResolveTransformer.kt | 25 +++++++++++---- 8 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 compiler/fir/analysis-tests/testData/resolve/bareTypes2.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt create mode 100644 compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.fir.txt create mode 100644 compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java index 8520639a6dc..cf7e0629eb3 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/LazyBodyIsNotTouchedTilContractsPhaseTestGenerated.java @@ -39,6 +39,16 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt"); } + @TestMetadata("bareTypes2.kt") + public void testBareTypes2() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt"); + } + + @TestMetadata("bareTypesWithFlexibleArguments.kt") + public void testBareTypesWithFlexibleArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt"); + } + @TestMetadata("cast.kt") public void testCast() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/cast.kt"); diff --git a/compiler/fir/analysis-tests/testData/resolve/bareTypes2.fir.txt b/compiler/fir/analysis-tests/testData/resolve/bareTypes2.fir.txt new file mode 100644 index 00000000000..bbec9d8c0e3 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/bareTypes2.fir.txt @@ -0,0 +1,32 @@ +FILE: bareTypes2.kt + public abstract interface A|> : R|kotlin/Any| { + public abstract fun foo(): R|kotlin/Any| + + public abstract val cond: R|kotlin/Boolean| + public get(): R|kotlin/Boolean| + + public abstract val field: R|kotlin/Any| + public get(): R|kotlin/Any| + + } + public abstract interface B|> : R|A| { + public abstract override fun foo(): R|kotlin/CharSequence| + + } + public abstract interface C : R|B| { + public abstract override fun foo(): R|kotlin/String| + + } + public final fun test(x: R|A<*>|): R|kotlin/Unit| { + when ((R|/x| as? R|C|)?.{ $subj$.R|/A.field| }) { + ($subj$ is R|kotlin/String|) -> { + when () { + ==((R|/x| as? R|B|)?.{ $subj$.R|/A.cond| }, Boolean(true)) -> { + R|/x|.R|/C.foo|() + } + } + + } + } + + } diff --git a/compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt b/compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt new file mode 100644 index 00000000000..4193632c6b6 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt @@ -0,0 +1,25 @@ +interface A> { + fun foo(): Any + + val cond: Boolean + val field: Any +} + +interface B> : A { + override fun foo(): CharSequence +} + +interface C : B { + override fun foo(): String +} + +fun test(x: A<*>) { + when ((x as? C)?.field) { + is String -> { + if ((x as? B)?.cond == true) { + x.foo() + } + } + } + +} diff --git a/compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.fir.txt b/compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.fir.txt new file mode 100644 index 00000000000..e941ae5c122 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.fir.txt @@ -0,0 +1,11 @@ +FILE: bareTypesWithFlexibleArguments.kt + public final fun R|kotlin/collections/Collection?|.concat(collection: R|kotlin/collections/Collection|): R|kotlin/collections/Collection?| { + when () { + (this@R|/concat| is R|kotlin/collections/LinkedHashSet|) -> { + this@R|/concat|.R|SubstitutionOverride|(R|/collection|) + ^concat this@R|/concat| + } + } + + ^concat this@R|/concat| + } diff --git a/compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt b/compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt new file mode 100644 index 00000000000..837d08fc8ad --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt @@ -0,0 +1,10 @@ +// WITH_STDLIB +// FULL_JDK + +fun Collection?.concat(collection: Collection): Collection? { + if (this is LinkedHashSet) { + addAll(collection) + return this + } + return this +} diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java index adb9a067766..64a33e4f967 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticTestGenerated.java @@ -38,6 +38,18 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest { runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt"); } + @Test + @TestMetadata("bareTypes2.kt") + public void testBareTypes2() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt"); + } + + @Test + @TestMetadata("bareTypesWithFlexibleArguments.kt") + public void testBareTypesWithFlexibleArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt"); + } + @Test @TestMetadata("cast.kt") public void testCast() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java index d4e136ce4e9..a53aadfc92c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirDiagnosticsWithLightTreeTestGenerated.java @@ -39,6 +39,18 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes.kt"); } + @Test + @TestMetadata("bareTypes2.kt") + public void testBareTypes2() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/bareTypes2.kt"); + } + + @Test + @TestMetadata("bareTypesWithFlexibleArguments.kt") + public void testBareTypesWithFlexibleArguments() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/bareTypesWithFlexibleArguments.kt"); + } + @Test @TestMetadata("cast.kt") public void testCast() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 0f18e0da2d8..2c35bf21862 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.fir.types.builder.* import org.jetbrains.kotlin.fir.visitors.* import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability +import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.types.TypeApproximatorConfiguration @@ -473,7 +474,10 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform val type = typeRef.coneTypeSafe() ?: return null val indexMapping = typeParameters.map { parameter -> // TODO: if many, check consistency of the result - type.typeArguments.indexOfFirst { it is ConeTypeParameterType && it.lookupTag.typeParameterSymbol == parameter.symbol } + type.typeArguments.indexOfFirst { + val argument = (it as? ConeKotlinType)?.lowerBoundIfFlexible() + argument is ConeTypeParameterType && argument.lookupTag.typeParameterSymbol == parameter.symbol + } } if (indexMapping.any { it == -1 }) return null @@ -488,14 +492,23 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform val firClass = type.lookupTag.toSymbol(session)?.fir ?: return this if (firClass !is FirTypeParameterRefsOwner || firClass.typeParameters.isEmpty()) return this - val baseType = argument.typeRef.coneTypeSafe()?.fullyExpandedType(session) ?: return this + val baseType = argument.typeRef.coneTypeSafe()?.lowerBoundIfFlexible()?.fullyExpandedType(session) ?: return this + if (baseType !is ConeClassLikeType) return this val baseFirClass = baseType.lookupTag.toSymbol(session)?.fir ?: return this - val newArguments = type.inheritTypeArguments(baseFirClass, baseType.typeArguments) - ?: return buildErrorTypeRef { - source = this@withTypeArgumentsForBareType.source - diagnostic = ConeWrongNumberOfTypeArgumentsError(firClass.typeParameters.size, firClass.symbol) + val newArguments = if (AbstractTypeChecker.isSubtypeOfClass(session.typeCheckerContext, baseType.lookupTag, type.lookupTag)) { + // If actual type of declaration is more specific than bare type then we should just find + // corresponding supertype with proper arguments + with(session.typeContext) { + val superType = baseType.fastCorrespondingSupertypes(type.lookupTag)?.firstOrNull() as? ConeKotlinType? + superType?.typeArguments } + } else { + type.inheritTypeArguments(baseFirClass, baseType.typeArguments) + } ?: return buildErrorTypeRef { + source = this@withTypeArgumentsForBareType.source + diagnostic = ConeWrongNumberOfTypeArgumentsError(firClass.typeParameters.size, firClass.symbol) + } return if (newArguments.isEmpty()) this else withReplacedConeType(type.withArguments(newArguments)) } -- GitLab