[NI] Report unstable smart cast directly instead of using SmartCastManager
Fix compilation errors, revealed by this fix. SmartCastManager is unnecessary for error reporting, intermediate diagnostics from the NI contain all required infromation. When SmartCastManager is used it leads to missing unstable smart casts in case of expressions with captured types. This happens, because data flow info is recorded for original expression without captured types, which is used as a key. DataFlowValues created from receivers with captured types can't be used to retrieve that info. ^KT-39010 Fixed
This commit is contained in:
+10
@@ -21545,6 +21545,16 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt29767.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt29767.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt39010.kt")
|
||||||
|
public void testKt39010() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt39010_2.kt")
|
||||||
|
public void testKt39010_2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt4009.kt")
|
@TestMetadata("kt4009.kt")
|
||||||
public void testKt4009() throws Exception {
|
public void testKt4009() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt4009.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt4009.kt");
|
||||||
|
|||||||
@@ -415,19 +415,19 @@ private val nameToOperationConventionOrigin = mutableMapOf(
|
|||||||
internal fun FirReference.statementOrigin(): IrStatementOrigin? {
|
internal fun FirReference.statementOrigin(): IrStatementOrigin? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is FirPropertyFromParameterResolvedNamedReference -> IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
is FirPropertyFromParameterResolvedNamedReference -> IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||||
is FirResolvedNamedReference -> when (resolvedSymbol) {
|
is FirResolvedNamedReference -> when (val symbol = resolvedSymbol) {
|
||||||
is AccessorSymbol, is SyntheticPropertySymbol -> IrStatementOrigin.GET_PROPERTY
|
is AccessorSymbol, is SyntheticPropertySymbol -> IrStatementOrigin.GET_PROPERTY
|
||||||
is FirNamedFunctionSymbol -> when {
|
is FirNamedFunctionSymbol -> when {
|
||||||
resolvedSymbol.callableId.isInvoke() ->
|
symbol.callableId.isInvoke() ->
|
||||||
IrStatementOrigin.INVOKE
|
IrStatementOrigin.INVOKE
|
||||||
source?.elementType == KtNodeTypes.FOR && resolvedSymbol.callableId.isIteratorNext() ->
|
source?.elementType == KtNodeTypes.FOR && symbol.callableId.isIteratorNext() ->
|
||||||
IrStatementOrigin.FOR_LOOP_NEXT
|
IrStatementOrigin.FOR_LOOP_NEXT
|
||||||
source?.elementType == KtNodeTypes.FOR && resolvedSymbol.callableId.isIteratorHasNext() ->
|
source?.elementType == KtNodeTypes.FOR && symbol.callableId.isIteratorHasNext() ->
|
||||||
IrStatementOrigin.FOR_LOOP_HAS_NEXT
|
IrStatementOrigin.FOR_LOOP_HAS_NEXT
|
||||||
source?.elementType == KtNodeTypes.FOR && resolvedSymbol.callableId.isIterator() ->
|
source?.elementType == KtNodeTypes.FOR && symbol.callableId.isIterator() ->
|
||||||
IrStatementOrigin.FOR_LOOP_ITERATOR
|
IrStatementOrigin.FOR_LOOP_ITERATOR
|
||||||
source?.elementType == KtNodeTypes.OPERATION_REFERENCE ->
|
source?.elementType == KtNodeTypes.OPERATION_REFERENCE ->
|
||||||
nameToOperationConventionOrigin[resolvedSymbol.callableId.callableName]
|
nameToOperationConventionOrigin[symbol.callableId.callableName]
|
||||||
else ->
|
else ->
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -76,7 +76,7 @@ class IntegerLiteralTypeApproximationTransformer(
|
|||||||
// check black box tests
|
// check black box tests
|
||||||
// e.g. Byte doesn't have `and` in member scope. It's an extension
|
// e.g. Byte doesn't have `and` in member scope. It's an extension
|
||||||
if (resultSymbol == null) return functionCall.compose()
|
if (resultSymbol == null) return functionCall.compose()
|
||||||
functionCall.resultType = data?.let { functionCall.resultType.resolvedTypeFromPrototype(it) } ?: resultSymbol.fir.returnTypeRef
|
functionCall.resultType = data?.let { functionCall.resultType.resolvedTypeFromPrototype(it) } ?: resultSymbol!!.fir.returnTypeRef
|
||||||
// If the original call has argument mapping, values in that mapping refer to value parameters in that original symbol. We should
|
// If the original call has argument mapping, values in that mapping refer to value parameters in that original symbol. We should
|
||||||
// map those original value parameters back to indices, and then renew the argument mapping with new value parameters in the result
|
// map those original value parameters back to indices, and then renew the argument mapping with new value parameters in the result
|
||||||
// symbol. Otherwise, while putting the value argument to the converted IR call, it will encounter an unknown value parameter,
|
// symbol. Otherwise, while putting the value argument to the converted IR call, it will encounter an unknown value parameter,
|
||||||
@@ -84,7 +84,7 @@ class IntegerLiteralTypeApproximationTransformer(
|
|||||||
val newArgumentMapping =
|
val newArgumentMapping =
|
||||||
functionCall.argumentMapping?.mapValues { (_, oldValueParameter) ->
|
functionCall.argumentMapping?.mapValues { (_, oldValueParameter) ->
|
||||||
val index = operator.valueParameters.indexOf(oldValueParameter)
|
val index = operator.valueParameters.indexOf(oldValueParameter)
|
||||||
if (index != -1) resultSymbol.fir.valueParameters[index] else oldValueParameter
|
if (index != -1) resultSymbol!!.fir.valueParameters[index] else oldValueParameter
|
||||||
}
|
}
|
||||||
return functionCall.transformCalleeReference(
|
return functionCall.transformCalleeReference(
|
||||||
StoreCalleeReference,
|
StoreCalleeReference,
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ abstract class AbstractFirUseSiteMemberScope(
|
|||||||
createFunctionCopy(firSimpleFunction, newSymbol).apply {
|
createFunctionCopy(firSimpleFunction, newSymbol).apply {
|
||||||
resolvePhase = firSimpleFunction.resolvePhase
|
resolvePhase = firSimpleFunction.resolvePhase
|
||||||
typeParameters += firSimpleFunction.typeParameters
|
typeParameters += firSimpleFunction.typeParameters
|
||||||
valueParameters += firSimpleFunction.valueParameters.zip(foundFir.valueParameters)
|
valueParameters += firSimpleFunction.valueParameters.zip(foundFir!!.valueParameters)
|
||||||
.map { (overrideParameter, overriddenParameter) ->
|
.map { (overrideParameter, overriddenParameter) ->
|
||||||
if (overriddenParameter.defaultValue != null)
|
if (overriddenParameter.defaultValue != null)
|
||||||
createValueParameterCopy(overrideParameter, overriddenParameter.defaultValue).apply {
|
createValueParameterCopy(overrideParameter, overriddenParameter.defaultValue).apply {
|
||||||
|
|||||||
+3
-2
@@ -34,8 +34,9 @@ internal class FirWhenExpressionImpl(
|
|||||||
typeRef.accept(visitor, data)
|
typeRef.accept(visitor, data)
|
||||||
annotations.forEach { it.accept(visitor, data) }
|
annotations.forEach { it.accept(visitor, data) }
|
||||||
calleeReference.accept(visitor, data)
|
calleeReference.accept(visitor, data)
|
||||||
if (subjectVariable != null) {
|
val subjectVariable_ = subjectVariable
|
||||||
subjectVariable.accept(visitor, data)
|
if (subjectVariable_ != null) {
|
||||||
|
subjectVariable_.accept(visitor, data)
|
||||||
} else {
|
} else {
|
||||||
subject?.accept(visitor, data)
|
subject?.accept(visitor, data)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -150,8 +150,9 @@ fun SmartPrinter.printImplementation(implementation: Implementation) {
|
|||||||
if (type == "FirWhenExpressionImpl" && field.name == "subject") {
|
if (type == "FirWhenExpressionImpl" && field.name == "subject") {
|
||||||
println(
|
println(
|
||||||
"""
|
"""
|
||||||
|if (subjectVariable != null) {
|
|val subjectVariable_ = subjectVariable
|
||||||
| subjectVariable.accept(visitor, data)
|
| if (subjectVariable_ != null) {
|
||||||
|
| subjectVariable_.accept(visitor, data)
|
||||||
| } else {
|
| } else {
|
||||||
| subject?.accept(visitor, data)
|
| subject?.accept(visitor, data)
|
||||||
| }
|
| }
|
||||||
|
|||||||
+14
-2
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
|
|||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||||
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
|
import org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
|
import org.jetbrains.kotlin.types.typeUtil.isNullableNothing
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNullable
|
||||||
@@ -283,8 +284,19 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun reportUnstableSmartCast(unstableSmartCast: UnstableSmartCast) {
|
private fun reportUnstableSmartCast(unstableSmartCast: UnstableSmartCast) {
|
||||||
// todo hack -- remove it after removing SmartCastManager
|
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(unstableSmartCast.argument.receiver.receiverValue, context)
|
||||||
reportSmartCast(SmartCastDiagnostic(unstableSmartCast.argument, unstableSmartCast.targetType, null))
|
val possibleTypes = unstableSmartCast.argument.receiver.typesFromSmartCasts
|
||||||
|
val argumentExpression = unstableSmartCast.argument.psiExpression ?: return
|
||||||
|
|
||||||
|
require(possibleTypes.isNotEmpty()) { "Receiver for unstable smart cast without possible types" }
|
||||||
|
trace.report(
|
||||||
|
SMARTCAST_IMPOSSIBLE.on(
|
||||||
|
argumentExpression,
|
||||||
|
intersectWrappedTypes(possibleTypes),
|
||||||
|
argumentExpression.text,
|
||||||
|
dataFlowValue.kind.description
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun constraintError(diagnostic: KotlinCallDiagnostic) {
|
override fun constraintError(diagnostic: KotlinCallDiagnostic) {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class A<E> {
|
||||||
|
fun foo(): E = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
class B(var a: A<*>?) {
|
||||||
|
fun bar() {
|
||||||
|
if (a != null) {
|
||||||
|
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
class A<E> {
|
||||||
|
fun foo(): E = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
class B(var a: A<*>?) {
|
||||||
|
fun bar() {
|
||||||
|
if (a != null) {
|
||||||
|
<!SMARTCAST_IMPOSSIBLE!>a<!>.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public final class A</*0*/ E> {
|
||||||
|
public constructor A</*0*/ E>()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): E
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class B {
|
||||||
|
public constructor B(/*0*/ a: A<*>?)
|
||||||
|
public final var a: A<*>?
|
||||||
|
public final fun bar(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
open class A<E> {
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A<String>() {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KI {
|
||||||
|
val a: A<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KI.bar() {
|
||||||
|
if (a is B) {
|
||||||
|
a.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
open class A<E> {
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A<String>() {
|
||||||
|
fun foo() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KI {
|
||||||
|
val a: A<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KI.bar() {
|
||||||
|
if (a is B) {
|
||||||
|
<!SMARTCAST_IMPOSSIBLE!>a<!>.foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun KI.bar(): kotlin.Unit
|
||||||
|
|
||||||
|
public open class A</*0*/ E> {
|
||||||
|
public constructor A</*0*/ E>()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class B : A<kotlin.String> {
|
||||||
|
public constructor B()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface KI {
|
||||||
|
public abstract val a: A<*>
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -21622,6 +21622,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt29767.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt29767.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt39010.kt")
|
||||||
|
public void testKt39010() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt39010_2.kt")
|
||||||
|
public void testKt39010_2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt4009.kt")
|
@TestMetadata("kt4009.kt")
|
||||||
public void testKt4009() throws Exception {
|
public void testKt4009() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt4009.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt4009.kt");
|
||||||
|
|||||||
Generated
+10
@@ -21547,6 +21547,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt29767.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt29767.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt39010.kt")
|
||||||
|
public void testKt39010() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt39010.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt39010_2.kt")
|
||||||
|
public void testKt39010_2() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt39010_2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt4009.kt")
|
@TestMetadata("kt4009.kt")
|
||||||
public void testKt4009() throws Exception {
|
public void testKt4009() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt4009.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/inference/kt4009.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user