FIR: Avoid reporting redundant TYPE_MISMATCH (for assignments)
This commit is contained in:
committed by
teamcityserver
parent
36c9418d55
commit
db500fab94
+25
-2
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeExplicitTypeParameterConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||
@@ -164,19 +165,36 @@ private fun mapSystemHasContradictionError(
|
||||
source: FirSourceElement,
|
||||
qualifiedAccessSource: FirSourceElement?,
|
||||
): List<FirDiagnostic<FirSourceElement>> {
|
||||
val errorsToIgnore = mutableSetOf<ConstraintSystemError>()
|
||||
return buildList<FirDiagnostic<FirSourceElement>> {
|
||||
for (error in diagnostic.candidate.system.errors) {
|
||||
addIfNotNull(error.toDiagnostic(source, qualifiedAccessSource, diagnostic.candidate.callInfo.session.typeContext))
|
||||
addIfNotNull(
|
||||
error.toDiagnostic(
|
||||
source,
|
||||
qualifiedAccessSource,
|
||||
diagnostic.candidate.callInfo.session.typeContext,
|
||||
errorsToIgnore,
|
||||
)
|
||||
)
|
||||
}
|
||||
}.ifEmpty {
|
||||
listOfNotNull(
|
||||
diagnostic.candidate.system.errors.firstNotNullOfOrNull {
|
||||
if (it in errorsToIgnore) return@firstNotNullOfOrNull null
|
||||
val message = when (it) {
|
||||
is NewConstraintError -> "NewConstraintError at ${it.position}: ${it.lowerType} <!: ${it.upperType}"
|
||||
// Error should be reported on the error type itself
|
||||
is ConstrainingTypeIsError -> return@firstNotNullOfOrNull null
|
||||
else -> "Inference error: ${it::class.simpleName}"
|
||||
}
|
||||
|
||||
if (it is NewConstraintError && it.position.from is FixVariableConstraintPosition<*>) {
|
||||
val morePreciseDiagnosticExists = diagnostic.candidate.system.errors.any { other ->
|
||||
other is NewConstraintError && other.position.from !is FixVariableConstraintPosition<*>
|
||||
}
|
||||
if (morePreciseDiagnosticExists) return@firstNotNullOfOrNull null
|
||||
}
|
||||
|
||||
FirErrors.NEW_INFERENCE_ERROR.on(qualifiedAccessSource ?: source, message)
|
||||
}
|
||||
)
|
||||
@@ -187,6 +205,7 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
source: FirSourceElement,
|
||||
qualifiedAccessSource: FirSourceElement?,
|
||||
typeContext: ConeTypeContext,
|
||||
errorsToIgnore: MutableSet<ConstraintSystemError>,
|
||||
): FirDiagnostic<FirSourceElement>? {
|
||||
return when (this) {
|
||||
is NewConstraintError -> {
|
||||
@@ -204,7 +223,11 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
}
|
||||
|
||||
when (position) {
|
||||
is ExpectedTypeConstraintPosition<*> -> {
|
||||
is ConeExpectedTypeConstraintPosition -> {
|
||||
if (position.expectedTypeMismatchIsReportedInChecker) {
|
||||
errorsToIgnore.add(this)
|
||||
return null
|
||||
}
|
||||
val inferredType =
|
||||
if (!lowerConeType.isNullableNothing)
|
||||
lowerConeType
|
||||
|
||||
@@ -15,8 +15,13 @@ sealed class ResolutionMode {
|
||||
object ContextDependent : ResolutionMode()
|
||||
object ContextDependentDelegate : ResolutionMode()
|
||||
object ContextIndependent : ResolutionMode()
|
||||
|
||||
// TODO: it's better not to use WithExpectedType(FirImplicitTypeRef)
|
||||
class WithExpectedType(val expectedTypeRef: FirTypeRef, val mayBeCoercionToUnitApplied: Boolean = false) : ResolutionMode()
|
||||
class WithExpectedType(
|
||||
val expectedTypeRef: FirTypeRef,
|
||||
val mayBeCoercionToUnitApplied: Boolean = false,
|
||||
val expectedTypeMismatchIsReportedInChecker: Boolean = false,
|
||||
) : ResolutionMode()
|
||||
|
||||
class WithStatus(val status: FirDeclarationStatus) : ResolutionMode()
|
||||
|
||||
@@ -29,8 +34,13 @@ fun ResolutionMode.expectedType(components: BodyResolveComponents): FirTypeRef?
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun withExpectedType(expectedTypeRef: FirTypeRef?): ResolutionMode =
|
||||
expectedTypeRef?.let { ResolutionMode.WithExpectedType(it) } ?: ResolutionMode.ContextDependent
|
||||
fun withExpectedType(expectedTypeRef: FirTypeRef?, expectedTypeMismatchIsReportedInChecker: Boolean = false): ResolutionMode =
|
||||
expectedTypeRef?.let {
|
||||
ResolutionMode.WithExpectedType(
|
||||
it,
|
||||
expectedTypeMismatchIsReportedInChecker = expectedTypeMismatchIsReportedInChecker
|
||||
)
|
||||
} ?: ResolutionMode.ContextDependent
|
||||
|
||||
@JvmName("withExpectedTypeNullable")
|
||||
fun withExpectedType(coneType: ConeKotlinType?, mayBeCoercionToUnitApplied: Boolean = false): ResolutionMode {
|
||||
|
||||
+20
-8
@@ -31,8 +31,6 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.fir.visitors.transformSingle
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -56,13 +54,26 @@ class FirCallCompleter(
|
||||
|
||||
data class CompletionResult<T>(val result: T, val callCompleted: Boolean)
|
||||
|
||||
fun <T> completeCall(call: T, expectedTypeRef: FirTypeRef?): CompletionResult<T> where T : FirResolvable, T : FirStatement =
|
||||
completeCall(call, expectedTypeRef, mayBeCoercionToUnitApplied = false)
|
||||
fun <T> completeCall(
|
||||
call: T,
|
||||
expectedTypeRef: FirTypeRef?,
|
||||
expectedTypeMismatchIsReportedInChecker: Boolean = false,
|
||||
): CompletionResult<T> where T : FirResolvable, T : FirStatement =
|
||||
completeCall(call, expectedTypeRef, mayBeCoercionToUnitApplied = false, expectedTypeMismatchIsReportedInChecker)
|
||||
|
||||
fun <T> completeCall(call: T, data: ResolutionMode): CompletionResult<T> where T : FirResolvable, T : FirStatement =
|
||||
completeCall(call, data.expectedType(components), (data as? ResolutionMode.WithExpectedType)?.mayBeCoercionToUnitApplied == true)
|
||||
completeCall(
|
||||
call,
|
||||
data.expectedType(components),
|
||||
(data as? ResolutionMode.WithExpectedType)?.mayBeCoercionToUnitApplied == true,
|
||||
(data as? ResolutionMode.WithExpectedType)?.expectedTypeMismatchIsReportedInChecker == true,
|
||||
)
|
||||
|
||||
fun <T> completeCall(call: T, expectedTypeRef: FirTypeRef?, mayBeCoercionToUnitApplied: Boolean): CompletionResult<T>
|
||||
private fun <T> completeCall(
|
||||
call: T, expectedTypeRef: FirTypeRef?,
|
||||
mayBeCoercionToUnitApplied: Boolean,
|
||||
expectedTypeMismatchIsReportedInChecker: Boolean,
|
||||
): CompletionResult<T>
|
||||
where T : FirResolvable, T : FirStatement {
|
||||
val typeRef = components.typeFromCallee(call)
|
||||
|
||||
@@ -82,14 +93,15 @@ class FirCallCompleter(
|
||||
}
|
||||
|
||||
if (expectedTypeRef is FirResolvedTypeRef) {
|
||||
val expectedTypeConstraintPosition = ConeExpectedTypeConstraintPosition(expectedTypeMismatchIsReportedInChecker)
|
||||
if (expectedTypeRef.coneType.isUnitOrFlexibleUnit && mayBeCoercionToUnitApplied) {
|
||||
if (candidate.system.notFixedTypeVariables.isNotEmpty()) {
|
||||
candidate.system.addSubtypeConstraintIfCompatible(
|
||||
initialType, expectedTypeRef.type, ConeExpectedTypeConstraintPosition()
|
||||
initialType, expectedTypeRef.type, expectedTypeConstraintPosition
|
||||
)
|
||||
}
|
||||
} else {
|
||||
candidate.system.addSubtypeConstraint(initialType, expectedTypeRef.type, ConeExpectedTypeConstraintPosition())
|
||||
candidate.system.addSubtypeConstraint(initialType, expectedTypeRef.type, expectedTypeConstraintPosition)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -17,7 +17,9 @@ class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVaria
|
||||
|
||||
class ConeArgumentConstraintPosition(argument: FirElement) : ArgumentConstraintPosition<FirElement>(argument)
|
||||
|
||||
class ConeExpectedTypeConstraintPosition : ExpectedTypeConstraintPosition<Nothing?>(null)
|
||||
class ConeExpectedTypeConstraintPosition(
|
||||
val expectedTypeMismatchIsReportedInChecker: Boolean
|
||||
) : ExpectedTypeConstraintPosition<Nothing?>(null)
|
||||
|
||||
class ConeExplicitTypeParameterConstraintPosition(
|
||||
typeArgument: FirTypeProjection,
|
||||
|
||||
+9
-2
@@ -423,7 +423,11 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
}
|
||||
|
||||
fun chooseOperator(): FirStatement {
|
||||
callCompleter.completeCall(resolvedOperatorCall, lhsVariable?.returnTypeRef ?: noExpectedType)
|
||||
callCompleter.completeCall(
|
||||
resolvedOperatorCall,
|
||||
lhsVariable?.returnTypeRef ?: noExpectedType,
|
||||
expectedTypeMismatchIsReportedInChecker = true
|
||||
)
|
||||
dataFlowAnalyzer.exitFunctionCall(resolvedOperatorCall, callCompleted = true)
|
||||
val assignment =
|
||||
buildVariableAssignment {
|
||||
@@ -684,7 +688,10 @@ 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
|
||||
completeAssignment.transformRValue(transformer, withExpectedType(variableAssignment.lValueTypeRef))
|
||||
completeAssignment.transformRValue(
|
||||
transformer,
|
||||
withExpectedType(variableAssignment.lValueTypeRef, expectedTypeMismatchIsReportedInChecker = true),
|
||||
)
|
||||
} else {
|
||||
// This can happen in erroneous code only
|
||||
resolvedAssignment
|
||||
|
||||
Reference in New Issue
Block a user