[FIR] Add lValueTypeRef to FirVariableAssignment, fix tests with ASSIGNMENT_TYPE_MISMATCH
This commit is contained in:
committed by
TeamCityServer
parent
e57108d4e8
commit
c3b8f3e859
@@ -2,7 +2,7 @@ class SomeClass {
|
||||
|
||||
var foo: Int = 0
|
||||
set(value: <!WRONG_SETTER_PARAMETER_TYPE!>String<!>){
|
||||
field = value
|
||||
field = <!ASSIGNMENT_TYPE_MISMATCH!>value<!>
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,5 +18,5 @@ FILE: hashSet.kt
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
lvar c: R|kotlin/collections/MutableSet<kotlin/String>?| = Null(null)
|
||||
R|<local>/c| = R|java/util/HashSet.HashSet|<R|ft<kotlin/String, kotlin/String?>|>()
|
||||
R|<local>/c|!!.R|/d| = R|/produce|<R|T?|>()
|
||||
R|<local>/c|!!.R|/d| = R|/produce|<R|kotlin/String?|>()
|
||||
}
|
||||
|
||||
+21
-11
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
||||
@@ -521,16 +522,34 @@ private val FirSimpleFunction.matchesToStringSignature: Boolean
|
||||
get() = valueParameters.isEmpty()
|
||||
|
||||
fun checkTypeMismatch(
|
||||
lValueType: ConeKotlinType,
|
||||
lValueOriginalType: ConeKotlinType,
|
||||
rValue: FirExpression,
|
||||
context: CheckerContext,
|
||||
source: FirSourceElement,
|
||||
reporter: DiagnosticReporter,
|
||||
isInitializer: Boolean
|
||||
) {
|
||||
val rValueType = rValue.typeRef.coneType
|
||||
var lValueType = lValueOriginalType
|
||||
var rValueType = rValue.typeRef.coneType
|
||||
val typeContext = context.session.typeContext
|
||||
|
||||
val diagnosticFactory = when {
|
||||
isInitializer -> {
|
||||
FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
}
|
||||
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement -> {
|
||||
if (!lValueType.isNullable && rValueType.isNullable) {
|
||||
val tempType = rValueType
|
||||
rValueType = lValueType
|
||||
lValueType = tempType
|
||||
}
|
||||
FirErrors.RESULT_TYPE_MISMATCH
|
||||
}
|
||||
else -> {
|
||||
FirErrors.ASSIGNMENT_TYPE_MISMATCH
|
||||
}
|
||||
}
|
||||
|
||||
if (!isSubtypeForTypeMismatch(typeContext, subtype = rValueType, supertype = lValueType)) {
|
||||
if (rValueType is ConeClassLikeType &&
|
||||
rValueType.lookupTag.classId == StandardClassIds.Int &&
|
||||
@@ -548,15 +567,6 @@ fun checkTypeMismatch(
|
||||
if (rValue.isNullLiteral && lValueType.nullability == ConeNullability.NOT_NULL) {
|
||||
reporter.reportOn(rValue.source, FirErrors.NULL_FOR_NONNULL_TYPE, context)
|
||||
} else {
|
||||
val diagnosticFactory = when {
|
||||
isInitializer ->
|
||||
FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
source.kind is FirFakeSourceElementKind.DesugaredIncrementOrDecrement ->
|
||||
FirErrors.RESULT_TYPE_MISMATCH
|
||||
else ->
|
||||
FirErrors.ASSIGNMENT_TYPE_MISMATCH
|
||||
}
|
||||
|
||||
reporter.report(diagnosticFactory.on(source, lValueType, rValueType), context)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,9 +9,9 @@ import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isComponentCall
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirInitializerTypeMismatchChecker : FirPropertyChecker() {
|
||||
|
||||
+3
-8
@@ -9,17 +9,12 @@ import org.jetbrains.kotlin.fir.analysis.checkers.checkTypeMismatch
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirAssignmentTypeMismatchChecker : FirVariableAssignmentChecker() {
|
||||
override fun check(expression: FirVariableAssignment, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = expression.rValue.source ?: return
|
||||
val lValueType =
|
||||
((expression.lValue as? FirResolvedNamedReference)?.resolvedSymbol as? FirPropertySymbol)?.fir?.returnTypeRef?.coneType
|
||||
?: return
|
||||
|
||||
checkTypeMismatch(lValueType, expression.rValue, context, source, reporter, false)
|
||||
val coneType = expression.lValueTypeRef.coneType
|
||||
checkTypeMismatch(coneType, expression.rValue, context, source, reporter, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -43,6 +43,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_PASSED_T
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNED_VALUE_IS_NEVER_READ
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER
|
||||
@@ -248,6 +249,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REIFIED_TYPE_PARA
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_BOUND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REPEATED_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESERVED_MEMBER_INSIDE_INLINE_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RESULT_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RETURN_TYPE_MISMATCH
|
||||
@@ -522,7 +524,14 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING)
|
||||
map.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list")
|
||||
|
||||
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", TO_STRING, TO_STRING)
|
||||
map.put(ARGUMENT_TYPE_MISMATCH, "Argument type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
|
||||
map.put(ASSIGNMENT_TYPE_MISMATCH, "Assignment type mismatch: actual type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE)
|
||||
map.put(
|
||||
RESULT_TYPE_MISMATCH,
|
||||
"Function return type mismatch: actual type is {1} but {0} was expected",
|
||||
RENDER_TYPE,
|
||||
RENDER_TYPE
|
||||
)
|
||||
|
||||
// Ambiguity
|
||||
map.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity between candidates: {0}", SYMBOLS)
|
||||
@@ -834,7 +843,10 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
)
|
||||
map.put(INITIALIZER_TYPE_MISMATCH, "Initializer type mismatch: expected {0}, actual {1}", RENDER_TYPE, RENDER_TYPE)
|
||||
map.put(GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, "Getter visibility must be the same as property visibility")
|
||||
map.put(SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY, "Setter visibility must be the same or less permissive than property visibility")
|
||||
map.put(
|
||||
SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY,
|
||||
"Setter visibility must be the same or less permissive than property visibility"
|
||||
)
|
||||
map.put(WRONG_SETTER_RETURN_TYPE, "Setter return type must be Unit")
|
||||
map.put(
|
||||
WRONG_GETTER_RETURN_TYPE,
|
||||
|
||||
-1
@@ -469,7 +469,6 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
|
||||
|
||||
if (unwrappedArgument == null) {
|
||||
return buildErrorExpression {
|
||||
source = unwrappedArgument
|
||||
diagnostic = ConeSimpleDiagnostic("Inc/dec without operand", DiagnosticKind.Syntax)
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvable
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.resolve.ResolutionMode
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||
@@ -56,7 +57,12 @@ class FirCallCompleter(
|
||||
where T : FirResolvable, T : FirStatement {
|
||||
val typeRef = components.typeFromCallee(call)
|
||||
|
||||
if (call is FirVariableAssignment) {
|
||||
call.replaceLValueTypeRef(typeRef)
|
||||
}
|
||||
|
||||
val reference = call.calleeReference as? FirNamedReferenceWithCandidate ?: return CompletionResult(call, true)
|
||||
|
||||
val candidate = reference.candidate
|
||||
val initialType = components.initialTypeOfCandidate(candidate, call)
|
||||
|
||||
|
||||
+18
-6
@@ -66,7 +66,7 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T : FirQualifiedAccessExpression> prepareQualifiedTransform(
|
||||
private fun <T : FirQualifiedAccess> prepareQualifiedTransform(
|
||||
qualifiedAccessExpression: T, calleeReference: FirNamedReferenceWithCandidate
|
||||
): T {
|
||||
val subCandidate = calleeReference.candidate
|
||||
@@ -111,7 +111,13 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
)
|
||||
.transformDispatchReceiver(StoreReceiver, subCandidate.dispatchReceiverExpression())
|
||||
.transformExtensionReceiver(StoreReceiver, subCandidate.extensionReceiverExpression()) as T
|
||||
result.replaceTypeRef(typeRef)
|
||||
|
||||
if (result is FirQualifiedAccessExpression) {
|
||||
result.replaceTypeRef(typeRef)
|
||||
} else if (result is FirVariableAssignment) {
|
||||
result.replaceLValueTypeRef(typeRef)
|
||||
}
|
||||
|
||||
if (declaration !is FirErrorFunction) {
|
||||
result.replaceTypeArguments(typeArguments)
|
||||
}
|
||||
@@ -354,13 +360,19 @@ class FirCallCompletionResultsWriterTransformer(
|
||||
): FirStatement {
|
||||
val calleeReference = variableAssignment.calleeReference as? FirNamedReferenceWithCandidate
|
||||
?: return variableAssignment
|
||||
val typeArguments = computeTypeArguments(variableAssignment, calleeReference.candidate)
|
||||
|
||||
// Initialize lValueTypeRef
|
||||
val qualifiedTransform = prepareQualifiedTransform(variableAssignment, calleeReference)
|
||||
val lValueTypeRef = qualifiedTransform.lValueTypeRef as FirResolvedTypeRef
|
||||
val resultLValueType = lValueTypeRef.substituteTypeRef(calleeReference.candidate)
|
||||
resultLValueType.ensureResolvedTypeDeclaration(session)
|
||||
variableAssignment.replaceLValueTypeRef(resultLValueType)
|
||||
session.lookupTracker?.recordTypeResolveAsLookup(resultLValueType, variableAssignment.lValue.source, null)
|
||||
|
||||
return variableAssignment.transformCalleeReference(
|
||||
StoreCalleeReference,
|
||||
calleeReference.toResolvedReference(),
|
||||
).apply {
|
||||
replaceTypeArguments(typeArguments)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private inner class TypeUpdaterForDelegateArguments : FirTransformer<Any?>() {
|
||||
|
||||
+1
-2
@@ -677,8 +677,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
val resolvedAssignment = callResolver.resolveVariableAccessAndSelectCandidate(variableAssignment)
|
||||
val result = if (resolvedAssignment is FirVariableAssignment) {
|
||||
val completeAssignment = callCompleter.completeCall(resolvedAssignment, noExpectedType).result // TODO: check
|
||||
val expectedType = components.typeFromCallee(completeAssignment)
|
||||
completeAssignment.transformRValue(transformer, withExpectedType(expectedType))
|
||||
completeAssignment.transformRValue(transformer, withExpectedType(variableAssignment.lValueTypeRef))
|
||||
} else {
|
||||
// This can happen in erroneous code only
|
||||
resolvedAssignment
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirPureAbstractElement
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
import org.jetbrains.kotlin.fir.FirImplementationDetail
|
||||
|
||||
@@ -27,6 +28,7 @@ abstract class FirVariableAssignment : FirPureAbstractElement(), FirQualifiedAcc
|
||||
abstract override val extensionReceiver: FirExpression
|
||||
abstract override val source: FirSourceElement?
|
||||
abstract val lValue: FirReference
|
||||
abstract val lValueTypeRef: FirTypeRef
|
||||
abstract val rValue: FirExpression
|
||||
|
||||
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitVariableAssignment(this, data)
|
||||
@@ -44,6 +46,8 @@ abstract class FirVariableAssignment : FirPureAbstractElement(), FirQualifiedAcc
|
||||
@FirImplementationDetail
|
||||
abstract override fun replaceSource(newSource: FirSourceElement?)
|
||||
|
||||
abstract fun replaceLValueTypeRef(newLValueTypeRef: FirTypeRef)
|
||||
|
||||
abstract override fun <D> transformCalleeReference(transformer: FirTransformer<D>, data: D): FirVariableAssignment
|
||||
|
||||
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirVariableAssignment
|
||||
|
||||
+2
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirVariableAssignmentImpl
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
|
||||
/*
|
||||
|
||||
+9
@@ -11,6 +11,8 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.references.FirReference
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.*
|
||||
import org.jetbrains.kotlin.fir.FirImplementationDetail
|
||||
|
||||
@@ -34,6 +36,7 @@ internal class FirVariableAssignmentImpl(
|
||||
set(value) {
|
||||
calleeReference = value
|
||||
}
|
||||
override var lValueTypeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
|
||||
|
||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
|
||||
calleeReference.accept(visitor, data)
|
||||
@@ -46,6 +49,7 @@ internal class FirVariableAssignmentImpl(
|
||||
if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) {
|
||||
extensionReceiver.accept(visitor, data)
|
||||
}
|
||||
lValueTypeRef.accept(visitor, data)
|
||||
rValue.accept(visitor, data)
|
||||
}
|
||||
|
||||
@@ -60,6 +64,7 @@ internal class FirVariableAssignmentImpl(
|
||||
if (extensionReceiver !== explicitReceiver && extensionReceiver !== dispatchReceiver) {
|
||||
extensionReceiver = extensionReceiver.transform(transformer, data)
|
||||
}
|
||||
lValueTypeRef = lValueTypeRef.transform(transformer, data)
|
||||
transformRValue(transformer, data)
|
||||
return this
|
||||
}
|
||||
@@ -116,4 +121,8 @@ internal class FirVariableAssignmentImpl(
|
||||
override fun replaceSource(newSource: FirSourceElement?) {
|
||||
source = newSource
|
||||
}
|
||||
|
||||
override fun replaceLValueTypeRef(newLValueTypeRef: FirTypeRef) {
|
||||
lValueTypeRef = newLValueTypeRef
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -495,5 +495,14 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
default(it, "FirImplicitTypeRefImpl(null)")
|
||||
useTypes(implicitTypeRefType)
|
||||
}
|
||||
|
||||
configureFieldInAllImplementations(
|
||||
field = "lValueTypeRef",
|
||||
implementationPredicate = { it.type in "FirVariableAssignmentImpl" },
|
||||
fieldPredicate = { it.defaultValueInImplementation == null }
|
||||
) {
|
||||
default(it, "FirImplicitTypeRefImpl(null)")
|
||||
useTypes(implicitTypeRefType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -521,6 +521,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
|
||||
|
||||
variableAssignment.configure {
|
||||
+field("lValue", reference)
|
||||
+field("lValueTypeRef", typeRef).withReplace()
|
||||
+field("rValue", expression).withTransform()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user