From e3721ed40637cede60e7c55ee299adb8ecf4db37 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 10 Feb 2020 10:56:59 +0300 Subject: [PATCH] [FIR] Implement bare type modification with known type arguments --- .../FirExpressionsResolveTransformer.kt | 42 +++++++++++++++---- .../testData/resolve/problems/bareTypes.kt | 16 ++++++- .../testData/resolve/problems/bareTypes.txt | 19 ++++++++- .../recursiveCallOnWhenWithSealedClass.txt | 6 +-- .../tests/cast/bare/AsNullable.fir.kt | 2 +- .../tests/cast/bare/EitherAs.fir.kt | 2 +- .../tests/cast/bare/EitherIs.fir.kt | 2 +- .../tests/cast/bare/EitherNotIs.fir.kt | 2 +- .../tests/cast/bare/EitherSafeAs.fir.kt | 2 +- .../tests/cast/bare/EitherWhen.fir.kt | 2 +- .../tests/cast/bare/NullableAs.fir.kt | 2 +- .../tests/cast/bare/NullableAsNullable.fir.kt | 2 +- .../inference/nothingType/kt32388.fir.kt | 2 +- .../classGenericsInParamsBoundMismatch.fir.kt | 2 +- 14 files changed, 79 insertions(+), 24 deletions(-) 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 3d51945b0f3..f53e52719f2 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 @@ -37,9 +37,7 @@ import org.jetbrains.kotlin.fir.symbols.invoke import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.* import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl -import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult -import org.jetbrains.kotlin.fir.visitors.compose -import org.jetbrains.kotlin.fir.visitors.transformSingle +import org.jetbrains.kotlin.fir.visitors.* import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.Variance @@ -282,31 +280,59 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : throw IllegalArgumentException(operatorCall.render()) } + private fun FirTypeRef.withTypeArgumentsForBareType(argument: FirExpression): FirTypeRef { + val baseTypeArguments = argument.typeRef.coneTypeSafe()?.typeArguments + val type = coneTypeSafe() + return if (type?.typeArguments?.isEmpty() != true || + type is ConeTypeParameterType || + baseTypeArguments?.isEmpty() != false || + (type is ConeClassLikeType && + (type.lookupTag.toSymbol(session)?.fir as? FirTypeParametersOwner)?.typeParameters?.isEmpty() == true) + ) { + this + } else { + withReplacedConeType(type.withArguments(baseTypeArguments)) + } + } + override fun transformTypeOperatorCall( typeOperatorCall: FirTypeOperatorCall, data: ResolutionMode, ): CompositeTransformResult { - val symbolProvider = session.firSymbolProvider val resolved = (transformExpression(typeOperatorCall, data).single as FirTypeOperatorCall) .transformArguments(integerLiteralTypeApproximator, null) + val conversionTypeRef = resolved.conversionTypeRef.withTypeArgumentsForBareType(resolved.argument) + resolved.transformChildren(object : FirDefaultTransformer() { + override fun transformElement(element: E, data: Nothing?): CompositeTransformResult { + return element.compose() + } + + override fun transformTypeRef(typeRef: FirTypeRef, data: Nothing?): CompositeTransformResult { + return if (typeRef === resolved.conversionTypeRef) { + conversionTypeRef.compose() + } else { + typeRef.compose() + } + } + }, null) when (resolved.operation) { FirOperation.IS, FirOperation.NOT_IS -> { resolved.resultType = session.builtinTypes.booleanType } FirOperation.AS -> { - resolved.resultType = resolved.conversionTypeRef + resolved.resultType = conversionTypeRef } FirOperation.SAFE_AS -> { resolved.resultType = - resolved.conversionTypeRef.withReplacedConeType( - resolved.conversionTypeRef.coneTypeUnsafe().withNullability( + conversionTypeRef.withReplacedConeType( + conversionTypeRef.coneTypeUnsafe().withNullability( ConeNullability.NULLABLE, session.inferenceContext, ), ) } else -> error("Unknown type operator") } - dataFlowAnalyzer.exitTypeOperatorCall(typeOperatorCall) + dataFlowAnalyzer.exitTypeOperatorCall(resolved) return resolved.transform(integerLiteralTypeApproximator, null) } diff --git a/compiler/fir/resolve/testData/resolve/problems/bareTypes.kt b/compiler/fir/resolve/testData/resolve/problems/bareTypes.kt index 5b844150b3f..0fcdba39736 100644 --- a/compiler/fir/resolve/testData/resolve/problems/bareTypes.kt +++ b/compiler/fir/resolve/testData/resolve/problems/bareTypes.kt @@ -4,6 +4,20 @@ interface MutableA : A { fun add(x: T) } +interface MutableString : MutableA + fun test(a: A) { - (a as MutableA).add("") + (a as? MutableA)?.add("") + (a as MutableA).add("") +} + +fun test2(a: A) { + val b = a as MutableString + b.add("") +} + +fun test3(a: A) { + if (a is MutableA) { + a.add("") + } } diff --git a/compiler/fir/resolve/testData/resolve/problems/bareTypes.txt b/compiler/fir/resolve/testData/resolve/problems/bareTypes.txt index c42d5f5f19d..25a360dacce 100644 --- a/compiler/fir/resolve/testData/resolve/problems/bareTypes.txt +++ b/compiler/fir/resolve/testData/resolve/problems/bareTypes.txt @@ -5,6 +5,21 @@ FILE: bareTypes.kt public abstract fun add(x: R|T|): R|kotlin/Unit| } - public final fun test(a: R|A|): R|kotlin/Unit| { - (R|/a| as R|MutableA|).#(String()) + public abstract interface MutableString : R|MutableA| { + } + public final fun test(a: R|A|): R|kotlin/Unit| { + (R|/a| as? R|MutableA|)?.R|FakeOverride|(String()) + (R|/a| as R|MutableA|).R|FakeOverride|(String()) + } + public final fun test2(a: R|A|): R|kotlin/Unit| { + lval b: R|MutableString| = (R|/a| as R|MutableString|) + R|/b|.R|FakeOverride|(String()) + } + public final fun test3(a: R|A|): R|kotlin/Unit| { + when () { + (R|/a| is R|MutableA|) -> { + R|/a|.R|FakeOverride|(String()) + } + } + } diff --git a/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt b/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt index c1a52077e51..d6975c2591c 100644 --- a/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt +++ b/compiler/fir/resolve/testData/resolve/recursiveCallOnWhenWithSealedClass.txt @@ -29,11 +29,11 @@ FILE: recursiveCallOnWhenWithSealedClass.kt public final fun unwrap(): R|T| { ^unwrap when (this@R|/Maybe|) { - ($subj$ is R|Maybe.Nope|) -> { + ($subj$ is R|Maybe.Nope|) -> { throw R|java/lang/Exception.Exception|(String()) } - ($subj$ is R|Maybe.Yeah|) -> { - this@R|/Maybe|.R|/Maybe.Yeah.meat| + ($subj$ is R|Maybe.Yeah|) -> { + this@R|/Maybe|.R|FakeOverride| } } diff --git a/compiler/testData/diagnostics/tests/cast/bare/AsNullable.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/AsNullable.fir.kt index 36520d5aab8..48f5318520a 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/AsNullable.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/AsNullable.fir.kt @@ -6,5 +6,5 @@ interface G : Tr fun test(tr: Tr) { val v = tr as G? // If v is not nullable, there will be a warning on this line: - checkSubtype>(v!!) + checkSubtype>(v!!) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherAs.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherAs.fir.kt index 7dd8ca15808..826e39357e0 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/EitherAs.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherAs.fir.kt @@ -9,7 +9,7 @@ class C2(val v2: Int) fun _as_left(e: Either): Any { val v = e as Left - return checkSubtype>(v) + return checkSubtype>(v) } fun _as_right(e: Either): Any { diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherIs.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherIs.fir.kt index 81c74588732..8c93645181b 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/EitherIs.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherIs.fir.kt @@ -12,7 +12,7 @@ class C2(val v2: Int) fun _is_l(e: Either): Any { if (e is Left) { - return e.value.v1 + return e.value.v1 } return e } diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.fir.kt index b84a60cd28d..3f83e6c0e18 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherNotIs.fir.kt @@ -14,7 +14,7 @@ fun _is_l(e: Either): Any { if (e !is Left) { return e } - return e.value.v1 + return e.value.v1 } fun _is_r(e: Either): Any { diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.fir.kt index a2873a79f36..8a1a2e70014 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherSafeAs.fir.kt @@ -9,7 +9,7 @@ class C2(val v2: Int) fun _as_left(e: Either): Any? { val v = e as? Left - return checkSubtype?>(v) + return checkSubtype?>(v) } fun _as_right(e: Either): Any? { diff --git a/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.fir.kt index 09855f1dbb6..cc6bbd8915a 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/EitherWhen.fir.kt @@ -12,7 +12,7 @@ class C2(val v2: Int) fun _when(e: Either): Any { return when (e) { - is Left -> e.value.v1 + is Left -> e.value.v1 is Right -> e.value.v2 else -> e } diff --git a/compiler/testData/diagnostics/tests/cast/bare/NullableAs.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/NullableAs.fir.kt index b11accdcd5f..85d624a9139 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/NullableAs.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/NullableAs.fir.kt @@ -5,5 +5,5 @@ interface G : Tr fun test(tr: Tr?) { val v = tr as G - checkSubtype>(v) + checkSubtype>(v) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/cast/bare/NullableAsNullable.fir.kt b/compiler/testData/diagnostics/tests/cast/bare/NullableAsNullable.fir.kt index 110de538ed4..3914084b7cb 100644 --- a/compiler/testData/diagnostics/tests/cast/bare/NullableAsNullable.fir.kt +++ b/compiler/testData/diagnostics/tests/cast/bare/NullableAsNullable.fir.kt @@ -6,5 +6,5 @@ interface G : Tr fun test(tr: Tr?) { val v = tr as G? // If v is not nullable, there will be a warning on this line: - checkSubtype>(v!!) + checkSubtype>(v!!) } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/nothingType/kt32388.fir.kt b/compiler/testData/diagnostics/tests/inference/nothingType/kt32388.fir.kt index 8a83e051a21..87f82df7b07 100644 --- a/compiler/testData/diagnostics/tests/inference/nothingType/kt32388.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/nothingType/kt32388.fir.kt @@ -1,7 +1,7 @@ // !WITH_NEW_INFERENCE fun Either.recover(f: (A) -> B): Either = when (this) { - is Either.Left -> f(this.a).right() + is Either.Left -> f(this.a).right() is Either.Right -> this } diff --git a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.fir.kt b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.fir.kt index 4aadd61475a..2bd33d184da 100644 --- a/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.fir.kt +++ b/compiler/testData/diagnostics/tests/multimodule/duplicateMethod/classGenericsInParamsBoundMismatch.fir.kt @@ -33,6 +33,6 @@ import p.* fun test(b: B?) { if (b is C) { - b?.foo(null) + b?.foo(null) } }